Summary Files Commits Branches @commit @diff @stats
path: root / src
diff options
context:
space:
mode:
Commite00257f5d98020c53202a30d766d3414780a0409 (patch)
Author
 Kamen Mladenov <kamen@syndamia.com>
2025-08-19 16:16:15 +0300
Committer
 Kamen Mladenov <kamen@syndamia.com>
2025-08-19 16:16:15 +0300
Files2f92becf43dd0d36076fbdd608ec900991aa7235 /src
syndamia.com-e00257f5d98020c53202a30d766d3414780a0409.tar
syndamia.com-e00257f5d98020c53202a30d766d3414780a0409.tar.gz
syndamia.com-e00257f5d98020c53202a30d766d3414780a0409.zip
Parent26399584792adef3896c92025353ec482cfa2d3d (diff)
Parent59d2bcb225eeaf41830c339bff1562a249c9cddd (diff)
Merge branch 'dunbar-rewrite' into 'master'
feat!: Convert from Markdown to dunbar See merge request Syndamia/syndamiadotcom!16
185 files changed, 8974 insertions, 8577 deletions
-rw-r--r--src/404.du (renamed from src/404.md)0
-rw-r--r--src/_footer.html14
-rw-r--r--src/_header.html125
-rw-r--r--src/about.du123
-rw-r--r--src/about.md68
-rw-r--r--src/about/index.du123
-rw-r--r--src/about/index.md68
-rw-r--r--src/accessibility.du (renamed from src/accessibility.md)18
-rw-r--r--src/acknowledgements.du36
-rw-r--r--src/acknowledgements.md33
-rw-r--r--src/blog.du63
-rw-r--r--src/blog.md56
-rw-r--r--src/blog/2.6-years-of-web-design/index.du (renamed from src/blog/2.6-years-of-web-design/index.md)122
-rw-r--r--src/blog/bash-is-weird/index.du65
-rw-r--r--src/blog/bash-is-weird/index.md55
-rw-r--r--src/blog/encrypted-email/index.du174
-rw-r--r--src/blog/encrypted-email/index.md149
-rw-r--r--src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du65
-rw-r--r--src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.md60
-rw-r--r--src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du (renamed from src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.md)239
-rw-r--r--src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du (renamed from src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.md)108
-rw-r--r--src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.du129
-rw-r--r--src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.md112
-rw-r--r--src/blog/index.du63
-rw-r--r--src/blog/index.md56
-rw-r--r--src/blog/microsoft-and-foss-extinguish/index.du (renamed from src/blog/microsoft-and-foss-extinguish/index.md)49
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/basic-concepts.du (renamed from src/blog/mundus-first-shot-at-gamedev/basic-concepts.md)42
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/index.du55
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/index.md44
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/introduction.du55
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/introduction.md44
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/timeline.du (renamed from src/blog/mundus-first-shot-at-gamedev/timeline.md)35
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/user-interface.du92
-rw-r--r--src/blog/mundus-first-shot-at-gamedev/user-interface.md85
-rw-r--r--src/blog/plan9-in-linux-mouse-menus/index.du (renamed from src/blog/plan9-in-linux-mouse-menus/index.md)172
-rw-r--r--src/blog/sane-explanation-of-compilers/index.du (renamed from src/blog/sane-explanation-of-compilers/index.md)3
-rw-r--r--src/blog/sane-explanation-of-compilers/part-1.du (renamed from src/blog/sane-explanation-of-compilers/part-1.md)794
-rw-r--r--src/blog/switchut-izgorq/index.du (renamed from src/blog/switchut-izgorq/index.md)17
-rw-r--r--src/blog/taming-the-fun-too/index.du (renamed from src/blog/taming-the-fun-too/index.md)66
-rw-r--r--src/blog/the-physics-behind-a-black-hole-shader/index.du (renamed from src/blog/the-physics-behind-a-black-hole-shader/index.md)274
-rw-r--r--src/blog/thinkpad-x270-my-favorite-machine/index.du (renamed from src/blog/thinkpad-x270-my-favorite-machine/index.md)96
-rw-r--r--src/blog/when-a-language-forces-simpler-thinking/index.du (renamed from src/blog/when-a-language-forces-simpler-thinking/index.md)37
-rw-r--r--src/index.du (renamed from src/index.md)34
-rw-r--r--src/license.du12
-rw-r--r--src/license.md12
-rw-r--r--src/misc.du (renamed from src/misc.md)7
-rw-r--r--src/misc/index.du (renamed from src/misc/index.md)7
-rw-r--r--src/misc/universitetski-belejki/index.du41
-rw-r--r--src/misc/universitetski-belejki/index.md37
-rw-r--r--src/preserved-media.du14
-rw-r--r--src/preserved-media.md13
-rw-r--r--src/preserved-media/index.du14
-rw-r--r--src/preserved-media/index.md13
-rw-r--r--src/preserved-web-pages.du11
-rw-r--r--src/preserved-web-pages.md10
-rw-r--r--src/preserved-web-pages/index.du11
-rw-r--r--src/preserved-web-pages/index.md10
-rw-r--r--src/privacy.du32
-rw-r--r--src/privacy.md33
-rw-r--r--src/regarding-js.du34
-rw-r--r--src/regarding-js.md34
-rw-r--r--src/rework.du5
-rw-r--r--src/rework.md6
-rw-r--r--src/setup.du62
-rw-r--r--src/setup.md62
-rw-r--r--src/setup/index.du62
-rw-r--r--src/setup/index.md62
-rw-r--r--src/slides.du17
-rw-r--r--src/slides.md15
-rw-r--r--src/slides/demo/index.du216
-rw-r--r--src/slides/demo/index.md265
-rw-r--r--src/slides/index.du17
-rw-r--r--src/slides/index.md15
-rw-r--r--src/slides/linuxgraphy-by-strabo/index.du1420
-rw-r--r--src/slides/linuxgraphy-by-strabo/index.md1382
-rw-r--r--src/styles.css13
-rw-r--r--src/teaching.du12
-rw-r--r--src/teaching.md11
-rw-r--r--src/teaching/index.du12
-rw-r--r--src/teaching/index.md11
-rw-r--r--src/teaching/oop-2023/index.du64
-rw-r--r--src/teaching/oop-2023/index.md32
-rw-r--r--src/teaching/oop-2023/week1/good-software.du (renamed from src/teaching/oop-2023/week1/good-software.md)230
-rw-r--r--src/teaching/oop-2023/week1/index.du (renamed from src/teaching/oop-2023/week1/index.md)117
-rw-r--r--src/teaching/oop-2023/week1/organization.du (renamed from src/teaching/oop-2023/week1/organization.md)45
-rw-r--r--src/teaching/oop-2023/week10/index.du150
-rw-r--r--src/teaching/oop-2023/week10/index.md146
-rw-r--r--src/teaching/oop-2023/week11/index.du210
-rw-r--r--src/teaching/oop-2023/week11/index.md201
-rw-r--r--src/teaching/oop-2023/week12/index.du97
-rw-r--r--src/teaching/oop-2023/week12/index.md94
-rw-r--r--src/teaching/oop-2023/week13/index.du141
-rw-r--r--src/teaching/oop-2023/week13/index.md138
-rw-r--r--src/teaching/oop-2023/week14/index.du (renamed from src/teaching/oop-2023/week14/index.md)24
-rw-r--r--src/teaching/oop-2023/week15/index.du (renamed from src/teaching/oop-2023/week15/index.md)8
-rw-r--r--src/teaching/oop-2023/week16/index.du (renamed from src/teaching/oop-2023/week16/index.md)7
-rw-r--r--src/teaching/oop-2023/week2/index.du (renamed from src/teaching/oop-2023/week2/index.md)118
-rw-r--r--src/teaching/oop-2023/week3/index.du (renamed from src/teaching/oop-2023/week3/index.md)80
-rw-r--r--src/teaching/oop-2023/week4/index.du115
-rw-r--r--src/teaching/oop-2023/week4/index.md110
-rw-r--r--src/teaching/oop-2023/week5/index.du (renamed from src/teaching/oop-2023/week5/index.md)44
-rw-r--r--src/teaching/oop-2023/week6/index.du104
-rw-r--r--src/teaching/oop-2023/week6/index.md102
-rw-r--r--src/teaching/oop-2023/week7/index.du (renamed from src/teaching/oop-2023/week7/index.md)36
-rw-r--r--src/teaching/oop-2023/week8/index.du (renamed from src/teaching/oop-2023/week8/index.md)67
-rw-r--r--src/teaching/oop-2023/week9/index.du (renamed from src/teaching/oop-2023/week9/index.md)74
-rw-r--r--src/teaching/upp-2023/additional1/index.du (renamed from src/teaching/upp-2023/additional1/index.md)229
-rw-r--r--src/teaching/upp-2023/additional2/index.du (renamed from src/teaching/upp-2023/additional2/index.md)161
-rw-r--r--src/teaching/upp-2023/index.du37
-rw-r--r--src/teaching/upp-2023/index.md35
-rw-r--r--src/teaching/upp-2023/week1/index.du (renamed from src/teaching/upp-2023/week1/index.md)33
-rw-r--r--src/teaching/upp-2023/week1/setup.du (renamed from src/teaching/upp-2023/week1/setup.md)345
-rw-r--r--src/teaching/upp-2023/week1/welcome.du (renamed from src/teaching/upp-2023/week1/welcome.md)303
-rw-r--r--src/teaching/upp-2023/week10/index.du91
-rw-r--r--src/teaching/upp-2023/week10/index.md90
-rw-r--r--src/teaching/upp-2023/week11/index.du129
-rw-r--r--src/teaching/upp-2023/week11/index.md127
-rw-r--r--src/teaching/upp-2023/week12/index.du (renamed from src/teaching/upp-2023/week12/index.md)93
-rw-r--r--src/teaching/upp-2023/week13/index.du (renamed from src/teaching/upp-2023/week13/index.md)72
-rw-r--r--src/teaching/upp-2023/week14/index.du (renamed from src/teaching/upp-2023/week14/index.md)33
-rw-r--r--src/teaching/upp-2023/week2/index.du (renamed from src/teaching/upp-2023/week2/index.md)183
-rw-r--r--src/teaching/upp-2023/week2/revision.du (renamed from src/teaching/upp-2023/week2/revision.md)207
-rw-r--r--src/teaching/upp-2023/week3/index.du (renamed from src/teaching/upp-2023/week3/index.md)255
-rw-r--r--src/teaching/upp-2023/week3/revision.du (renamed from src/teaching/upp-2023/week3/revision.md)196
-rw-r--r--src/teaching/upp-2023/week4/index.du (renamed from src/teaching/upp-2023/week4/index.md)96
-rw-r--r--src/teaching/upp-2023/week4/revision.du (renamed from src/teaching/upp-2023/week4/revision.md)106
-rw-r--r--src/teaching/upp-2023/week5/index.du (renamed from src/teaching/upp-2023/week5/index.md)99
-rw-r--r--src/teaching/upp-2023/week5/revision.du (renamed from src/teaching/upp-2023/week5/revision.md)24
-rw-r--r--src/teaching/upp-2023/week6/index.du (renamed from src/teaching/upp-2023/week6/index.md)139
-rw-r--r--src/teaching/upp-2023/week7/index.du (renamed from src/teaching/upp-2023/week7/index.md)146
-rw-r--r--src/teaching/upp-2023/week8/index.du (renamed from src/teaching/upp-2023/week8/index.md)100
-rw-r--r--src/teaching/upp-2023/week9/index.du (renamed from src/teaching/upp-2023/week9/index.md)101
-rw-r--r--src/tutorials.du68
-rw-r--r--src/tutorials.md63
-rw-r--r--src/tutorials/connect-to-mysql-in-dotnet-ef/index.du78
-rw-r--r--src/tutorials/connect-to-mysql-in-dotnet-ef/index.md75
-rw-r--r--src/tutorials/disable-sticky-keys-popup/index.du31
-rw-r--r--src/tutorials/disable-sticky-keys-popup/index.md21
-rw-r--r--src/tutorials/export-skype/index.du88
-rw-r--r--src/tutorials/export-skype/index.md58
-rw-r--r--src/tutorials/fix-network-brother-printers/index.du (renamed from src/tutorials/fix-network-brother-printers/index.md)48
-rw-r--r--src/tutorials/fix-no-frame-buffer-plan9/index.du90
-rw-r--r--src/tutorials/fix-no-frame-buffer-plan9/index.md87
-rw-r--r--src/tutorials/fix-qc-timeout/index.du (renamed from src/tutorials/fix-qc-timeout/index.md)24
-rw-r--r--src/tutorials/gns3-initsh-no-such-file/index.du27
-rw-r--r--src/tutorials/gns3-initsh-no-such-file/index.md24
-rw-r--r--src/tutorials/how-to-encrypt-email/index.du263
-rw-r--r--src/tutorials/how-to-encrypt-email/index.md109
-rw-r--r--src/tutorials/how-to-use-jira/bug.du21
-rw-r--r--src/tutorials/how-to-use-jira/bug.md16
-rw-r--r--src/tutorials/how-to-use-jira/cards.du161
-rw-r--r--src/tutorials/how-to-use-jira/cards.md151
-rw-r--r--src/tutorials/how-to-use-jira/components.du50
-rw-r--r--src/tutorials/how-to-use-jira/components.md45
-rw-r--r--src/tutorials/how-to-use-jira/dashboards.du65
-rw-r--r--src/tutorials/how-to-use-jira/dashboards.md61
-rw-r--r--src/tutorials/how-to-use-jira/filters.du44
-rw-r--r--src/tutorials/how-to-use-jira/filters.md40
-rw-r--r--src/tutorials/how-to-use-jira/index.du75
-rw-r--r--src/tutorials/how-to-use-jira/index.md50
-rw-r--r--src/tutorials/how-to-use-jira/introduction.md49
-rw-r--r--src/tutorials/how-to-use-jira/kanban.du38
-rw-r--r--src/tutorials/how-to-use-jira/kanban.md33
-rw-r--r--src/tutorials/how-to-use-jira/pages.du22
-rw-r--r--src/tutorials/how-to-use-jira/pages.md16
-rw-r--r--src/tutorials/how-to-use-jira/projects.du158
-rw-r--r--src/tutorials/how-to-use-jira/projects.md147
-rw-r--r--src/tutorials/how-to-use-jira/releases.du21
-rw-r--r--src/tutorials/how-to-use-jira/releases.md16
-rw-r--r--src/tutorials/how-to-use-jira/scrum.du55
-rw-r--r--src/tutorials/how-to-use-jira/scrum.md50
-rw-r--r--src/tutorials/index.du68
-rw-r--r--src/tutorials/index.md63
-rw-r--r--src/tutorials/install-drivers-for-epson-scanners/index.du62
-rw-r--r--src/tutorials/install-drivers-for-epson-scanners/index.md54
-rw-r--r--src/tutorials/install-plan9-with-virt-manager/index.du91
-rw-r--r--src/tutorials/install-plan9-with-virt-manager/index.md74
-rw-r--r--src/tutorials/managing-apps-with-adb-without-root/index.du (renamed from src/tutorials/managing-apps-with-adb-without-root/index.md)157
-rw-r--r--src/tutorials/remove-weather-widget/index.du19
-rw-r--r--src/tutorials/remove-weather-widget/index.md12
-rw-r--r--src/tutorials/turn-off-notifications-windows/index.du27
-rw-r--r--src/tutorials/turn-off-notifications-windows/index.md18
-rw-r--r--src/tutorials/virt-manager-freeze-on-browse/index.du (renamed from src/tutorials/virt-manager-freeze-on-browse/index.md)17
-rw-r--r--src/tutorials/windows-run-dialog/index.du125
-rw-r--r--src/tutorials/windows-run-dialog/index.md114
diff --git a/src/404.md b/src/404.du
index b23ffa7..b23ffa7 100644
--- a/src/404.md
+++ b/src/404.du
diff --git a/src/_footer.html b/src/_footer.html
deleted file mode 100644
index 605da32..0000000
--- a/src/_footer.html
+++ /dev/null
@@ -1,14 +0,0 @@
- <div class="gap"></div>
- <footer>
- Unless stated otherwise - <a href="/licensing.html">CC BY-SA 4.0</a> - <a href="/about">Kamen</a> @ <a href="/">syndamia.com</a>
- </footer>
- </article>
-
- <div id="scrollBtn" class="btn">&#xFE3D;</div>
-</body>
-
-<script type="text/javascript" src="/scripts/theme-changer.js" crossorigin="anonymous" defer></script>
-<script type="text/javascript" src="/scripts/back-to-top.js" crossorigin="anonymous" defer></script>
-<script type="text/javascript" src="/scripts/keyboard.js" crossorigin="anonymous" defer></script>
-
-</html>
diff --git a/src/_header.html b/src/_header.html
deleted file mode 100644
index a54be39..0000000
--- a/src/_header.html
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-<head>
- <meta charset="UTF-8">
- <meta name="author" content="Kamen Mladenov">
- <meta name="robots" content="index, follow">
- <link rel="icon" href="/img/favicon.ico" type="image/x-icon">
- <link rel="shortcut icon" href="/img/favicon.ico" type="image/x-icon">
- <meta name="theme-color" content="#ffffff"/>
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <link rel="stylesheet" href="/styles.css">
- <link rel="stylesheet" href="/darkmode.css">
- <link rel="stylesheet" href="/hide-js-styling.css">
- <link rel="stylesheet" href="/presentation.css">
- <script type="text/javascript" src="/scripts/styling-preload.js" crossorigin="anonymous"></script>
- <meta name="description" content="[DESCRIPTION]">
- <!-- Thanks https://stackoverflow.com/a/25093272/12036073 -->
- <meta prefix="og: http://ogp.me/ns#" property="og:type" content="website">
- <meta prefix="og: http://ogp.me/ns#" property="og:title" content="[TITLE]">
- <meta prefix="og: http://ogp.me/ns#" property="og:description" content="[DESCRIPTION]">
- <meta prefix="og: http://ogp.me/ns#" property="og:image" content="https://syndamia.com/img/meta-banner.png">
- <meta prefix="og: http://ogp.me/ns#" property="og:url" content="https://syndamia.com">
- <title>[TITLE]</title>
-</head>
-<body id="content-wrapper" text="black" bgcolor="white" link="#336700" vlink="#336700">
- <nav id="sidebar">
- <nav id="header" class="sidebar-section">
- <span class="nocss-aid">[[</span>
-
- <a href="/">Home</a>
- <span id="expandNavbarBtn" class="btn">&#x25B2;</span>
- <script type="text/javascript" src="/scripts/expand-navbar.js" crossorigin="anonymous" defer></script>
-
- <span class="nocss-aid">]]</span>
- </nav>
-
- <nav id="index" class="sidebar-section">
- <span class="nocss-aid"><br>[[</span>
-
- <span>Text</span><span class="nocss-aid">:</span>
- <span class="index-list">
- <a class="index-list-item" href="/blog">Blog</a>
- <a class="index-list-item" href="/teaching">Teaching</a>
- <a class="index-list-item" href="/tutorials">Tutorials</a>
- </span>
-
- <span class="nocss-aid">]]</span>
-
- <span class="nocss-aid"><br>[[</span>
-
- <span>Interactive</span><span class="nocss-aid">:</span>
- <span class="index-list">
- <a class="index-list-item" href="/slides">Slides</a>
- <a class="index-list-item" href="/preserved-web-pages">Preserved web</a>
- </span>
-
- <span class="nocss-aid">]]</span>
-
- <span class="nocss-aid"><br>[[</span>
-
- <span>Files</span><span class="nocss-aid">:</span>
- <span class="index-list">
- <a class="index-list-item" href="/preserved-media">Archived media</a>
- <a class="index-list-item" href="/misc">Miscellaneous</a>
- </span>
-
- <span class="nocss-aid">]]</span>
-
- <span class="nocss-aid"><br>[[</span>
-
- <span>Me</span><span class="nocss-aid">:</span>
- <span class="index-list">
- <a class="index-list-item" href="/about">About</a>
- <a class="index-list-item" href="/setup">Setup</a>
- </span>
-
- <span class="nocss-aid">]]</span>
- </nav>
-
- <span class="nocss-aid"><br></span>
-
- <nav id="settingsWrapper" class="sidebar-section">
- <span class="nocss-aid"><br>[[</span>
-
- <span id="changeThemeBtn" class="btn setting-btn"><span>Light</span><span class="br"></span>theme</span>
- <span id="changeWidthBtn" class="btn setting-btn"><span>Wide</span><span class="br"></span>article</span>
-
- <span class="nocss-aid">]]</span>
- </nav>
-
- <span class="nocss-aid"><br></span>
-
- <nav id="footer" class="sidebar-section">
- <span class="nocss-aid">[[</span>
-
- <a href="/license.html" title="CC BY-SA 4.0 and GNU GPLv3">CC BY-SA 4.0 and GNU GPLv3</a>
-
- <span class="nocss-aid"><br>[[</span><span class="brt"></span>
-
- <a href="/privacy.html" title="Privacy policy">Privacy policy</a> |
- <a href="/accessibility.html" title="Accessibility">Accessibility</a><span class="br"></span><span class="nocss-aid"> |</span>
- <a href="/regarding-js.html" title="Regarding usage of JavaScript">Regarding JavaScript</a><span class="br"></span><span class="nocss-aid"> |</span>
- <a href="/acknowledgements.html" title="Acknowledgements">Acknowledgements</a><span class="br"></span>
-
- <span class="nocss-aid">]]<br>[[</span><span class="brt"></span>
-
- <a href="https://gitlab.com/Syndamia" target="_blank" title="GitLab">GitLab</a> |
- <a href="https://github.com/Syndamia" target="_blank" title="GitHub">GitHub</a> |
- <a href="/about/#contact" target="_blank" title="Contact">Contact</a><span class="br"></span><span class="nocss-aid"> |</span>
- <a href="https://bg.linkedin.com/in/kamen-mladenov" target="_blank" title="Linkedin">LinkedIn</a><span class="br"></span>
-
- <span class="nocss-aid">]]<br>[[</span><span class="brt"></span>
-
- <a href="https://gitlab.com/Syndamia/syndamiadotcom" target="_blank" class="link-tab">Powered with:</a><span class="br"></span>
- <a href="https://gitlab.com/Syndamia/csg" target="_blank" class="link-tab">csg by me</a><span class="br"></span><span class="nocss-aid">, </span>
- <a href="https://kristaps.bsd.lv/lowdown/" target="_blank" class="link-tab">lowdown by Kristaps Dzonsons</a><span class="br"></span><span class="nocss-aid">, </span>
- <a href="https://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html" target="_blank" class="link-tab">awk</a> and <a href="https://www.gnu.org/software/bash/" target="_blank" class="link-tab">GNU bash</a>
-
- <span class="nocss-aid">]]</span>
- </nav>
- </nav>
-
- <article>
- <script type="text/javascript" src="/scripts/page-width.js" crossorigin="anonymous" defer></script>
diff --git a/src/about.du b/src/about.du
new file mode 100644
index 0000000..ed53ba7
--- /dev/null
+++ b/src/about.du
@@ -0,0 +1,123 @@
+# About Me
+
+:defs
+; =[Contact me casually]=
+:
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">
+&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-2c9b555f61c33e30acbe477dcb2956a33e10cc8c.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a>
+
+\n
+
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;">
+&#107;&#097;&#109;&#101;&#110;&#046;&#115;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;-0xDFC9D42E.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a> *[(for this one, make sure to check your spam folder!)]*
+
+; =[Contact me about work and projects I'm maintaining]=
+:
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">
+&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-62ca52e87475c874b9e6ebf3c4c9f716b6ce4c9d.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a>
+
+\n
+
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;">
+&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;-0x354C5F95.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a>
+*[for this one, make sure to check your spam folder!]*
+
+\n
+
+[url https://www.linkedin.com/in/kamen-mladenov/ linkedin.com/in/kamen-mladenov]
+
+; =[Resume]=
+: [url /files/resume-bg.pdf Български] | [url /files/resume-en.pdf English]
+
+
+\n
+
+### Antibio [url https://www.brendangregg.com/antibio.html (opposite of bio, and much more fun)]
+
+<img id="about-image" class="borderless" src="/img/face.jpeg" alt="">
+
+I'm a [url https://www.fmi.uni-sofia.bg/en university] student and general computer nerd.
+My current interests include: operating systems, functional programming, webdev (without =[any]= libraries, pure JavaScript), old tech, some amount of server administration and a teeny weeny bit of computer history.
+
+I have a good amount of [url https://gitlab.com/users/Syndamia/projects projects under my belt], although very few are actually useful.
+I've put down the more notable ones [url /software here], but [url https://github.com/Syndamia/filite-list filite-list] and [url https://github.com/Syndamia/min-youtube-element-blocker min-youtube-element-blocker] seem to have gotten the most attention (if any).
+
+As for what exactly you can expect in the future, anything goes really.
+I've done a lot of low(er)-level programming, a bit less functional programming, professional-ish web development (back-end + front-end), a whole lot of scripting and more server/system administration that I would ever want.
+So, who knows what's gonna be next.
+
+Unfortunately there isn't too much I can show now, especially as content on this website...
+But hey, you gotta start somewhere!
+
+### Software
+
+This is a curated list of the more relevant software projects I've made or heavily contributed to
+
+\n
+
+#### *[2023]*
+
+:defs
+; [url https://gitlab.com/Syndamia/texty-office gitlab / texty-office] + [url https://gitlab.com/Syndamia/texty-office.vim gitlab / texty-office.vim]
+: An imperfect converter from DOCX, PPTX and XLSX to normal text with it's associated [url https://www.vim.org/ Vim] plugin. \n
+ `[GNU GPLv3]` & `[MIT]` | `[C++]` `[vimscript]` | `[Office file]` `[converter]` `[plugin]` `[Vim]` `[CLI tool]`
+
+; [url https://gitlab.com/Syndamia/small-web-utilities gitlab / small-web-utilities] &emsp; *[maintained]*
+: A collection of small but fast utilities, like a checklist, that work locally on your browser. Also hosted [url https://utils.syndamia.com here]. \n
+ `[GNU GPLv3]` | `[HTML]` `[Javascript]` | `[checklist]` `[utilities]`
+
+; [url https://gitlab.com/Syndamia/ss-law gitlab / ss-law] + [url https://github.com/Syndamia/ss-law github / ss-law] &emsp; *[maintained]*
+: A small, lightweight and simple static site generation system, extracted as a template from my own \n
+ `[Markdown]` `[bash]` `[awk]` | `[ssg]` `[lowdown]` `[static site generator]` `[pipelines]`
+
+; [url https://gitlab.com/Syndamia/homelander gitlab / homelander] &emsp; *[maintained]*
+: A very small and good looking, handmade prompt for zsh \n
+ `[GPLv3]` | `[bash]` | `[zsh]` `[shell]` `[prompt]` `[script]` `[Linux]`
+
+; [url https://gitlab.com/Syndamia/goodwolf gitlab / goodwolf] &emsp; *[abandoned]*
+: Fork of the [url https://hacktivis.me/projects/badwolf badwolf] browser, which aims to add features \n
+ `[BSD-3-Clause]` | `[C]` | `[web browser]` `[GTK]` `[WebKitGTK]` `[Linux]`
+
+
+#### *[2021]*
+
+:defs
+; [url https://gitlab.com/Syndamia/reposync gitlab / RepoSync] &emsp; *[completed]*
+: Script and some config files for synchronizing a git repository with a server \n
+ `[MIT]` | `[python]` | `[server]` `[git]` `[systemd]`
+
+; [url https://github.com/Syndamia/filite-list github / filite-list] &emsp; *[completed]*
+: Script for managing [url https://github.com/raftario/filite filite] links \n
+ `[GPLv3]` | `[bash]` | `[filite]` `[server]` `[script]` `[Linux]`
+
+
+#### *[2020]*
+
+:defs
+; [url https://github.com/Team-Kaleidoscope/DevHive github / DevHive] and [url https://github.com/Team-Kaleidoscope/DevHive-Angular github / DevHive-Angular] &emsp; *[completed]*
+: DevHive is a social network oriented towards programmers. It's FOSS, built from the ground up, and made from a team of three for a course. \n
+ `[GPLv3]` | `[C#]` `[TypeScript]` | `[Angular]` `[ASP.NET Core]` `[social media]` `[mvc]` `[Docker]` `[CSS]`
+
+; [url https://github.com/Syndamia/min-youtube-element-blocker github / min-youtube-element-blocker] &emsp; *[maintained]*
+: Userscript for hiding certain UI elements in YouTube \n
+ `[MIT]` | `[JavaScript]` | `[youtube]` `[userscript]` `[css]`
diff --git a/src/about.md b/src/about.md
deleted file mode 100644
index 52c6bf9..0000000
--- a/src/about.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# About Me
-
-**Contact me casually**
-: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-2c9b555f61c33e30acbe477dcb2956a33e10cc8c.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a><br><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;">&#107;&#097;&#109;&#101;&#110;&#046;&#115;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;-0xDFC9D42E.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a> *(for this one, make sure to check your spam folder!)*
-
-**Contact me about work and projects I'm maintaining**
-: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-62ca52e87475c874b9e6ebf3c4c9f716b6ce4c9d.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a> <br> <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;">&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;-0x354C5F95.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a> *(for this one, make sure to check your spam folder!)*<br>[linkedin.com/in/kamen-mladenov](https://www.linkedin.com/in/kamen-mladenov/)
-
-**Resume**
-: [Български](/files/resume-bg.pdf) | [English](/files/resume-en.pdf)
-
-<br>
-
-### Antibio [(opposite of bio, and much more fun)](https://www.brendangregg.com/antibio.html)
-
-<img id="about-image" class="borderless" src="/img/face.jpeg" alt="">
-
-I'm a [university](https://www.fmi.uni-sofia.bg/en) student and general computer nerd.
-My current interests include: operating systems, functional programming, webdev (without **any** libraries, pure JavaScript), old tech, some amount of server administration and a teeny weeny bit of computer history.
-
-I have a good amount of [projects under my belt](https://gitlab.com/users/Syndamia/projects), although very few are actually useful.
-I've put down the more notable ones [here](/software), but [filite-list](https://github.com/Syndamia/filite-list) and [min-youtube-element-blocker](https://github.com/Syndamia/min-youtube-element-blocker) seem to have gotten the most attention (if any).
-
-As for what exactly you can expect in the future, anything goes really.
-I've done a lot of low(er)-level programming, a bit less functional programming, professional-ish web development (back-end + front-end), a whole lot of scripting and more server/system administration that I would ever want.
-So, who knows what's gonna be next.
-
-Unfortunately there isn't too much I can show now, especially as content on this website...
-But hey, you gotta start somewhere!
-
-### Software
-
-This is a curated list of the more relevant software projects I've made or heavily contributed to
-
-<br>
-
-#### *2023*
-
-[gitlab / texty-office](https://gitlab.com/Syndamia/texty-office) + [gitlab / texty-office.vim](https://gitlab.com/Syndamia/texty-office.vim)
-: An imperfect converter from DOCX, PPTX and XLSX to normal text with it's associated [Vim](https://www.vim.org/) plugin. <br> `GNU GPLv3` & `MIT` | `C++` `vimscript` | `Office file` `converter` `plugin` `Vim` `CLI tool`
-
-[gitlab / small-web-utilities](https://gitlab.com/Syndamia/small-web-utilities) &emsp; *maintained*
-: A collection of small but fast utilities, like a checklist, that work locally on your browser. Also hosted [here](https://utils.syndamia.com). <br> `GNU GPLv3` | `HTML` `Javascript` | `checklist` `utilities`
-
-[gitlab / ss-law](https://gitlab.com/Syndamia/ss-law) + [github / ss-law](https://github.com/Syndamia/ss-law) &emsp; *maintained*
-: A small, lightweight and simple static site generation system, extracted as a template from my own <br> `Markdown` `bash` `awk` | `ssg` `lowdown` `static site generator` `pipelines`
-
-[gitlab / homelander](https://gitlab.com/Syndamia/homelander) &emsp; *maintained*
-: A very small and good looking, handmade prompt for zsh <br> `GPLv3` | `bash` | `zsh` `shell` `prompt` `script` `Linux`
-
-[gitlab / goodwolf](https://gitlab.com/Syndamia/goodwolf) &emsp; *abandoned*
-: Fork of the [badwolf](https://hacktivis.me/projects/badwolf) browser, which aims to add features <br> `BSD-3-Clause` | `C` | `web browser` `GTK` `WebKitGTK` `Linux`
-
-#### *2021*
-
-[gitlab / RepoSync](https://gitlab.com/Syndamia/reposync) &emsp; *completed*
-: Script and some config files for synchronizing a git repository with a server <br> `MIT` | `python` | `server` `git` `systemd`
-
-[github / filite-list](https://github.com/Syndamia/filite-list) &emsp; *completed*
-: Script for managing [filite](https://github.com/raftario/filite) links <br> `GPLv3` | `bash` | `filite` `server` `script` `Linux`
-
-#### *2020*
-
-[github / DevHive](https://github.com/Team-Kaleidoscope/DevHive) and [github / DevHive-Angular](https://github.com/Team-Kaleidoscope/DevHive-Angular) &emsp; *completed*
-: DevHive is a social network oriented towards programmers. It's FOSS, built from the ground up, and made from a team of three for a course. <br> `GPLv3` | `C#` `TypeScript` | `Angular` `ASP.NET Core` `social media` `mvc` `Docker` `CSS`
-
-[github / min-youtube-element-blocker](https://github.com/Syndamia/min-youtube-element-blocker) &emsp; *maintained*
-: Userscript for hiding certain UI elements in YouTube <br> `MIT` | `JavaScript` | `youtube` `userscript` `css`
diff --git a/src/about/index.du b/src/about/index.du
new file mode 100644
index 0000000..ed53ba7
--- /dev/null
+++ b/src/about/index.du
@@ -0,0 +1,123 @@
+# About Me
+
+:defs
+; =[Contact me casually]=
+:
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">
+&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-2c9b555f61c33e30acbe477dcb2956a33e10cc8c.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a>
+
+\n
+
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;">
+&#107;&#097;&#109;&#101;&#110;&#046;&#115;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;-0xDFC9D42E.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a> *[(for this one, make sure to check your spam folder!)]*
+
+; =[Contact me about work and projects I'm maintaining]=
+:
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">
+&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-62ca52e87475c874b9e6ebf3c4c9f716b6ce4c9d.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a>
+
+\n
+
+<a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;">
+&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;
+</a>
+
+<a class="borderless" href="/files/publickey-&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;-0x354C5F95.asc">
+ <img class="borderless" src="/img/pgpkey.gif" alt="PGP key">
+</a>
+*[for this one, make sure to check your spam folder!]*
+
+\n
+
+[url https://www.linkedin.com/in/kamen-mladenov/ linkedin.com/in/kamen-mladenov]
+
+; =[Resume]=
+: [url /files/resume-bg.pdf Български] | [url /files/resume-en.pdf English]
+
+
+\n
+
+### Antibio [url https://www.brendangregg.com/antibio.html (opposite of bio, and much more fun)]
+
+<img id="about-image" class="borderless" src="/img/face.jpeg" alt="">
+
+I'm a [url https://www.fmi.uni-sofia.bg/en university] student and general computer nerd.
+My current interests include: operating systems, functional programming, webdev (without =[any]= libraries, pure JavaScript), old tech, some amount of server administration and a teeny weeny bit of computer history.
+
+I have a good amount of [url https://gitlab.com/users/Syndamia/projects projects under my belt], although very few are actually useful.
+I've put down the more notable ones [url /software here], but [url https://github.com/Syndamia/filite-list filite-list] and [url https://github.com/Syndamia/min-youtube-element-blocker min-youtube-element-blocker] seem to have gotten the most attention (if any).
+
+As for what exactly you can expect in the future, anything goes really.
+I've done a lot of low(er)-level programming, a bit less functional programming, professional-ish web development (back-end + front-end), a whole lot of scripting and more server/system administration that I would ever want.
+So, who knows what's gonna be next.
+
+Unfortunately there isn't too much I can show now, especially as content on this website...
+But hey, you gotta start somewhere!
+
+### Software
+
+This is a curated list of the more relevant software projects I've made or heavily contributed to
+
+\n
+
+#### *[2023]*
+
+:defs
+; [url https://gitlab.com/Syndamia/texty-office gitlab / texty-office] + [url https://gitlab.com/Syndamia/texty-office.vim gitlab / texty-office.vim]
+: An imperfect converter from DOCX, PPTX and XLSX to normal text with it's associated [url https://www.vim.org/ Vim] plugin. \n
+ `[GNU GPLv3]` & `[MIT]` | `[C++]` `[vimscript]` | `[Office file]` `[converter]` `[plugin]` `[Vim]` `[CLI tool]`
+
+; [url https://gitlab.com/Syndamia/small-web-utilities gitlab / small-web-utilities] &emsp; *[maintained]*
+: A collection of small but fast utilities, like a checklist, that work locally on your browser. Also hosted [url https://utils.syndamia.com here]. \n
+ `[GNU GPLv3]` | `[HTML]` `[Javascript]` | `[checklist]` `[utilities]`
+
+; [url https://gitlab.com/Syndamia/ss-law gitlab / ss-law] + [url https://github.com/Syndamia/ss-law github / ss-law] &emsp; *[maintained]*
+: A small, lightweight and simple static site generation system, extracted as a template from my own \n
+ `[Markdown]` `[bash]` `[awk]` | `[ssg]` `[lowdown]` `[static site generator]` `[pipelines]`
+
+; [url https://gitlab.com/Syndamia/homelander gitlab / homelander] &emsp; *[maintained]*
+: A very small and good looking, handmade prompt for zsh \n
+ `[GPLv3]` | `[bash]` | `[zsh]` `[shell]` `[prompt]` `[script]` `[Linux]`
+
+; [url https://gitlab.com/Syndamia/goodwolf gitlab / goodwolf] &emsp; *[abandoned]*
+: Fork of the [url https://hacktivis.me/projects/badwolf badwolf] browser, which aims to add features \n
+ `[BSD-3-Clause]` | `[C]` | `[web browser]` `[GTK]` `[WebKitGTK]` `[Linux]`
+
+
+#### *[2021]*
+
+:defs
+; [url https://gitlab.com/Syndamia/reposync gitlab / RepoSync] &emsp; *[completed]*
+: Script and some config files for synchronizing a git repository with a server \n
+ `[MIT]` | `[python]` | `[server]` `[git]` `[systemd]`
+
+; [url https://github.com/Syndamia/filite-list github / filite-list] &emsp; *[completed]*
+: Script for managing [url https://github.com/raftario/filite filite] links \n
+ `[GPLv3]` | `[bash]` | `[filite]` `[server]` `[script]` `[Linux]`
+
+
+#### *[2020]*
+
+:defs
+; [url https://github.com/Team-Kaleidoscope/DevHive github / DevHive] and [url https://github.com/Team-Kaleidoscope/DevHive-Angular github / DevHive-Angular] &emsp; *[completed]*
+: DevHive is a social network oriented towards programmers. It's FOSS, built from the ground up, and made from a team of three for a course. \n
+ `[GPLv3]` | `[C#]` `[TypeScript]` | `[Angular]` `[ASP.NET Core]` `[social media]` `[mvc]` `[Docker]` `[CSS]`
+
+; [url https://github.com/Syndamia/min-youtube-element-blocker github / min-youtube-element-blocker] &emsp; *[maintained]*
+: Userscript for hiding certain UI elements in YouTube \n
+ `[MIT]` | `[JavaScript]` | `[youtube]` `[userscript]` `[css]`
diff --git a/src/about/index.md b/src/about/index.md
deleted file mode 100644
index 52c6bf9..0000000
--- a/src/about/index.md
+++ /dev/null
@@ -1,68 +0,0 @@
-# About Me
-
-**Contact me casually**
-: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-2c9b555f61c33e30acbe477dcb2956a33e10cc8c.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a><br><a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;">&#107;&#097;&#109;&#101;&#110;&#046;&#115;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#115;&#64;&#115;&#121;&#110;&#100;&#97;&#109;&#105;&#97;&#46;&#99;&#111;&#109;-0xDFC9D42E.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a> *(for this one, make sure to check your spam folder!)*
-
-**Contact me about work and projects I'm maintaining**
-: <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-62ca52e87475c874b9e6ebf3c4c9f716b6ce4c9d.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a> <br> <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;">&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;-0x354C5F95.asc"><img class="borderless" src="/img/pgpkey.gif" alt="PGP key"></a> *(for this one, make sure to check your spam folder!)*<br>[linkedin.com/in/kamen-mladenov](https://www.linkedin.com/in/kamen-mladenov/)
-
-**Resume**
-: [Български](/files/resume-bg.pdf) | [English](/files/resume-en.pdf)
-
-<br>
-
-### Antibio [(opposite of bio, and much more fun)](https://www.brendangregg.com/antibio.html)
-
-<img id="about-image" class="borderless" src="/img/face.jpeg" alt="">
-
-I'm a [university](https://www.fmi.uni-sofia.bg/en) student and general computer nerd.
-My current interests include: operating systems, functional programming, webdev (without **any** libraries, pure JavaScript), old tech, some amount of server administration and a teeny weeny bit of computer history.
-
-I have a good amount of [projects under my belt](https://gitlab.com/users/Syndamia/projects), although very few are actually useful.
-I've put down the more notable ones [here](/software), but [filite-list](https://github.com/Syndamia/filite-list) and [min-youtube-element-blocker](https://github.com/Syndamia/min-youtube-element-blocker) seem to have gotten the most attention (if any).
-
-As for what exactly you can expect in the future, anything goes really.
-I've done a lot of low(er)-level programming, a bit less functional programming, professional-ish web development (back-end + front-end), a whole lot of scripting and more server/system administration that I would ever want.
-So, who knows what's gonna be next.
-
-Unfortunately there isn't too much I can show now, especially as content on this website...
-But hey, you gotta start somewhere!
-
-### Software
-
-This is a curated list of the more relevant software projects I've made or heavily contributed to
-
-<br>
-
-#### *2023*
-
-[gitlab / texty-office](https://gitlab.com/Syndamia/texty-office) + [gitlab / texty-office.vim](https://gitlab.com/Syndamia/texty-office.vim)
-: An imperfect converter from DOCX, PPTX and XLSX to normal text with it's associated [Vim](https://www.vim.org/) plugin. <br> `GNU GPLv3` & `MIT` | `C++` `vimscript` | `Office file` `converter` `plugin` `Vim` `CLI tool`
-
-[gitlab / small-web-utilities](https://gitlab.com/Syndamia/small-web-utilities) &emsp; *maintained*
-: A collection of small but fast utilities, like a checklist, that work locally on your browser. Also hosted [here](https://utils.syndamia.com). <br> `GNU GPLv3` | `HTML` `Javascript` | `checklist` `utilities`
-
-[gitlab / ss-law](https://gitlab.com/Syndamia/ss-law) + [github / ss-law](https://github.com/Syndamia/ss-law) &emsp; *maintained*
-: A small, lightweight and simple static site generation system, extracted as a template from my own <br> `Markdown` `bash` `awk` | `ssg` `lowdown` `static site generator` `pipelines`
-
-[gitlab / homelander](https://gitlab.com/Syndamia/homelander) &emsp; *maintained*
-: A very small and good looking, handmade prompt for zsh <br> `GPLv3` | `bash` | `zsh` `shell` `prompt` `script` `Linux`
-
-[gitlab / goodwolf](https://gitlab.com/Syndamia/goodwolf) &emsp; *abandoned*
-: Fork of the [badwolf](https://hacktivis.me/projects/badwolf) browser, which aims to add features <br> `BSD-3-Clause` | `C` | `web browser` `GTK` `WebKitGTK` `Linux`
-
-#### *2021*
-
-[gitlab / RepoSync](https://gitlab.com/Syndamia/reposync) &emsp; *completed*
-: Script and some config files for synchronizing a git repository with a server <br> `MIT` | `python` | `server` `git` `systemd`
-
-[github / filite-list](https://github.com/Syndamia/filite-list) &emsp; *completed*
-: Script for managing [filite](https://github.com/raftario/filite) links <br> `GPLv3` | `bash` | `filite` `server` `script` `Linux`
-
-#### *2020*
-
-[github / DevHive](https://github.com/Team-Kaleidoscope/DevHive) and [github / DevHive-Angular](https://github.com/Team-Kaleidoscope/DevHive-Angular) &emsp; *completed*
-: DevHive is a social network oriented towards programmers. It's FOSS, built from the ground up, and made from a team of three for a course. <br> `GPLv3` | `C#` `TypeScript` | `Angular` `ASP.NET Core` `social media` `mvc` `Docker` `CSS`
-
-[github / min-youtube-element-blocker](https://github.com/Syndamia/min-youtube-element-blocker) &emsp; *maintained*
-: Userscript for hiding certain UI elements in YouTube <br> `MIT` | `JavaScript` | `youtube` `userscript` `css`
diff --git a/src/accessibility.md b/src/accessibility.du
index 6dc2550..d9356cd 100644
--- a/src/accessibility.md
+++ b/src/accessibility.du
@@ -6,7 +6,7 @@ This is how I reach a middle ground between both sides:
### Bare bone website version
-At [tiny.syndamia.com](https://tiny.syndamia.com) I offer my website with almost all styling and JavaScript functionality removed.
+At [url https://tiny.syndamia.com tiny.syndamia.com] I offer my website with almost all styling and JavaScript functionality removed.
You'll receive only the webpage text and asset contents, and nothing more.
From my testing, pages usually load two times faster on tiny.syndamia.com.
@@ -14,23 +14,27 @@ I do also hope that without the styling and JavaScript, people with impairments
### Consumable content with everything blocked
-By design, all "normal" pages[^normal-pages] can be viewed without any JavaScript, any styling and any custom font.
+'footnote normal-pages Meaning a page that has only text, images and video. If the page contains a JavaScript demo, it obviously cannot function entirely without JS.
+
+By design, all "normal" pages[$normal-pages] can be viewed without any JavaScript, any styling and any custom font.
All of those are meant to make the browsing experience prettier and easier for those that can benefit from it and allow you to change and block certain features without the content being obstructed.
-Even my [talks](/talks), where each one is a collection of delicately crafted CSS and JS slides, can be viewed as any normal text article on my site.
+Even my [url /talks talks], where each one is a collection of delicately crafted CSS and JS slides, can be viewed as any normal text article on my site.
### Reasonable icons
First, icons on this website are managed with an icon font.
-I've watched [Seren Davies' talk](https://www.youtube.com/watch?v=9xXBYcWgCHA), but I've found working with SVGs noticeably increases workload on my end.
+I've watched [url https://www.youtube.com/watch?v=9xXBYcWgCHA Seren Davies' talk], but I've found working with SVGs noticeably increases workload on my end.
-**However**, I've still implemented those icons with accessibility in mind:
+=[However]=, I've still implemented those icons with accessibility in mind:
+:unordered
- Navigation is done with text entries in the sidebar, not icons.
+
- Buttons for other functionalities use text to reference their action, rather than (only) an "image", most of the time.
The only mission-critical one that isn't represented with text is the sidebar folding and expanding button, right next to "Home".
But it is mapped to the standard up and down pointing triangle characters, so it should still be useable.
+
- Icons that aren't decorative are "mapped" to their closest standard Unicode symbol, so even without the font, their purpose should be fairly understandable.
Furthermore, I make sure those Unicode symbols have been standardised since at least 1999.
-- My font has only the icons I use, and compared to the SVG equivalent setup, it takes up roughly a third of the size.
-[^normal-pages]: Meaning a page that has only text, images and video. If the page contains a JavaScript demo, it obviously cannot function entirely without JS.
+- My font has only the icons I use, and compared to the SVG equivalent setup, it takes up roughly a third of the size.
diff --git a/src/acknowledgements.du b/src/acknowledgements.du
new file mode 100644
index 0000000..06d0aad
--- /dev/null
+++ b/src/acknowledgements.du
@@ -0,0 +1,36 @@
+# Acknowledgements
+
+:defs
+; [url https://github.com/tabler/tabler-icons tabler-icons], licensed under [url https://github.com/tabler/tabler-icons/blob/master/LICENSE MIT]
+: All UI icons
+
+; [url https://github.com/sindresorhus/github-markdown-css github-markdown-css], licensed under [url https://github.com/sindresorhus/github-markdown-css/blob/main/license MIT]
+: Some of the styling, especially for tables and code/pre tags
+
+; [url https://github.com/lipis/flag-icons flag-icons], licensed under [url https://github.com/lipis/flag-icons/blob/main/LICENSE MIT]
+: Icons of flags
+
+; [url https://github.com/linuxmint/mint-y-icons mint-y-icons], licensed under [url https://creativecommons.org/licenses/by-sa/4.0 CC BY-SA 4.0]
+: Certain icons in articles/pages
+
+
+## Special thanks to
+
+:defs
+; [url https://danluu.com/programming-blogs/ danuluu's programming blogs list]
+: For the excellent list of awesome blogs, from which I drew a good amount of inspiration.
+
+; [url https://shipilev.net/ Aleksey Shipilëv's], [url https://tonsky.me/ Nikita's], [url https://jvns.ca/ Julia Evan's] and [url https://hacktivis.me Haelwenn Monnier's] blogs
+: From which I drew the most inspiration
+
+; [url http://www.ringlet.net/roam/ Peter Pentchev's personal page]
+: For igniting my love for website badges and the somewhat rare "Created with Vim" badge
+
+; [url https://www.anybrowser.org/cdaveb/ Cari D. Burstein]
+: For his [url https://www.anybrowser.org/campaign/index.html Viewable with Any Browser] comapign and the awesome [url https://www.anybrowser.org/campaign/abgraphics.html provided badges]
+
+; [url https://sh2.us/ RusticCyberpunk/cypnk] <img class="borderless" src="https://sh2.us/buttons/btn-cypnk-at-sh2.png" alt="">
+: For his [url https://sh2.us/buttons/ archive] of [url https://gtmcknight.com/ Taylor McKnight's] collection of buttons
+
+; [url https://kalsey.com/ Adam Kalsey]
+: For his awesome [url https://kalsey.com/tools/buttonmaker/ button maker]
diff --git a/src/acknowledgements.md b/src/acknowledgements.md
deleted file mode 100644
index 3d0ae3e..0000000
--- a/src/acknowledgements.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Acknowledgements
-
-[tabler-icons](https://github.com/tabler/tabler-icons), licensed under [MIT](https://github.com/tabler/tabler-icons/blob/master/LICENSE)
-: All UI icons
-
-[github-markdown-css](https://github.com/sindresorhus/github-markdown-css), licensed under [MIT](https://github.com/sindresorhus/github-markdown-css/blob/main/license)
-: Some of the styling, especially for tables and code/pre tags
-
-[flag-icons](https://github.com/lipis/flag-icons), licensed under [MIT](https://github.com/lipis/flag-icons/blob/main/LICENSE)
-: Icons of flags
-
-[mint-y-icons](https://github.com/linuxmint/mint-y-icons), licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0)
-: Certain icons in articles/pages
-
-## Special thanks to
-
-[danuluu's programming blogs list](https://danluu.com/programming-blogs/)
-: For the excellent list of awesome blogs, from which I drew a good amount of inspiration.
-
-[Aleksey Shipilëv's](https://shipilev.net/), [Nikita's](https://tonsky.me/), [Julia Evan's](https://jvns.ca/) and [Haelwenn Monnier's](https://hacktivis.me) blogs
-: From which I drew the most inspiration
-
-[Peter Pentchev's personal page](http://www.ringlet.net/roam/)
-: For igniting my love for website badges and the somewhat rare "Created with Vim" badge
-
-[Cari D. Burstein](https://www.anybrowser.org/cdaveb/)
-: For his [Viewable with Any Browser](https://www.anybrowser.org/campaign/index.html) comapign and the awesome [provided badges](https://www.anybrowser.org/campaign/abgraphics.html)
-
-[RusticCyberpunk/cypnk](https://sh2.us/) <img class="borderless" src="https://sh2.us/buttons/btn-cypnk-at-sh2.png" alt="">
-: For his [archive](https://sh2.us/buttons/) of [Taylor McKnight's](https://gtmcknight.com/) collection of buttons
-
-[Adam Kalsey](https://kalsey.com/)
-: For his awesome [button maker](https://kalsey.com/tools/buttonmaker/)
diff --git a/src/blog.du b/src/blog.du
new file mode 100644
index 0000000..c10655d
--- /dev/null
+++ b/src/blog.du
@@ -0,0 +1,63 @@
+# Blog
+
+Articles detailing personal experiences or exploration of certain topics.
+
+\n
+
+:defs
+; [$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] 20 Feb &emsp; [url /blog/microsoft-and-foss-extinguish Microsoft and FOSS: a fire to be extinguished]
+: `[Shallow dive]` | `[Opinion]` | `[Microsoft]` `[GitHub]` `[Linux]` `[FOSS]`
+
+
+#### *[2023]*
+
+:defs
+; [$gb] 30 Aug &emsp; [url /blog/thinkpad-x270-my-favorite-machine ThinkPad X270 - my favorite machine]
+: `[Medium dive]` | `[Review]` | `[Lenovo]` `[ThinkPad]` `[Yoga]`
+
+; [$gb] 19 July &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]`
+
+; [$bg] 14 July &emsp; [url /blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq ФМИ и висшето образование в програмистката индустрия]
+: `[Deep dive]` | `[University]` | `[FMI]` `[Education]`
+
+; [$gb] 07 June &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] 01 May &emsp; [url /blog/bash-is-weird BASH is weird]
+: `[Shallow dive]` | `[bash]` | `[Linux]` `[scripting]`
+
+; [$gb] 18 Apr &emsp; [url /blog/sane-explanation-of-compilers/part-1.html 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]`
+
+
+#### *[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] 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] 04 Dec &emsp; [url /blog/taming-the-fun-too Taming The Fun-too]
+: `[Story]` | `[Funtoo]` | `[Linux]` `[Gentoo]` `[packages]`
+
+; [$gb] 10 Sep &emsp; [url /blog/encrypted-email Encrypted email]
+: `[Medium dive]` | `[Email]` | `[Encryption]` `[Security]` `[PGP]` `[S/MIME]` `[Protonmail]` `[Tutanota]`
+
+
+#### *[2020]*
+
+:defs
+; [$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#]`
diff --git a/src/blog.md b/src/blog.md
deleted file mode 100644
index d5238fe..0000000
--- a/src/blog.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Blog
-
-Articles detailing personal experiences or exploration of certain topics.
-
-<br>
-
-&.bg 18 Nov &emsp; [Суичът изгоря!](/blog/switchut-izgorq)
-: `Shallow dive` | `Story` | `Networking` `Switch` `NetworkPartner`
-
-&.gb 06 Oct &emsp; [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; [Microsoft and FOSS: a fire to be extinguished](/blog/microsoft-and-foss-extinguish)
-: `Shallow dive` | `Opinion` | `Microsoft` `GitHub` `Linux` `FOSS`
-
-#### *2023*
-
-&.gb 30 Aug &emsp; [ThinkPad X270 - my favorite machine](/blog/thinkpad-x270-my-favorite-machine)
-: `Medium dive` | `Review` | `Lenovo` `ThinkPad` `Yoga`
-
-&.gb 19 July &emsp; [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 July &emsp; [ФМИ и висшето образование в програмистката индустрия](/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq)
-: `Deep dive` | `University` | `FMI` `Education`
-
-&.gb 07 June &emsp; [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; [BASH is weird](/blog/bash-is-weird)
-: `Shallow dive` | `bash` | `Linux` `scripting`
-
-&.gb 18 Apr &emsp; [Sane explanation of compilers: Part 1](/blog/sane-explanation-of-compilers/part-1.html)
-: `Deep dive` | `Compilers` | `C` `yacc` `bison` `math` `Trees` `Regex` `Grammar` `Languages`
-
-&.gb 13 Jan &emsp; [Plan 9 in Linux: Mouse menus](/blog/plan9-in-linux-mouse-menus)
-: `Medium dive` | `Linux` | `Plan 9` `mouse` `bash` `script` `X11` `openbox` `jgmenu` `plumber`
-
-#### *2022*
-
-&.gb 23 Dec &emsp; [2.6 years of web design](/blog/2.6-years-of-web-design)
-: `Shallow dive` | `Web design`
-
-&.gb 13 Dec &emsp; [When a language forces simpler thinking](/blog/when-a-language-forces-simpler-thinking)
-: `Shallow dive` | `Common Lisp` | `Advent of Code`
-
-&.gb 04 Dec &emsp; [Taming The Fun-too](/blog/taming-the-fun-too)
-: `Story` | `Funtoo` | `Linux` `Gentoo` `packages`
-
-&.gb 10 Sep &emsp; [Encrypted email](/blog/encrypted-email)
-: `Medium dive` | `Email` | `Encryption` `Security` `PGP` `S/MIME` `Protonmail` `Tutanota`
-
-#### *2020*
-
-&.gb 20 May &emsp; [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/2.6-years-of-web-design/index.md b/src/blog/2.6-years-of-web-design/index.du
index 109d6d7..10d1237 100644
--- a/src/blog/2.6-years-of-web-design/index.md
+++ b/src/blog/2.6-years-of-web-design/index.du
@@ -1,17 +1,23 @@
# 2.6 years of web design
-## Contents
+'define expected-reading 13 min
+'define created 23 December 2022
+'define edited 23 December 2022
+[$pagenav]
-1. [v1.0](#v1.0)
-2. [v2.0](#v2.0)
-3. [v2.1](#v2.1)
-4. [v2.2](#v2.2)
-5. [v3.0](#v3.0)
-6. [v3.1](#v3.1)
-7. [now](#now)
-8. [Appendix](#appendix)
+: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]
-On 17 May 2020 I [pushed the very first version of this website](https://gitlab.com/Syndamia/syndamiadotcom/-/commit/f2d3991cf3381d4d794b3faa2890439bb70af729), which went live 3 days later.
+
+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.
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.
@@ -19,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:
-![](./img/v1.0-index.png)
+[image ./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:
-![](./img/v1.0-code block.png)
+[image ./img/v1.0-code\ block.png]
-Although I wasn't the one to invent that color scheme, it was *inspired* from [xed](https://github.com/linuxmint/xed)'s Oblivion theme.
+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.
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.
-![](./img/v1.0-tutorial-page.png)
+[image ./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:
-![](./img/v1.0-index-smallscreen.png)
+[image ./img/v1.0-index-smallscreen.png]
-You know, if this website was published on [neocities](https://neocities.org/), my desktop-oriented unscaleable layout might've been seen as cool and novel...
+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...
Thankfully (or maybe unfortunately), I didn't go down that road.
Finally, tables, like those used in the "Projects" listing, were the absolute dumbest:
-![](./img/v1.0-projects.png)
+[image ./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 [**generated client-side with JavaScript**](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/v1.0/website/js)?
+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]=]?
-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 *[adventures]*.
### v2.0
-Less than two months later, on 21 July, [I did a complete redesign](https://gitlab.com/Syndamia/syndamiadotcom/-/commit/64fbbd514733e42dd047bf65c511563a84ebd629).
-To more easily separate the two, I decided to use [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.
+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.
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 [Wolfgang's Channel](https://www.youtube.com/@WolfgangsChannel)'s tutorial on making a ["Fast & Minimal Blog"](https://www.youtube.com/watch?v=N_ttw2Dihn8).
-There, he showed how to setup and use [ssg](https://www.romanzolotarev.com/ssg.html) with [lowdown](https://kristaps.bsd.lv/lowdown/), a combination that still powers this website.
+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.
Turning to the actual website itself, now it looked quite pleasant, in the day at least:
-![](./img/v2.0-index.png)
+[image ./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:
-![](./img/v2.0-code block.png)
-![](./img/v2.0-resume.png)
+[image ./img/v2.0-code\ block.png]
+[image ./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 [sindresorhus](https://github.com/sindresorhus/github-markdown-css).
+Though that last part wasn't done by me, but by [url https://github.com/sindresorhus/github-markdown-css sindresorhus].
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.
-![](./img/v2.0-index-smartphone.png)
+[image ./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.
@@ -87,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:
-![](./img/v2.1-index-smartphone.png)
+[image ./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.
@@ -95,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 [gruvbox](https://github.com/morhetz/gruvbox), a color overhaul needed to be done.
+As an avid fan of not hurting my eyes and [url https://github.com/morhetz/gruvbox 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 [2.1's release](https://gitlab.com/Syndamia/syndamiadotcom/-/releases/v2.1): [DevHive](https://github.com/Team-Kaleidoscope).
+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].
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.
@@ -105,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 [Pencil](https://pencil.evolus.vn/), a somewhat limited application for designing layouts:
+The first was done in [url https://pencil.evolus.vn/ Pencil], a somewhat limited application for designing layouts:
-![](./img/devhive-index-concept1.png)
+[image ./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:
-![](./img/devhive-index-concept2.png)
+[image ./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.
-![](./img/devhive-index-concept3.png)
+[image ./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.
@@ -129,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:
-![](./img/devhive-index-concept4.png)
+[image ./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.
@@ -150,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;
-![](./img/devhive-index-concept5.png)
+[image ./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:
-![](./img/v2.2-index.png)
+[image ./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.
@@ -165,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 (=[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:
-![](./img/v2.2-index-footer-smallwidth.png)
+[image ./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?
-![](./img/v2.2-index-full-header.png)
+[image ./img/v2.2-index-full-header.png]
And don't get me started on how comically bad this is on mobile:
-![](./img/v2.2-index-full-header-smartphone.png)
+[image ./img/v2.2-index-full-header-smartphone.png]
Something needed to change yet again, and something did.
-A year and a third later, on [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:
+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:
-![](./img/v3.0-index-initial.png)
+[image ./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 [Julia Evan's blog](https://jvns.ca/), where there is a big orange ribbon running on the sides and across the page.
+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.
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:
-![](./img/v3.0-index.png)
+[image ./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.
@@ -204,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 [added color separation between the background and article and navbar](https://gitlab.com/Syndamia/syndamiadotcom/-/commit/55afc85bf7da9c0ed5e8859027080aebfa55ec50).
+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].
-![](./img/v3.1-index.png)
+[image ./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:
-![](./img/v3.1-index-smartphone.png)
+[image ./img/v3.1-index-smartphone.png]
Another notable styling change was in tables.
-I pretty much stole the design from [LEMMiNO](https://www.lemmi.no/)'s website:
+I pretty much stole the design from [url https://www.lemmi.no/ LEMMiNO]'s website:
-![](./img/v3.1-table.png)
+[image ./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 [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 [the slide presentation system](/talks/demo.html) without too much trouble.
+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
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 [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.
+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.
Happy holidays everyone!
### Appendix
This post has been in the works since 01 August 2020.
-At the time it was just called ["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.
+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.
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, [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.
@@ -246,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!
+*[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
new file mode 100644
index 0000000..3fe56cb
--- /dev/null
+++ b/src/blog/bash-is-weird/index.du
@@ -0,0 +1,65 @@
+# BASH is weird
+
+'define expected-reading 4 min
+'define created 01 May 2023
+'define edited 02 May 2023
+[$pagenav]
+
+'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).
+An example which illustrates my point would be:
+
+```bash
+myvar=($(echo A B C))
+myvar=1234
+echo $((myvar += 46)) ${myvar[\${myvar:0:1}]}
+
+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.
+
+ .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]).
+
+ .p
+ Side note: obviously, the original expected behaviour can happen if we use some quotes:
+
+ ```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.
+ 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].
+
+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]`.
+ 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.
+ 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:
+
+.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].
+Every language has mind-numbing oddities, some get the out of the way from the start (like BASH), and others much later.
diff --git a/src/blog/bash-is-weird/index.md b/src/blog/bash-is-weird/index.md
deleted file mode 100644
index d0d7190..0000000
--- a/src/blog/bash-is-weird/index.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# BASH is weird
-
-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 [Linuxgraphy by Strabo](/talks/linuxgraphy-by-strabo) presentation).
-An example which illustrates my point would be:
-
-```bash
-myvar=($(echo A B C))
-myvar=1234
-echo $((myvar += 46)) ${myvar[${myvar:0:1}]}
-```
-
-It has 3 things which really bothered me:
-
-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.
-
- 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 [Command **Substitution**](https://www.gnu.org/software/bash/manual/html_node/Command-Substitution.html), the text gets executed and it's output **replaces** the `$(...)` itself (slightly reminiscent of [LISP macros](https://lispcookbook.github.io/cl-cookbook/macros.html)).
-
- Side note: obviously, the original expected behaviour can happen if we use some quotes:
-
- ```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.
- However it correctly returns the number 1 (and no, that isn't a default, the number is correctly parsed as a string).
-
- 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, [there isn't a type at all](https://tldp.org/LDP/abs/html/untyped.html)!
- Which makes everything even more weird, considering you *can* [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!
-
- 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?
-
- This is strange, but it cannot be the full picture, because [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 [square brackets](https://www.vidarholen.net/contents/blog/?p=25) and [most ok looking code](https://mywiki.wooledge.org/BashPitfalls).
-[Some people](https://chrisdone.com/posts/shell-conduit/) even go as far to say:
-
-> 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, [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.
-
-[^parameter-expansion]: Of course this is just one of the many ways to reference and work with variables.
diff --git a/src/blog/encrypted-email/index.du b/src/blog/encrypted-email/index.du
new file mode 100644
index 0000000..8102dcf
--- /dev/null
+++ b/src/blog/encrypted-email/index.du
@@ -0,0 +1,174 @@
+# Encrypted email
+
+'define expected-reading 10 min
+'define created 10 September 2022
+'define edited 16 September 2022
+[$pagenav]
+
+:contents
+:numbered
+1. [url #encryption-and-signature Encryption and signature]
+2. [url #openpgp OpenPGP]
+ .numbered
+ 1. [url #pgpinline PGP/Inline]
+ 2. [url #pgpmime 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]
+ .numbered
+ 1. [url #protonmail Protonmail]
+ 2. [url #tutanota Tutanota]
+
+7. [url #conclusion 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].
+
+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 /tutorials/how-to-encrypt-email tutorial on how to setup] [url #openpgp OpenPGP] or [url #smime S/MIME] 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.
+
+## 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].
+
+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:
+
+.numbered
+1. You encrypt =[your]= email with =[their public key]=
+2. The recipient decrypts =[your]= message with =[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]=.
+
+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:
+
+.numbered
+1. You sign =[your]= email with =[your private key]=
+2. Then the recipient verifies =[your]= message with =[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.
+
+## 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 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.
+
+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).
+
+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:
+
+.numbered
+1. You can't encrypt attachments, period.
+2. Your message can only be plain ASCII text characters. So any Unicode character (probably) won't work, and HTML messages are out of the question.
+
+Though, it's not all bad. If you can survive only sending text to other people, PGP/Inline might be a better option:
+
+.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]
+
+### 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:
+
+.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.
+
+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:
+
+.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
+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.
+
+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).
+
+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.
+
+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.
+
+Otherwise, it's email encryption capabilities are the same as those outlined in [url #pgpmime PGP/MIME].
+
+## 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.
+
+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.
+
+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.
+
+In it, they define the term "[url https://github.com/OpenTechFund/secure-email#post-email-alternatives post-mail]" 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].
+
+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].
+
+## 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:
+
+:quote
+:numbered
+1. Closed system: you can only send to other users on the same provider.
+2. Semi-closed system: you can communicate outside the system, but it is troublesome to do so.
+ .bulleted
+ - If you send an email to someone else using the same system, it is end-to-end encrypted.
+ - If you send an email outside the system, then the recipient gets a URL they can use to view the message. Often, the message is symmetrically encrypted using a shared secret.
+
+3. Semi-closed system, with no encryption: just like above, but emails outside the system have no encryption.
+
+
+
+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.
+
+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].
+
+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].
+
+### 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).
+
+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.
+
+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].
+
+## 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.
+
+[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/encrypted-email/index.md b/src/blog/encrypted-email/index.md
deleted file mode 100644
index ccd0868..0000000
--- a/src/blog/encrypted-email/index.md
+++ /dev/null
@@ -1,149 +0,0 @@
-# Encrypted email
-
-## Contents
-
-1. [Encryption and signature](#encryption-and-signature)
-2. [OpenPGP](#openpgp)
- 1. [PGP/Inline](#pgpinline)
- 2. [PGP/MIME](#pgpmime)
-3. [S/MIME](#smime)
-4. [reop](#reop)
-5. [Post-email systems](#post-email-systems)
-6. [Centralized non-email systems](#centralized-non-email-systems)
- 1. [Protonmail](#protonmail)
- 2. [Tutanota](#tutanota)
-7. [Conclusion](#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 [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) [tutorial on how to setup](/tutorials/how-to-encrypt-email) [OpenPGP](#openpgp) or [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.
-
-## Encryption and signature
-
-Unless stated otherwise, all of the listed encryption (and signature) schemes work by utilizing [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:
-
-1. You encrypt **your** email with **their public key**
-2. The recipient decrypts **your** message with **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**.
-
-Every email you send can be [digitally signed](https://en.wikipedia.org/wiki/Digital_signature) (not to be confused with [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:
-
-1. You sign **your** email with **your private key**
-2. Then the recipient verifies **your** message with **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 [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 [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 [web of trust](https://en.wikipedia.org/wiki/Web_of_trust), the idea being, different people sign each others public keys (sometimes at [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 [abolish it](https://restoreprivacy.com/let-pgp-die/) while other still [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 [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 [other limitations](https://josefsson.org/inline-openpgp-considered-harmful.html) too, to name a few:
-
-1. You can't encrypt attachments, period.
-2. Your message can only be plain ASCII text characters. So any Unicode character (probably) won't work, and HTML messages are out of the question.
-
-Though, it's not all bad. If you can survive only sending text to other people, PGP/Inline might be a better option:
-
-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 [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 [MIME](https://en.wikipedia.org/wiki/MIME) data with PGP, which by definition means it supports any content type. This includes:
-
-1. Support for Unicode characters and HTML messages
-2. Attachments of any type
-3. Delivery status report
-
-Basically, any [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 [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:
-
-1. As already mentioned, it is hard to implement and [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
-
-[S/MIME](https://en.wikipedia.org/wiki/S/MIME), roughly said, combines and extends the [Cryptograhic Message Syntax](https://en.wikipedia.org/wiki/Cryptographic_Message_Syntax) encryption scheme and [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 [Public key infrastructure](https://en.wikipedia.org/wiki/Public_key_infrastructure). This means that, rather than people exchanging certificates between themselves, a [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 [Google Workspace Enterprise Edition](https://support.google.com/a/answer/6374496?hl=en#zippy=) and [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) ([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 [paid clients](https://docs.microsoft.com/en-us/deployoffice/endofsupport/microsoft-365-services-connectivity)) is available.
-
-On the other hand, you can browse [Google's](https://support.google.com/a/answer/7448393?hl=en&ref_topic=9061730) and [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: [Actalis](https://www.actalis.com/s-mime-certificates.aspx). A good tutorial on the procedure can be found [here](https://www.dannyguo.com/blog/how-to-get-a-free-s-mime-certificate/), but beware, *they* generate the private key.
-
-Otherwise, it's email encryption capabilities are the same as those outlined in [PGP/MIME](#pgpmime).
-
-## reop
-
-[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 [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:
-
-> no support for key revocation, or long chains of certificates, or partial trust, or key servers
-
-However, as explained in it's [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 [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 [document](https://github.com/OpenTechFund/secure-email), created by the [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 "[post-mail](https://github.com/OpenTechFund/secure-email#post-email-alternatives)" as:
-
-> 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 [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 [goldbug](http://goldbug.sourceforge.net/) and [retroshare](https://retroshare.cc/). Until 2021, zeronet *was* updated, but the [author](https://github.com/shortcutme) seems to have [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 [this document](https://github.com/OpenTechFund/secure-email) from [OpenTechFunc](https://www.opentech.fund/). They define it as "centralized email-like messaging platform" and further divide it into:
-
-> 1. Closed system: you can only send to other users on the same provider.
-> 2. Semi-closed system: you can communicate outside the system, but it is troublesome to do so.
-> - If you send an email to someone else using the same system, it is end-to-end encrypted.
-> - If you send an email outside the system, then the recipient gets a URL they can use to view the message. Often, the message is symmetrically encrypted using a shared secret.
-> 3. Semi-closed system, with no encryption: just like above, but emails outside the system have no encryption.
-
-Out of the listed options, Enlocked doesn't work anymore and was [a bad system](https://adammonsen.com/post/853/) to begin with, ShazzleMail is pretty much [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 [proton.me](https://proton.me/) as they are called now, which uses good old [OpenPGP](#openpgp). That means they have end-to-end encryption and zero-access encryption by default for all protonmail accounts. They also [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 [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 [here](https://proton.me/pricing).
-
-### Tutanota
-
-[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) [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 [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.
-
-Finally, pricing. In general, they have a lot less features than [Protonmail](#protonmail), but their free tier is a lot more capable than [Protonmail](#protonmail)'s. Their pricing is extremely flexible, being able to buy specific features by themselves, like storage or mail aliases. Check it out [here](https://tutanota.com/pricing/).
-
-## Conclusion
-
-In brief, almost all email encryption systems use [public-key cryptography](#encryption-and-signature). The most popular of these systems for personal use is [OpenPGP](#openpgp), but in the business space, [S/MIME](#smime) is quite a bit more prominent. [reop](#reop) is a viable, but limited, very new and lightweight systems for encrypting your email messages.
-
-[Protonmail](#protonmail) is an email provider, which has [OpenPGP](#openpgp) built-in, enabling and supporting encryption by default, but their free tier leaves what to be desired. [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/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du
new file mode 100644
index 0000000..ca16262
--- /dev/null
+++ b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.du
@@ -0,0 +1,65 @@
+# Балове 2021
+
+'define expected-reading 3 min
+'define created 13 July 2023
+'define edited 14 July 2023
+[$pagenav]
+
+*[Тази страница е разширение на [url ./ "ФМИ и висшето образование в програмистката индустрия"].]*
+
+Благодарение на електронната система за кандидатстване, имам минимални балове на трите класирания през 2021 за компютърни науки, софтуерно инженерство и информатика (без информационни системи, защото не исках да влизам там).
+Понеже такава информация много не се разпространява, тук ще я споделя подробно.
+Очевидна бележка: това са баловете за мъже, за жени са различни.
+
+Също в бележките под линия на оригиналната статия съм дал стойности и източници за [url ./#fn4 бройка кандидати през 2021].
+
+Напомням, че 2021 беше последната година с два изпита по математика: Математика I и Математика II.
+Първият беше по-обикновен, със затворени и отворени въпроси, и задачи с решения.
+Вторият беше 8 задачи с решения.
+
+Балът се формираше така:
+.bulleted
+- 3 по оценката от Математика II *[или]* 2.5 по оценката от Математика I (което от двете носи по-голямо число)
+- +
+- ако си ходил на държавен зрелостен изпит по математика, оценката от него, *[иначе]* оценката по математика от дипломата
+
+За някакво усещане за баловете, ще напиша минималната нужна оценка от изпитите, считайки оценката от ДЗИ или дипломата за 6,00.
+Ако балът е под 13.5, то тогава със сигурност са приети студенти, които са имали по-малко от 6.00 на ДЗИ/диплома и са компенсирали с резултати на изпитите по математика (не може да кандидатстваш с оценка, по-ниска от 3.000).
+Тези балове са в наклонен шрифт.
+Тирета показват, че за даденото класиране не е имало свободни места (и дисциплината не е участвала).
+
+## Първо класиране
+
+.table
+|=Специалност - форма на обучение=||=Минимален бал=||=Мин. оценка по Математика I=||=Мин. оценка по Математика II=|
+|:Софтуерно инженерство - редовно:||:20.57:||:5.828:||:4.857:|
+|:Компютърни науки - редовно:||:19.45:||:5.380:||:4.483:|
+|:Информатика - редовно:||:14.88:||:3.552:||:3.000:|
+|::||::||::||::|
+|:Софтуерно инженерство - платено редовно:||:18.73:||:5.092:||:4.243:|
+|:Компютърни науки - платено редовно:||:17.63:||:4.652:||:3.877:|
+|:Информатика - платено редовно:||:*[11.62]*:||:3.000:||:3.000:|
+
+## Второ класиране
+
+.table
+|=Специалност - форма на обучение=||=Минимален бал=||=Мин. оценка по Математика I=||=Мин. оценка по Математика II=|
+|:Софтуерно инженерство - редовно:||:20.27:||:5.708:||:4.757:|
+|:Компютърни науки - редовно:||:18.79:||:5.116:||:4.263:|
+|:Информатика - редовно:||:*[10.64]*:||:3.000:||:3.000:|
+|::||::||::||::|
+|:Софтуерно инженерство - платено редовно:||:16.63:||:4.252:||:3.543:|
+|:Компютърни науки - платено редовно:||:14.81:||:3.524:||:3.000:|
+|:Информатика - платено редовно:||:-:||:-:||:-:|
+
+## Трето класиране
+
+.table
+|=Специалност - форма на обучение=||=Минимален бал=||=Мин. оценка по Математика I=||=Мин. оценка по Математика II=|
+|:Софтуерно инженерство - редовно:||:-:||:-:||:-:|
+|:Компютърни науки - редовно:||:19.22:||:5.288:||:4.406:|
+|:Информатика - редовно:||:*[12.00]*:||:3.000:||:3.000:|
+|::||::||::||::|
+|:Софтуерно инженерство - платено редовно:||:16.63:||:4.252:||:3.543:|
+|:Компютърни науки - платено редовно:||:17.15:||:4.460:||:3.717:|
+|:Информатика - платено редовно:||:-:||:-:||:-:|
diff --git a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.md b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.md
deleted file mode 100644
index 57546bc..0000000
--- a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/balove-2021.md
+++ /dev/null
@@ -1,60 +0,0 @@
-# Балове 2021
-
-*Тази страница е разширение на ["ФМИ и висшето образование в програмистката индустрия"](./).*
-
-Благодарение на електронната система за кандидатстване, имам минимални балове на трите класирания през 2021 за компютърни науки, софтуерно инженерство и информатика (без информационни системи, защото не исках да влизам там).
-Понеже такава информация много не се разпространява, тук ще я споделя подробно.
-Очевидна бележка: това са баловете за мъже, за жени са различни.
-
-Също в бележките под линия на оригиналната статия съм дал стойности и източници за [бройка кандидати през 2021](./#fn4).
-
-Напомням, че 2021 беше последната година с два изпита по математика: Математика I и Математика II.
-Първият беше по-обикновен, със затворени и отворени въпроси, и задачи с решения.
-Вторият беше 8 задачи с решения.
-
-Балът се формираше така:
-
-- 3 по оценката от Математика II *или* 2.5 по оценката от Математика I (което от двете носи по-голямо число)
-- +
-- ако си ходил на държавен зрелостен изпит по математика, оценката от него, *иначе* оценката по математика от дипломата
-
-За някакво усещане за баловете, ще напиша минималната нужна оценка от изпитите, считайки оценката от ДЗИ или дипломата за 6,00.
-Ако балът е под 13.5, то тогава със сигурност са приети студенти, които са имали по-малко от 6.00 на ДЗИ/диплома и са компенсирали с резултати на изпитите по математика (не може да кандидатстваш с оценка, по-ниска от 3.000).
-Тези балове са в наклонен шрифт.
-Тирета показват, че за даденото класиране не е имало свободни места (и дисциплината не е участвала).
-
-## Първо класиране
-
-|Специалност - форма на обучение|Минимален бал|Мин. оценка по Математика I|Мин. оценка по Математика II|
-|---|---|---|---|
-|Софтуерно инженерство - редовно|20.57|5.828|4.857|
-|Компютърни науки - редовно|19.45|5.380|4.483|
-|Информатика - редовно|14.88|3.552|3.000|
-|||||
-|Софтуерно инженерство - платено редовно|18.73|5.092|4.243|
-|Компютърни науки - платено редовно|17.63|4.652|3.877|
-|Информатика - платено редовно|*11.62*|3.000|3.000|
-
-## Второ класиране
-
-|Специалност - форма на обучение|Минимален бал|Мин. оценка по Математика I|Мин. оценка по Математика II|
-|---|---|---|---|
-|Софтуерно инженерство - редовно|20.27|5.708|4.757|
-|Компютърни науки - редовно|18.79|5.116|4.263|
-|Информатика - редовно|*10.64*|3.000|3.000|
-|||||
-|Софтуерно инженерство - платено редовно|16.63|4.252|3.543|
-|Компютърни науки - платено редовно|14.81|3.524|3.000|
-|Информатика - платено редовно|-|-|-|
-
-## Трето класиране
-
-|Специалност - форма на обучение|Минимален бал|Мин. оценка по Математика I|Мин. оценка по Математика II|
-|---|---|---|---|
-|Софтуерно инженерство - редовно|-|-|-|
-|Компютърни науки - редовно|19.22|5.288|4.406|
-|Информатика - редовно|*12.00*|3.000|3.000|
-|||||
-|Софтуерно инженерство - платено редовно|16.63|4.252|3.543|
-|Компютърни науки - платено редовно|17.15|4.460|3.717|
-|Информатика - платено редовно|-|-|-|
diff --git a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.md b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du
index 0861ff4..3b13c4c 100644
--- a/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.md
+++ b/src/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq/index.du
@@ -1,44 +1,63 @@
# ФМИ и висшето образование в програмистката индустрия
-## Contents
+'define expected-reading 39 min
+'define created 12 July 2023
+'define edited 14 July 2023
+[$pagenav]
+
+:contents
+:numbered
+1. [url #section-2 Кой съм аз]
+2. [url #section-3 Университетите в България (София)]
+ .numbered
+ 1. [url #section-4 УниБит]
+ 2. [url #section-5 НБУ]
+ 3. [url #section-6 Технически университет]
+
+4. [url #section-7 ФМИ]
+ :numbered
+ 1. [url #section-8 Специалности]
+ 2. [url #section-9 Влизане]
+ 3. [url #section-10 Следване и оцеляване]
+ .numbered
+ 1. [url #section-11 Оценяване, влачене и повтаряне]
+ 2. [url #section-12 Седмична заетост]
+ 3. [url #section-13 Преподаватели]
+ 4. [url #section-14 Избираеми дисциплини и работа]
+
+ 4. [url #-2 Какво се учи в КН2]
+ :numbered
+ 1. [url #section-15 Училищната математика\nсрещу университетската математика]
+ 2. [url #section-16 Първи курс: М-то във ФМИ означава МатеМатика]
+ .numbered
+ 1. [url #section-17 Зимен семестър]
+ 2. [url #section-18 Летен семестър]
+
+ 3. [url #section-19 Втори курс: И-то във ФМИ означава математИка]
+ .numbered
+ 1. [url #section-20 Зимен семестър]
+ 2. [url #section-21 Летен семестър]
+
+
+
+5. [url #section-22 Има ли смисъл от следване във фми? ДА!]
+
-1. [Кой съм аз](#section-1)
-2. [Университетите в България (София)](#section-2)
- 1. [УниБит](#section-3)
- 2. [НБУ](#section-4)
- 3. [Технически университет](#section-5)
-4. [ФМИ](#section-6)
- 1. [Специалности](#section-7)
- 2. [Влизане](#section-8)
- 3. [Следване и оцеляване](#section-9)
- 1. [Оценяване, влачене и повтаряне](#section-10)
- 2. [Седмична заетост](#section-11)
- 3. [Преподаватели](#section-12)
- 4. [Избираеми дисциплини и работа](#section-13)
- 4. [Какво се учи в КН2](#2)
- 1. [Училищната математика<br>срещу университетската математика](#section-14)
- 2. [Първи курс: М-то във ФМИ означава МатеМатика](#--)
- 1. [Зимен семестър](#section-15)
- 2. [Летен семестър](#section-16)
- 3. [Втори курс: И-то във ФМИ означава математИка](#--1)
- 1. [Зимен семестър](#section-17)
- 2. [Летен семестър](#section-18)
-5. [Има ли смисъл от следване във фми? ДА!](#section-19)
Всеки гимназиален ученик, който се насочва към програмиране, рано или късно започва да мисли за висшето си образование.
Мненията онлайн са разнообразни, някои твърдят че не е нужно, някои хвалят определени университети, други пък изрично ги отричат.
И цялата тази дискусия се намира в постове от преди 5-10 години...
Аз вече съм следвал 2 години в университет, плюс това имам сериозен опит от преди това.
-Макар и този блогпост да е главно за [Факултета по Математика и Информатика](https://www.fmi.uni-sofia.bg/) към [Софийски Университет](https://www.uni-sofia.bg/index.php), по-общата ми цел е да споделя всичко , което знам свързано с образованието в индустрията.
+Макар и този блогпост да е главно за [url https://www.fmi.uni-sofia.bg/ Факултета по Математика и Информатика] към [url https://www.uni-sofia.bg/index.php Софийски Университет], по-общата ми цел е да споделя всичко , което знам свързано с образованието в индустрията.
-Бърза бележка: всичко казано **важи за моя випуск**, с времето нещата се изменят и може повечето информация тук да бъде **остаряла**.
-Допълнително, [тук](./balove-2021.html) имам изкарани баловете във ФМИ (на СУ) за 2021 година.
+Бърза бележка: всичко казано =[важи за моя випуск]=, с времето нещата се изменят и може повечето информация тук да бъде =[остаряла]=.
+Допълнително, [url ./balove-2021.html тук] имам изкарани баловете във ФМИ (на СУ) за 2021 година.
## Кой съм аз
Този блогпост няма да бъде напълно неутрален и ще включва моето мнение, затова е добре да знаеш от къде идва моята гледна точка.
-Завършил съм [9 Френска езикова гимназия](https://www.feg.bg/), обаче едновременно от 10 до 12 клас участвах интензивно в националната програма [ИТ-кариера](https://it-kariera.mon.bg/e-learning/).
+Завършил съм [url https://www.feg.bg/ 9 Френска езикова гимназия], обаче едновременно от 10 до 12 клас участвах интензивно в националната програма [url https://it-kariera.mon.bg/e-learning/ ИТ-кариера].
Накратко, в тази програма изучавах практически неща, главните няколко типове програмирания, и към края се занимавах с разработване на софтуер на сравнително индустриално ниво (или поне най-близкото до това).
От цялата програма бях единствения от център София с пълно отличие.
@@ -54,7 +73,7 @@
## Университетите в България (София)
Сега ще обсъдим какви са алтернативите на ФМИ, и защо те не са толкова добри.
-В София има четири (смислени) университета, които предлагат някаква форма на софтуерно образование: [Софийски университет](https://www.uni-sofia.bg/), [Нов Български Университет](https://nbu.bg/), [Техническия Университет](https://www.tu-sofia.bg/) и [Университет по Библеотекознание и Информационни технологии](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/ Университет по Библеотекознание и Информационни технологии].
Този пост ще бъде посветен на първата от тези опции, но все пак покрай приятели и колеги имам добра представа за другите опции.
### УниБит
@@ -84,15 +103,17 @@
### Технически университет
-Не съм чувал много, но техническият университет се занимава повече с инженерство, така че [се учат не толкова свързани предмети](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), като физика, проектиране и електротехника.
-[Доколкото виждам онлайн, мненията не са позитивни](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/ Доколкото виждам онлайн, мненията не са позитивни]:
-> За IT ТУ е абсолютна загуба на време - редовно ми идват стажанти от там. Ако не са се занимавали с програмиране от преди това, почваме от 0
+.quote
+За IT ТУ е абсолютна загуба на време - редовно ми идват стажанти от там. Ако не са се занимавали с програмиране от преди това, почваме от 0
-<br>
+\n
-> Завършил съм компютърни системи и технологии на немски в ТУ. Знам за какво иде реч и в българските факултети.
-> След като разбрах какво се изучава във ФМИ ме хвана яд, че не се бях записал там.
+.quote
+Завършил съм компютърни системи и технологии на немски в ТУ. Знам за какво иде реч и в българските факултети.
+След като разбрах какво се изучава във ФМИ ме хвана яд, че не се бях записал там.
Също когато кандидатствах се разпространяваше видео за някаква преподавателка как по новините разказва колко е добре в ТУ, и директно след това имаше запис как изпада в истерия покрай нещо сравнително дребно.
@@ -105,10 +126,10 @@
Във ФМИ много от предметите са математики и програмиранията се говори, че не са много добре.
Онлайн има стотици часове материали и курсове, повечето от които са безплатни, на всяка тема свързана с програмиране.
-Допълнително имаш [Telerik Academy](https://www.telerikacademy.com/) и [SoftUni](https://softuni.bg/) (само искам да напомня, че **СофтУни не е университет**, макар и така да се казват) - две места които предлагат разнообразни програмистки и чисто практически курсове (и също дават сертификати).
+Допълнително имаш [url https://www.telerikacademy.com/ Telerik Academy] и [url https://softuni.bg/ SoftUni] (само искам да напомня, че =[СофтУни не е университет]=, макар и така да се казват) - две места които предлагат разнообразни програмистки и чисто практически курсове (и също дават сертификати).
А и повечето програмисти нямат висше и са самоуки, тоест този път не е изобщо странен, даже е най-често следвания.
-Финалното ми мнение се намира [най-долу](#section-19), но един такова решение трябва да се вземе с възможно най-много информация.
+Финалното ми мнение се намира [url #section-19 най-долу], но един такова решение трябва да се вземе с възможно най-много информация.
### Специалности
@@ -116,16 +137,18 @@
Технически всяка се занимава с различни неща, но на практика всички влезли искат да са програмисти.
От тях, най-желани са компютърни науки и софтуерно инженерство (тези ще наричам "хубавите" специалности).
-В информатика се влизаше много лесно, там балът беше [безнадеждно нисък](./balove-2021.html), обаче следването е най-трудно от всички останали дисциплини.
-Късането е брутално, особено първи курс: по Алгебра 1 от към 200 човека (това включваше и минали години май) само един човек беше *допуснат* до изпит (ама си го мина де).
+В информатика се влизаше много лесно, там балът беше [url ./balove-2021.html безнадеждно нисък], обаче следването е най-трудно от всички останали дисциплини.
+Късането е брутално, особено първи курс: по Алгебра 1 от към 200 човека (това включваше и минали години май) само един човек беше *[допуснат]* до изпит (ама си го мина де).
По дискретни структури бяха повече, цели 10тима човека.
-Общо от 1ви курс преминаха успешно 20-30 човека във 2ри курс (за да минеш не е нужно всички изпити да си минал, ама детайли [по-късно](#section-10)).
+Общо от 1ви курс преминаха успешно 20-30 човека във 2ри курс (за да минеш не е нужно всички изпити да си минал, ама детайли [url #section-10 по-късно]).
Има няколко причини за това:
-
+.bulleted
- от една страна бала като е най-нисък, хората с най-ниски умения по математика се намират там, така че успехите ще са най-ниски,
- от друга страна има и преподаватели които са прекомерно неадекватни като изпитване и преподаване.
-Информационни системи от своя страна сякаш се занимава повече с бази данни и проектиране на информационни системи[^inf-sistemi], не толкова чисто програмиране и нещата около него.
+'footnote inf-sistemi Признавам, за тази информация използвах [url https://forums.bgdev.org/index.php?showtopic=34217&st=0&#entry255351 това мнение от форум], никой не обсъжда ИС.
+
+Информационни системи от своя страна сякаш се занимава повече с бази данни и проектиране на информационни системи[$inf-sistemi], не толкова чисто програмиране и нещата около него.
Признавам, че не съм чувал много за тях, ама балът не изглежда да е много висок (мисля че е по-висок от информатика) и мисля, че следването е най-лесно от 4те специалности.
Сега, компютърни науки и софтуерно инженерство.
@@ -141,29 +164,33 @@
Само по Алгебра 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%[$minali-1-kurs] от редовните студенти (които не повтарят) успешно минаха (минахме ;)) към втори курс.
Иначе имам впечатлението, че най-умните и умелите хора измежду компютърни науки и софтуерно инженерство се намират тук, макар че това зависи от випуска: няма гаранция, че един много умен кандидат-студент ще реши да се запише за КН (и ще попадне в КН2).
Като обобщение, това са дисциплините подредени от най-трудна за минаване към най-лесна:
-1. **Информатика**: много трудно, не по много основателни причини, макар че като цяло малцинството което успява да завърши са на високо ниво.
+:ordered
+1. =[Информатика]=: много трудно, не по много основателни причини, макар че като цяло малцинството което успява да завърши са на високо ниво.
Не препоръчвам, ако не си много издържлив и КН и СИ не са се получили.
-2. **Компютърни науки, 2ри поток**: трудно, но като цяло е сравнително основателно (пак на моменти е малко нечестно, но не толкова колкото при информатика), нивото просто е високо.
+2. =[Компютърни науки, 2ри поток]=: трудно, но като цяло е сравнително основателно (пак на моменти е малко нечестно, но не толкова колкото при информатика), нивото просто е високо.
Поне от моя випуск, повечето от най-добрите се намират тук.
Ако си представим, че има някакво перфектно ниво на обучение, където не е твърде лесно, но и не е твърде трудно, бих казал че КН2 се намира малко над това ниво.
-3. **Компютърни науки, 1ви поток**: малко по-лесно от КН2, но с малко понижаване на качеството.
+3. =[Компютърни науки, 1ви поток]=: малко по-лесно от КН2, но с малко понижаване на качеството.
Има добро количество материал, което в КН2 ти е набито в главата, докато при КН1 си го забравил след лятната ваканция (не че това не важи в обратната посока, но в КН2 ни вкарват повече неща в умовете).
В сравнение с перфектното ниво, КН1 е малко под него.
Обаче трябва да се има в предвид, че 2ри курс сложиха доста взискателни преподаватели.
Ако това се запази, разликата между двата потока може да изчезне.
-4. **Софтуерно инженерство**: забележимо по-лесно от компютърни науки, повечето хора по повечето дисциплини минават без твърде много проблеми.
+4. =[Софтуерно инженерство]=: забележимо по-лесно от компютърни науки, повечето хора по повечето дисциплини минават без твърде много проблеми.
Ама нивото също спада забележително, макар и бала да е най-висок.
Както споменах, при компютърни науки е по-добре, ама нивото на СИ пак е сравнително ок.
-5. **Информационни системи**: нисичък бал и сравнително лесно, но не ми изглежда да е супер развиващо за програмисти.
+5. =[Информационни системи]=: нисичък бал и сравнително лесно, но не ми изглежда да е супер развиващо за програмисти.
Не бих препоръчал, освен ако алтернативата не е информатика.
+
Трябва да напомня, че под лесно имам предвид, че се налага полу-редовно учене, не е като лесно в НБУ, където мързелуваш цял семестър, правиш един калпав проект за седмица и минаваш.
Също по някои предмети преподавателите са едни и същи всяка година, по други не, тоест колко са сложни дадени предмети и специалности зависи от годината.
@@ -173,23 +200,35 @@
Сега главният определящ изпит е просто "Математика" и включва сложни въпроси като "кое от следните числа е най-голямо" и "намерете броя решения на уравнението".
Разбира се, с това си идват свои трудности, и най-малката грешка може да постави 10-20 човека над тебе като успех, но в края на деня не се изисква толкова много тренинг както при моите изпити.
-Моята генерация беше последната по старата програма на обучение[^mat-i-ii], така че при кандидатстване се вземаше една от оценките на изпитите Математика I или Математика II (като втория изпит допринася повече към бала).
+'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 (като втория изпит допринася повече към бала).
Математика I беше сравнително стандартен, напомнящ на модерната "Математика" или матурата, обаче Математика II беше съвсем друго животно: там имаш 8 задачи, всяка с отворен отговор и изисквано решение.
-Този изпит беше трудният и до голяма степен определящият, от максимум 593[^2021-kandidati] човека се рееха слухове че само 20тина са имали 6,00.
+Този изпит беше трудният и до голяма степен определящият, от максимум 593[$2021-kandidati] човека се рееха слухове че само 20тина са имали 6,00.
-Въпреки това, влизането във ФМИ беше лесно, общо имаше 525[^2021-mesta] места, предостатъчно, имайки предвид, че не всички явили се на тези изпити, кандидатстваха в компютърна специалност (оценката важи за физическия и стопанския факултет).
+'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, поне за специалности като компютърни науки и софтуерно инженерство. Сякаш малко след това баловете на всичко започват яко да падат, ама такива статистики вече хептен ги няма публично. Единствената така информация имат кандидат-студенти, и то за своята година в която влизат, и не се познавам с достатъчно хора, за да разпитвам.
+
+Въпреки това, влизането във ФМИ беше лесно, общо имаше 525[$2021-mesta] места, предостатъчно, имайки предвид, че не всички явили се на тези изпити, кандидатстваха в компютърна специалност (оценката важи за физическия и стопанския факултет).
Вече за конкретни специалности беше малко по-трудно, 300 от тези места бяха в хубавите компютърни специалности, така че конкуренцията беше горе-долу двама човека за едно място.
Също е добре да спомена, че баловете бяха супер ниски, в компютърни науки влязох с 4.70 (на Математика II) на първо класиране, на второ можеше и с 4.30 да вляза.
-Конкретни стойности за баловете от тази година съм изкарал [тук](./balove-2021.html).
-В Софтуерно инженерство бяха малко по-високи изискванията (а там бяха най-високи от компютърните специалности), ама пак, далеч от времето, когато с 5.40 е можело и да не влезеш[^visoki-iziskvaniq].
+Конкретни стойности за баловете от тази година съм изкарал [url ./balove-2021.html тук].
+В Софтуерно инженерство бяха малко по-високи изискванията (а там бяха най-високи от компютърните специалности), ама пак, далеч от времето, когато с 5.40 е можело и да не влезеш[$visoki-iziskvaniq].
+
+'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]).
-С новия изпит вече конкуренцията е малко по-висока, все пак са се явили 969[^2022-kandidati] ученици на Математика през 2022 и максимум 979[^2023-kandidati] през 2023.
+'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.
Местата са същия брой, така че излиза към примерно трима човека за едно място и ако примерно имаш 3ка или 4ка може и да не влезеш във ФМИ.
-Обаче, **най-важното: материалът във ФМИ не се е изменил!**
+Обаче, =[най-важното: материалът във ФМИ не се е изменил!]=
Макар и изпитът да е значително по-лесен, трудността на материала не се е снижила (или поне толкова, колкото изпита) и в същото време математиката се изучава доста.
Тоест, един човек, влязъл с най-ниския бал на Математика ще е далеч по-неподготвен за ФМИ от човек с минимален бал на Математика II.
-Затова **препоръчвам всеки кандидат-студент да може да реши някоя Математика II за към 4-4.50!**
+Затова =[препоръчвам всеки кандидат-студент да може да реши някоя Математика II за към 4-4.50!]=
Това са горе-долу 5-6 от 8те задачи.
Иначе ако не можеш редовно да учиш математика и не можеш да се справиш с такива задачи (които са по-прости като характер в сравнение с това, което учим в университета), следването ти ще бъде твърде трудно според мен.
@@ -214,10 +253,12 @@
Оценката се формира по различни начини при различните предмети, но най-често контролните и домашните през семестъра носят 40-50% и през сесията си изкарваш останалата част от оценката.
Също понякога, ако си се справил достатъчно добре на контролните през семестъра, може да бъдеш освободен от изпит-задачи (не е нужно да ходиш и като оценка на него ти се пише средно аритметично от контролните).
-Обаче почти винаги **ако изкараш двойка на някой от изпитите през сесията, цялата ти оценка за предмета става двойка!**
+Обаче почти винаги =[ако изкараш двойка на някой от изпитите през сесията, цялата ти оценка за предмета става двойка!]=
+
+'footnote september Разговорно на поправителната сесия им викаме септември, макар и само един-два дена от нея да са в този месец. Причината е, че просто до преди няколко години наистина е била през септември, но са я изместили назад. Защо са я изместили, не знам.
Когато не си минал един предмет, ти го "влачиш".
-За всеки предмет имаш две дати през академичната година, през които може да го вземеш: редовната сесията след семестър (тоест когато по принцип се изпитват хора по този предмет) и поправителната сесия, която се случва във втората половина от август[^september].
+За всеки предмет имаш две дати през академичната година, през които може да го вземеш: редовната сесията след семестър (тоест когато по принцип се изпитват хора по този предмет) и поправителната сесия, която се случва във втората половина от август[$september].
По принцип имаш и ликвидационна сесия, ама идеята е, ако два изпита през поправителната сесия ти се препокриват, през поправителната да отидеш на единия и на ликвидационната да може да отидеш на другия (трябва да подадеш документ, че това си направил, не можеш да отложиш изпити ей така).
Можеш да преминеш към следващия курс без проблеми ако влачиш максимум 3 предмета от годината.
@@ -241,7 +282,7 @@
Количеството подготовка за едно контролно зависи от човек на човек, но ако нищо не си учил, бих казал че е поне една-две интензивни седмици за сериозните предмети са достатъчни.
За домашните е по-малко, защото по принцип те са върху неща, изучавани на упражнения, така че ако си си водел записки (или споделящи колеги са водели) ще знаеш как да решиш всички задачи (разбира се, има изключения).
-Това обаче е **само за контролни-задачи по някои предмети**, все пак имаш теория и имаш задачи за които ти трябва теория, и тя вече не може да се научи толкова бързо.
+Това обаче е =[само за контролни-задачи по някои предмети]=, все пак имаш теория и имаш задачи за които ти трябва теория, и тя вече не може да се научи толкова бързо.
Нещо много хубаво е, че никой не следи за присъствие на занятия и не се пишат отсъствия както в училище.
Разбира се, това не означава, че не е нужно да се ходи на всички занятия, напротив, но ако искаш винаги може да пропуснеш нещо.
@@ -264,16 +305,16 @@
Обаче, си задължен и да ходиш на избираеми дисциплини: имаш минимален брой избираеми за всеки семестър, минимален общ брой за всичките години и минимален брой ECTS кредити за всичките години.
За разлика от училище, имаш доста голям избор и много от тях са интересни и полезни.
-Обаче, **не записвай избираеми през първи курс!**
-Скоро ще обсъдим предметите, обаче **първи курс е най-труден и изисква цялото ти работно време!**
-Това трябва да навежда на мисълта, че **не трябва да работиш по време на първи курс**, освен ако не ти се налага или не си от най-умните хора в специалността.
+Обаче, =[не записвай избираеми през първи курс!]=
+Скоро ще обсъдим предметите, обаче =[първи курс е най-труден и изисква цялото ти работно време!]=
+Това трябва да навежда на мисълта, че =[не трябва да работиш по време на първи курс]=, освен ако не ти се налага или не си от най-умните хора в специалността.
Материалът е нещо напълно ново, не само като изучавани неща, ами и като концепции и модел на учене.
-Ама каквото и да си говорим, **най-доброто обучение се намира в избираемите дисциплини!**
+Ама каквото и да си говорим, =[най-доброто обучение се намира в избираемите дисциплини!]=
Не е задължително да си доцент или професор, за да направиш избираема, и може да я направиш както си искаш.
Има много такива, които се водят от бивши студенти на ФМИ, които сега работят в големи компании, и предоставят супер практично и готино обучение.
-За някои неща даже не можеш да намериш в България курсове, като [Реализация на езици за програмиране](https://intranet.fmi.uni-sofia.bg/index.php/s/uGI4XDReO3WoUok), където се разглежда как се правят компилатори или [Употреба и скриптиране на Vim](https://intranet.fmi.uni-sofia.bg/index.php/s/v2v4WlP2GdDbWtb), където подробно поглежда един от най-добрите текстови редактори някога създавани.
+За някои неща даже не можеш да намериш в България курсове, като [url https://intranet.fmi.uni-sofia.bg/index.php/s/uGI4XDReO3WoUok Реализация на езици за програмиране], където се разглежда как се правят компилатори или [url https://intranet.fmi.uni-sofia.bg/index.php/s/v2v4WlP2GdDbWtb Употреба и скриптиране на Vim], където подробно поглежда един от най-добрите текстови редактори някога създавани.
### Какво се учи в КН2
@@ -295,13 +336,17 @@
Твърденията са неща, които казваме че са верни за дадена конструкция, тоест за нещо, което си измислим (и което не противоречи на аксиомите).
Конструкция е ключова дума, понеже сътворяваме с въображение някакъв обект, нещо с някакви свойства и после доказваме, чисто формално и прецизно със стриктно определени уреди, че дадения обект прави това, което искаме.
+'footnote def-set Формално няма дефиниция на множество, понеже става малко бездънно: какво е множество, еми колекция от елементи, какво е колекция от елементи, еми съвкупност от елементи, какво е съвкупност, еми множество от елементи. Формално казваме, че множество е първично понятие, тоест че няма дефиниция и се надяваме, че читателя схваща за какво се говори.
+
+'footnote axiom-of-choice В интерес на истината, това със сигурност е вярно само когато приемаме [url https://en.wikipedia.org/wiki/Axiom_of_choice аксиомата за избора], ако не я приемем, тогава доооста неща стават супер неинтуитивни и изглеждат грешни, обаче чисто формално и математически са верни.
+
Трудно ми е да дам лесен пример, понеже нищо в училище не може и да се сравнява, но нека да пробваме следното: нека да разгледаме множества.
-Множество е просто някаква колекция от елементи[^def-set], представи си кутия с някакви предмети в нея.
+Множество е просто някаква колекция от елементи[$def-set], представи си кутия с някакви предмети в нея.
Аз твърдя, че едно празно множество е елемент на друго празно множество, тоест че една празната кутия се съдържа в друга празна кутия.
-Това е очевидно грешно[^axiom-of-choice], нашето доказателство е, че щом кутията е празна, то по дефиниция няма елементи, следователно няма как да има друга кутия в нея.
+Това е очевидно грешно[$axiom-of-choice], нашето доказателство е, че щом кутията е празна, то по дефиниция няма елементи, следователно няма как да има друга кутия в нея.
Ето: конструкция, твърдение и доказателство, доста елементарно и очевидно, но все пак се опитвам да не навлизам в детайли, а и в математиката има такива резултати, които не са хич очевидни.
-Също, доказателството, че нещо не е вярно може би изглежда безполезно, но някои от [най-големите теореми на математиката са формулиране така](https://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem).
+Също, доказателството, че нещо не е вярно може би изглежда безполезно, но някои от [url https://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem най-големите теореми на математиката са формулиране така].
Сега вече ще обсъдим конкретно изучаваните предмети в детайл.
@@ -312,7 +357,7 @@
##### Зимен семестър
-**Алгебра 1**: пълното име е линейна алгебра.
+=[Алгебра 1]=: пълното име е линейна алгебра.
Занимава се главно с линейни уравнения (ax + by + ... + mz = k), обаче интересното идва като изследваме операции върху тях и ги навържем в пространства.
Много фундаментален предмет, използват се поне части от него в много клони на математиката и инженерството (защото много неща могат да се моделират с нея).
Има употреби в machine learning, в компютърната графика, в алгоритми за препоръки (търсачки примерно), обработка на изображения и много други.
@@ -320,7 +365,7 @@
Има по една малка задача всяка седмица, но не са трудни, изисква постоянство.
Предметът се минава без твърде много трудности, лекционните записки са много прецизно написани и упражненията са супер.
-**Диференциално и интегрално смятане 1**: с други думи, реален анализ.
+=[Диференциално и интегрално смятане 1]=: с други думи, реален анализ.
Главно разглеждаме свойства и операции върху функции и редици числа.
В училище учим производни; глаголът да правиш производни разговорно може да се нарече "производиране", обаче терминът е диференциране.
Интегрирането е обраното действие на диференцирането, тоест намирането на функция, имайки само нейната производна.
@@ -331,11 +376,12 @@
Главната цедка е теорията, на която имаш теоретични задачи, при които дори за 3ка ще трябва да приложиш малко усет към предмета.
Като цяло просто изискванията са високи, иначе екипа са готини и бих казал, че оценяването е честно.
-**Дискретни структури**: този предмет е малко смесица от три предмета - булева алгебра, увод в теория на множествата, комбинаторика и теория на графите.
+=[Дискретни структури]=: този предмет е малко смесица от три предмета - булева алгебра, увод в теория на множествата, комбинаторика и теория на графите.
От всичките математики, това е може би най-важната за програмиране.
В определен смисъл на думата, ДИС се занимава с безкрайно много и безкрайно малки елементи: на една функция може да и подадеш числото 1, но и 1.1, и 1.11 и так. нат., без проблем.
Обаче ДСТР разглежда дискретни обекти, тоест някакъв краен брой конкретни неща.
+.unordered
- Булевата алгебра е малка, тя много се ползва в булеви изрази при условия в код.
Формално дефинираме логически изрази и разглеждаме техни свойства.
- Класифицирал съм теория на множествата като увод, защото истинският предмет става много странен (има си избираема за това), но се занимава точно с обекта за който говорехме по-рано: множества.
@@ -351,7 +397,7 @@
Ама трябва да предупредя, че не получаваш точки за половинчати решения, като цяло или си решил задачата коректно или не.
Бих казал че при този предмет се появяват нечестности или прекомерно високи изисквания на моменти, но се минава.
-**Увод в програмирането**, неговото значение трябва да е очевидно.
+=[Увод в програмирането]=, неговото значение трябва да е очевидно.
Изучава се C++, макар и някои неща да не са направени по най-добрите начини.
Налага се да знаеш и ползваш точно нещата, които ти се преподават и нищо друго.
Не бих казал, че е лошо направен, има някакво основание за тази методика, обаче някои неща се разглеждат твърде формално и програмирането не се изучава като динамичен предмет, в който може да решиш проблеми по много начини, а като задача по математика, където се изисква определено решение.
@@ -364,9 +410,9 @@
##### Летен семестър
-**Диференциално и интегрално смятане 2**: директно продължение на ДИС1.
+=[Диференциално и интегрално смятане 2]=: директно продължение на ДИС1.
-**Геометрия**: истинското име на този предмет е аналитична геометрия и няма нищо общо с училищната евклидова геометрия.
+=[Геометрия]=: истинското име на този предмет е аналитична геометрия и няма нищо общо с училищната евклидова геометрия.
Разглеждаме пространствата и геометричните обекти като по-абстрактни неща, или по-конкретно, разглеждаме повече числата и зависимостите между конкретни обекти.
Централно в компютърната графика и всичко около нея (обработка на изображения, 3D моделиране, ...).
@@ -374,18 +420,18 @@
Упражненията са супер, има и много добри записки по тях.
Минава се без твърде много проблеми.
-**Езици, автомати и изчислимост**: вторият най-важен предмет от математиките, на английски се казва Theoretical Computer Science.
+=[Езици, автомати и изчислимост]=: вторият най-важен предмет от математиките, на английски се казва Theoretical Computer Science.
Занимава се с различни теоретични обекти, които могат да правят изчисления върху текстови низове.
Всичко свързано с анализ или шаблони върху текст използва нещата тук, а пък и отвъд.
Ако някога си чувал за машина на Тюринг, Тюринг-завършеност на програмни езици или проблемът за спирането, от тука идват.
Благодарение на тази наука е възможно да имплементираш компилатори на програмни езици и да правиш всички форми на разбор на текст (като обработката на уебстраници и интернет пакети).
-Записките са много добри, даже публично се намират, заедно с минали изпитни теми, [тук](http://logic.fmi.uni-sofia.bg/eai.html).
+Записките са много добри, даже публично се намират, заедно с минали изпитни теми, [url http://logic.fmi.uni-sofia.bg/eai.html тук].
И както по дискретни структури, асистентите не са консистентни и нивото малко криви.
Ама в края на деня преподавателите са готини и не искат да прецакват хора, така че се минава спокойно.
-**Обектно ориентирано програмиране**: това е най-популярният начин/парадигма за програмиране.
-Обект е групиране на данни с функциите върху тях, като са изпълнени [няколко свойства](https://en.wikipedia.org/wiki/Object-oriented_design#Object-oriented_concepts).
+=[Обектно ориентирано програмиране]=: това е най-популярният начин/парадигма за програмиране.
+Обект е групиране на данни с функциите върху тях, като са изпълнени [url https://en.wikipedia.org/wiki/Object-oriented_design#Object-oriented_concepts няколко свойства].
Кажи-речи всяка компания и всеки модерен програмен език, който се използва в индустрията, поддържа ООП.
Екипът е същия като при УП, така че общото ми мнение е същото, макар че при ООП ситуацията е може би една идея по-релаксирана.
@@ -398,7 +444,7 @@
##### Зимен семестър
-**Компютърни архитектури**: описание на хардуера.
+=[Компютърни архитектури]=: описание на хардуера.
Малко се доближава и до електротехниката, но се разглеждат много фундаменталните хардуерни компоненти и техните функционалности в един компютър.
Разглеждаме основните компонентни схеми за изчисления и хардуерно как се ползват и работят нещата.
Не е кой знае колко полезен за средния програмист, освен ако не се занимаваш със системно програмиране, ама е много важен фундамент.
@@ -407,22 +453,22 @@
Това е първият предмет при който няма задължителни упражнения, но никой не препоръчва да се ходи на избираемия практикум, понеже не е координиран много добре с лекциите и някои неща стават твърде трудни.
Иначе минаването е лесно.
-**Основи на компютърната графика**: има ли изобщо какво да обяснявам.
+=[Основи на компютърната графика]=: има ли изобщо какво да обяснявам.
Разглеждаме част от математиката, но повече се занимаваме с 3D моделиране и идеите на сложните неща, не толкова тяхното имплементиране.
Минаването е лесно, трябва да си малко консистентен със седмичните задачи обаче.
И този лектор ми е един от любимите.
Презентациите в които се намира материала са перфектно направени и упражненията са много приятни.
-Ето [тук](https://boytchev.github.io/scorm/) има редици малки задачки/игри с които можеше да изкараш малък бонус към оценката.
+Ето [url https://boytchev.github.io/scorm/ тук] има редици малки задачки/игри с които можеше да изкараш малък бонус към оценката.
-**Структури от данни и програмиране**: нещо като въведение в дизайн и анализ на алгоритмите.
+=[Структури от данни и програмиране]=: нещо като въведение в дизайн и анализ на алгоритмите.
Занимаваме се с някои много важни структури от данни, като стек и опашка, и разглеждаме алгоритми върху тях.
Супер важно за всеки програмист.
Екипът пак е същия, както при УП и ООП, така че мнението ми продължава, но тук поне изискванията за писане на код са по-основателни.
Все пак разглеждаме конкретни структури от данни и алгоритми, ако не ги ползваш в решенията на задачи, малко би се обезсмислила цялата история.
-**Функционално програмиране**: втората най-използвана парадигма след ООП.
+=[Функционално програмиране]=: втората най-използвана парадигма след ООП.
Идеята е, че разглеждаме всичко като функции, във всеки момент една функция връща нещо или приема нещо и никъде не пазим състояния.
Тоест, една стойност се намира или като аргумент или като върната стойност.
Също супер важно да се знае и може.
@@ -432,18 +478,18 @@
##### Летен семестър
-**Алгебра 2**: дефакто разглеждаме теория на групите, което на английски съм го виждал и като "Modern algebra".
+=[Алгебра 2]=: дефакто разглеждаме теория на групите, което на английски съм го виждал и като "Modern algebra".
Група е някакво множество от елементи и операция върху тях, като за операцията са изпълнени няколко свойства.
Допълнително имаме и пръстен, където вече имаш множество и две операции върху тях.
-Може би звучи странно, но е една от [най-интересните и шантави математики](https://www.youtube.com/watch?v=mH0oCDa74tE).
+Може би звучи странно, но е една от [url https://www.youtube.com/watch?v=mH0oCDa74tE най-интересните и шантави математики].
Криптографията се основава на нея и има употреби в теория на графите.
Екипът същия като при Алгебра 1, така че нямам оплаквания.
Макар че този път няма седмични задачи - ура!
-**Дизайн и анализ на алгоритми**: също едно име, което обяснява себе си.
+=[Дизайн и анализ на алгоритми]=: също едно име, което обяснява себе си.
Разглеждаме методиките за сравняване на алгоритми (асимптотика) и как да докажем тяхната коректност.
-Също разглеждаме доста основни и често използвани алгоритми, както и се допираме до [NP сложност](https://en.wikipedia.org/wiki/NP_%28complexity%29).
+Също разглеждаме доста основни и често използвани алгоритми, както и се допираме до [url https://en.wikipedia.org/wiki/NP_%28complexity%29 NP сложност].
Още един много важен предмет.
Тук сякаш асистентите преподават по-добре и нивото е по-изравнено.
@@ -451,7 +497,7 @@
Обаче смятам, че на доста моменти навлиза твърде много в математиката и теорията, и има същите проблеми с оценяването както по ДСТР.
Цели 15 човека минаха от първия път, така че нивото е горе-долу същото.
-**Изследване на операциите**: решава оптимизационни задачи, тоест задачи при които искаш минимум или максимум, като за всяка променлива имаш някакво ограничение (на английски се казва Linear Programming, но няма нищо общо с програмиране).
+=[Изследване на операциите]=: решава оптимизационни задачи, тоест задачи при които искаш минимум или максимум, като за всяка променлива имаш някакво ограничение (на английски се казва Linear Programming, но няма нищо общо с програмиране).
Една оптимизационна задача е примерно ако имаме фабрики за автомобили, всяка произвеждаща различно количество коли и складове в други градове, с различни капацитети, и имаме цената на пътя между градовете и складовете, как най-евтно ще пренесем всички автомобили в складовете.
Има употреба ако се опитваш да решиш такъв тип задачи, но ми се струва от по-безполезните неща за един програмист.
@@ -459,7 +505,7 @@
Лекторът е готин.
Минаването е лесно, нещата не са супер трудни.
-**Компютърни мрежи**: пак име, което само се обяснява.
+=[Компютърни мрежи]=: пак име, което само се обяснява.
Абсолютно всичко свързано с интернет и мрежите, от протоколи до методи за маршрутизация.
Като КАРХ не е от най-полезните за ежедневието, но е много важен фундамент.
@@ -467,7 +513,7 @@
Както и по други предмети, лектора не иска да ни прецаква, затова минаването не е проблем.
Даже бих казал, че е твърде лесно.
-**Операционни системи**: може би най-важният не-математически предмет, ако беше направен свестно.
+=[Операционни системи]=: може би най-важният не-математически предмет, ако беше направен свестно.
Имам много силно мнение за него, като цяло предмета се свежда до 70% менижиране на процеси, 20% менижиране на памет и 10% случайни неща.
Имаше потенциалът да е от най-добрите предмети в целия бакалавър, ама програмата и изпитването беше наистина зле направено.
@@ -481,27 +527,16 @@
Не бих казал, че се учат стари неща, които не са актуални, но за най-новите технологии трябва да се обърнеш към избираеми.
Обучението е далеч от перфектно, обаче каквото и да си говорим, обучението никъде не е перфектно.
-Бих казал, че качеството на курсове също [може да бъде много по-ниско](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/ може да бъде много по-ниско].
Това е много голяма тема, обаче въпреки че не учим най-новите и използваемите неща, основите с които излизаш ти позволяват да научиш новите технологии значително по-бързо и в значително по-голяма дълбочина.
Колкото и да не се харесва, математиката е в основата на всички кътчета от компютрите.
Разбира се, има пре-достатъчно работа, която не изисква и елементарно събиране да знаеш, но ако се стремиш нагоре, математиката е нужна.
Ама, преподаването не е единствената причина защо бих препоръчал ФМИ:
+.ordered
1. Колегите, които влизат са много готини и ако се постараеш ще се запознаеш с много добри приятели
2. Студентстването като изживяване е веднъж в живота, все пак характерът става по-издържлив когато те скъсат по няколко изпита, за които си учил много.
3. Каквото и да си говорим, ФМИ е доста авторитетно учебно заведение, макар и диплома за един програмист да не е задължителна, със сигурност ще помогне значително.
-И даже бих аргументирал, че е **по-добре да следваш една година във ФМИ и да се откажеш, отколкото да следваш 4 години и да завършиш в който и да е друг университет!**
-
-[^inf-sistemi]: Признавам, за тази информация използвах [това мнение от форум](https://forums.bgdev.org/index.php?showtopic=34217&st=0&#entry255351), никой не обсъжда ИС.
-[^mat-i-ii]: Макар че това не е много добра причина за смяна на изпитването, понеже схемата с два такива изпита (единия стандартен и другия с малко задачи, но с пълни решения) си е държала още от времето на комунизма. Моето предположение за тази промяна, е че новата система е влошила качеството на обучение твърде много и искат минималните оценки за влизане се повишават обратно към околността на 6ца, но това вече са мои си конспирации.
-[^minali-1-kurs]: Тази статистика е взета директно от таблици с оценки на редовни студенти на [първи курс по Дискретни структури](https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=228877) и [втори курс по Дизайн и Анализ на Алгоритми](https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=283034). Тези таблици са правени от лектора по списъци от СУСИ (онлайн системата за студенти). Ще спомена по-късно, но дългите факултетни номера, в които има и букви, са на студентите, влезли през 2021, докато кратките пет-цифрени са на студенти от минали години, които повтарят.
-[^2021-kandidati]: Такива статистики много не се намират публично и линковете не са сложени на достъпно място, но успях да изровя директните линкове към разпределението по зали за [първа изпитна сесия по Математика 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), [първата изпитна сесия по Математика 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) и [втората изпитна сесия по Математика 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 година (ако някой от тях спре да работи, архивирани са на [archive.org](https://web.archive.org/)). До всяка зала пише колко човека са разпределени за там, така че общата бройка е една проста сума. Най-много хора са се явили на първата сесися по Математика II: 593, на Математика I са 514 и на втората сесия по Математика II са 568.
-[^2021-mesta]: Този документ вече е лесно достъпен в [сайта на СУ](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). Също говоря за нормалните места по държавна субсидия: без платено обучение и българи, живеещи в чужбина.
-[^visoki-iziskvaniq]: Доколкото съм чувал, тази схема е била валидна до към 2014, поне за специалности като компютърни науки и софтуерно инженерство. Сякаш малко след това баловете на всичко започват яко да падат, ама такива статистики вече хептен ги няма публично. Единствената така информация имат кандидат-студенти, и то за своята година в която влизат, и не се познавам с достатъчно хора, за да разпитвам.
-[^2022-kandidati]: Както за 2021, пак трябваше да се ровя, но намерих разпределението по зали за [единствената изпитна сесия по Математика](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 (също архивирано в [archive.org](https://web.archive.org/)).
-[^2023-kandidati]: Както за 2021, пак имаше ровене, но намерих разпределението по зали за [първата изпитна сесия по Математика](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) и [втората изпитна сесия по математика](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) (както винаги, налични в [archive.org](https://web.archive.org/)). На първата са се явили 979 и 875 на втората.
-[^september]: Разговорно на поправителната сесия им викаме септември, макар и само един-два дена от нея да са в този месец. Причината е, че просто до преди няколко години наистина е била през септември, но са я изместили назад. Защо са я изместили, не знам.
-[^def-set]: Формално няма дефиниция на множество, понеже става малко бездънно: какво е множество, еми колекция от елементи, какво е колекция от елементи, еми съвкупност от елементи, какво е съвкупност, еми множество от елементи. Формално казваме, че множество е първично понятие, тоест че няма дефиниция и се надяваме, че читателя схваща за какво се говори.
-[^axiom-of-choice]: В интерес на истината, това със сигурност е вярно само когато приемаме [аксиомата за избора](https://en.wikipedia.org/wiki/Axiom_of_choice), ако не я приемем, тогава доооста неща стават супер неинтуитивни и изглеждат грешни, обаче чисто формално и математически са верни.
+И даже бих аргументирал, че е =[по-добре да следваш една година във ФМИ и да се откажеш, отколкото да следваш 4 години и да завършиш в който и да е друг университет!]=
diff --git a/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.md b/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du
index 64f94d4..783050b 100644
--- a/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.md
+++ b/src/blog/friendship-ended-with-funtoo-now-gentoo-is-my-best-friend/index.du
@@ -1,15 +1,21 @@
# Friendship ended with Funtoo, now Gentoo is my best friend
-## Contents
+'define expected-reading 11 min
+'define created 28 May 2023
+'define edited 07 June 2023
+[$pagenav]
-1. [Terminology](#terminology)
-2. [Public Enemy No 1: Packages](#public-enemy-no-1-packages)
-3. [I didn't follow the wolf pack philosophy](#i-didnt-follow-the-wolf-pack-philosophy)
-4. [Why did I choose Funtoo in the first place?](#why-did-i-choose-funtoo-in-the-first-place)
- 1. [Debunking benefits](#debunking-benefits)
- 2. [Personal advantages over Gentoo](#personal-advantages-over-gentoo)
+.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?]
+ .numbered
+ 1. [url #debunking-benefits Debunking benefits]
+ 2. [url #personal-advantages-over-gentoo Personal advantages over Gentoo]
-Around 6 months ago I wrote [Taming The Fun-too](/blog/taming-the-fun-too), a blog post sharing my personal experiences with the Funtoo linux distribution.
+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.
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.
@@ -17,50 +23,65 @@ Here is what happened.
Before we begin, I want to take a second and explain some Gentoo/Funtoo terminology:
-- `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.
+: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.
+
+ .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 [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?
+ 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]).
+
+- `[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 [vim](https://packages.gentoo.org/packages/app-editors/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 https://packages.gentoo.org/packages/app-editors/vim vim] supports sound, but not everyone would want to have that feature.
+
## Public Enemy No 1: Packages
Most packages and their dependencies on Funtoo go unmaintained and untested for years, which significantly limits your abilities to install and build software.
-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.
+'footnote packages-in-repo-tree Not all of those packages are in the repository tree, but that doesn't matter, if you want to compile a program, you should be able to do so.
+
+'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.
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 =[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.
-Another problem child was glibc, it is *currently* at [version 2.33-r2](https://github.com/funtoo/core-kit/tree/1.4-release/sys-libs/glibc), which under Gentoo [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).
+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).
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!
+=[But]= Funtoo shouldn't be blamed for it!
## I didn't follow the wolf pack philosophy
-On the [Welcome](https://www.funtoo.org/Welcome) page of Funtoo's website, in the second paragraph, we are linked the [Wolf Pack Philosophy](https://www.funtoo.org/Wolf_Pack_Philosophy) page.
+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.
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:
-
-- **Be Mindful of the Pack** by tackling challenges with the community
+.unordered
+- =[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
+- =[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"
+- =[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.
-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.
+'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].
+
+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.
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 =[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.
@@ -78,15 +99,15 @@ Looking back at it, the last two parts could be applied to a lot of distros, but
But we did also talk about Gentoo, and he pointed out some reasons why Funtoo is better.
Looking at these with the benefit of hindsight:
-> git > rsync
+.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 [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, [rsync is probably better with bad internet connections](https://lwn.net/Articles/759578/).
+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].
-> profiles (flavors and mix-ins)
+.quote profiles (flavors and mix-ins)
-Funtoo has a system called [profiles](https://www.funtoo.org/Funtoo_Profiles).
+Funtoo has a system called [url https://www.funtoo.org/Funtoo_Profiles 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.
@@ -94,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).
-> Funtoo has [stage 3 tarballs](https://wiki.gentoo.org/wiki/Stage_tarball) with already setup DEs
+.quote Funtoo has [url https://wiki.gentoo.org/wiki/Stage_tarball stage 3 tarballs] 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 [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.
+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.
-> fixed release model
+.quote fixed release model
-[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.
+[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.
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.
-> [autogens](https://www.funtoo.org/Autogen)
+.quote [url https://www.funtoo.org/Autogen autogens]
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.
@@ -116,34 +137,29 @@ And I'm not a maintainer, so I don't really care.
Though I've "disproved" all of them, that's not to say there aren't any advantages:
-> ccache
+.quote ccache
Imagine you are compiling a program with source code of over 20000 files and in the latest update, only 1000 of them were changed.
It will be significantly faster, if you recompile only those 1000 files and use your work from before for the others.
That is the idea of ccache, and on Funtoo it works great, I had it enabled for all packages.
Unfortunately, for Gentoo it's the opposite effect, I couldn't compile most packages with it enabled.
-> package.use > make.conf
+.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.
-> better ebuilds
+.quote better ebuilds
Though I can't empirically prove this, I found that the packages that worked on Funtoo compiled faster than their Gentoo counterparts and generally the ebuilds were simpler and more manageable.
-> Slightly better documentation
+.quote Slightly better documentation
I'm not saying Gentoo's documentation is bad, but Funtoo's is often written a bit more simply.
-<br>
+\n
Funtoo has it's audience, if you're ready to be a part of the wolf pack, it has to potential to be even better than Gentoo.
That said, if you need something which always just works, your choice should be Gentoo, as it is for me.
-
-[^packages-in-repo-tree]: Not all of those packages are in the repository tree, but that doesn't matter, if you want to compile a program, you should be able to do so.
-[^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.
-[^glibc]: This point may not be completely fair, since Funtoo has a system for [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.
-[^kicad]: On that aforementioned kicad package, drobbins, the benevolent dictator for life of Funtoo, categorized it as a [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).
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
new file mode 100644
index 0000000..d09c890
--- /dev/null
+++ b/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.du
@@ -0,0 +1,129 @@
+# Icon fonts aren't evil, you just have to care
+
+'define expected-reading 9 min
+'define created 19 July 2023
+'define edited 19 July 2023
+[$pagenav]
+
+.contents
+.numbered
+1. [url #the-problem-with-svgs The problem with SVGs]
+2. [url #icon-fonts 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]
+
+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.
+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.
+
+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].
+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]:
+
+.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].
+ 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]
+
+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.
+- 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.
+
+## 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.
+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]).
+
+### Text antialiasing: unavoidable
+
+At the end of the day, your icons are text, so they'll be antialised.
+The result is them being more blurry.
+This is pretty much unavoidable, but in my limited testing, most of the time they aren't blurry, and when they are, it's never so bad that you start loosing detail.
+
+### Better control over SVGs: not always needed
+
+This is true, you can make an SVG have multiple colors, you can add animations and since SVGs are images, styling is usually easier.
+However, I don't have any desire to do either of these, in practice my icons are "extending" the surrounding text.
+
+### 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].
+
+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.
+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!
+
+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.
+ 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.
+
+2. =[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.
+ To expand it, you need to click an arrow on the top-right corner of the page.
+ Now, that arrow image is "mapped" to the standard triangle pointing up and down characters, so if the font doesn't load or is changed, you would get a triangle, which conveys the same action.
+
+ .p
+ This isn't always possible though, for example, what if you have a company logo of some sort?
+ The solution is in the previous point: don't make your link to that company a single icon, at least add the name next to the icon (or in other words, make the icon decorative).
+
+
+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].
+
+### 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.
+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!
+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.
+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.
+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].
+
+\n
+
+Overall, even with a lot of customization, icon fonts could still sometimes cause issues for accessibility and are more limited in some ways.
+For me, I've found that their negatives (when applicable) don't degrade website usage that much and their positives make my life a whole lot simpler.
diff --git a/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.md b/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.md
deleted file mode 100644
index fe6c84d..0000000
--- a/src/blog/icon-fonts-arent-evil-you-just-have-to-care/index.md
+++ /dev/null
@@ -1,112 +0,0 @@
-# Icon fonts aren't evil, you just have to care
-
-## Contents
-
-1. [The problem with SVGs](#the-problem-with-svgs)
-2. [Icon fonts](#icon-fonts)
- 1. [Text antialiasing: unavoidable](#text-antialiasing-unavoidable)
- 2. [Better control over SVGs: not always needed](#better-control-over-svgs-not-always-needed)
- 3. [Fetching failures and accessible fonts: fixable with care](#fetching-failures-and-accessible-fonts-fixable-with-care)
- 4. [Screen reader accessibility: almost unavoidable](#screen-reader-accessibility-almost-unavoidable)
- 5. [File size: fixable with care](#file-size-fixable-with-care)
-
-Recently I did a [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 [Seren Davies' talk](https://www.youtube.com/watch?v=9xXBYcWgCHA) as well as [many](https://www.irigoyen.dev/blog/2021/02/17/stop-using-icon-fonts/) [other](http://technotes.iangreenleaf.com/posts/font-awesome-not-awesome.html) [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 [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 [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 `<img>` tag, as I was doing, you could do some [magic with filters](https://stackoverflow.com/a/53336754) to change the exact color, though this is kinda difficult and [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 [require JavaScript](https://stackoverflow.com/a/21503151) to edit the internal styling and have [a lot of problems](https://vecta.io/blog/best-way-to-embed-svg):
-
-- `<object>` [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 [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:
-
-- There will be no icon caching, since they'll be a part of the downloaded webpage.
-- [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.
-
-## Icon fonts
-
-The alternative is to create your own font, where you replace certain unicode symbols with your own custom graphics.
-It is [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 [this post by Chris Coyier](https://css-tricks.com/icon-fonts-vs-svg/)).
-
-### Text antialiasing: unavoidable
-
-At the end of the day, your icons are text, so they'll be antialised.
-The result is them being more blurry.
-This is pretty much unavoidable, but in my limited testing, most of the time they aren't blurry, and when they are, it's never so bad that you start loosing detail.
-
-### Better control over SVGs: not always needed
-
-This is true, you can make an SVG have multiple colors, you can add animations and since SVGs are images, styling is usually easier.
-However, I don't have any desire to do either of these, in practice my icons are "extending" the surrounding text.
-
-### 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 [Seren Davies' talk](https://www.youtube.com/watch?v=9xXBYcWgCHA).
-
-Unicode defines certain characters as part of so-called [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 [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:
-
-1. **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).
- Even outside this topic, having text instead of icons [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).
- For example, on mobile devices my sidebar is put on the top, but as to not take too much space, it is "folded" up.
- To expand it, you need to click an arrow on the top-right corner of the page.
- Now, that arrow image is "mapped" to the standard triangle pointing up and down characters, so if the font doesn't load or is changed, you would get a triangle, which conveys the same action.
- This isn't always possible though, for example, what if you have a company logo of some sort?
- The solution is in the previous point: don't make your link to that company a single icon, at least add the name next to the icon (or in other words, make the icon decorative).
-
-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 [tabler-icons](https://tabler-icons.io/) (and more specifically, [version 2.10.0](https://github.com/tabler/tabler-icons/releases/tag/v2.10.0)) and for the editing I use [FontForge](https://fontforge.org/en-US/).
-So, I download the `.ttf` version of the font and then a (part of a) [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 [accessibility attributes](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Attributes) like [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!
-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 [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 ([/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, [there are always ways to load fonts progressively](https://www.filamentgroup.com/lab/font-events.html).
-
-<br>
-
-Overall, even with a lot of customization, icon fonts could still sometimes cause issues for accessibility and are more limited in some ways.
-For me, I've found that their negatives (when applicable) don't degrade website usage that much and their positives make my life a whole lot simpler.
diff --git a/src/blog/index.du b/src/blog/index.du
new file mode 100644
index 0000000..c10655d
--- /dev/null
+++ b/src/blog/index.du
@@ -0,0 +1,63 @@
+# Blog
+
+Articles detailing personal experiences or exploration of certain topics.
+
+\n
+
+:defs
+; [$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] 20 Feb &emsp; [url /blog/microsoft-and-foss-extinguish Microsoft and FOSS: a fire to be extinguished]
+: `[Shallow dive]` | `[Opinion]` | `[Microsoft]` `[GitHub]` `[Linux]` `[FOSS]`
+
+
+#### *[2023]*
+
+:defs
+; [$gb] 30 Aug &emsp; [url /blog/thinkpad-x270-my-favorite-machine ThinkPad X270 - my favorite machine]
+: `[Medium dive]` | `[Review]` | `[Lenovo]` `[ThinkPad]` `[Yoga]`
+
+; [$gb] 19 July &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]`
+
+; [$bg] 14 July &emsp; [url /blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq ФМИ и висшето образование в програмистката индустрия]
+: `[Deep dive]` | `[University]` | `[FMI]` `[Education]`
+
+; [$gb] 07 June &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] 01 May &emsp; [url /blog/bash-is-weird BASH is weird]
+: `[Shallow dive]` | `[bash]` | `[Linux]` `[scripting]`
+
+; [$gb] 18 Apr &emsp; [url /blog/sane-explanation-of-compilers/part-1.html 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]`
+
+
+#### *[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] 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] 04 Dec &emsp; [url /blog/taming-the-fun-too Taming The Fun-too]
+: `[Story]` | `[Funtoo]` | `[Linux]` `[Gentoo]` `[packages]`
+
+; [$gb] 10 Sep &emsp; [url /blog/encrypted-email Encrypted email]
+: `[Medium dive]` | `[Email]` | `[Encryption]` `[Security]` `[PGP]` `[S/MIME]` `[Protonmail]` `[Tutanota]`
+
+
+#### *[2020]*
+
+:defs
+; [$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#]`
diff --git a/src/blog/index.md b/src/blog/index.md
deleted file mode 100644
index d5238fe..0000000
--- a/src/blog/index.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# Blog
-
-Articles detailing personal experiences or exploration of certain topics.
-
-<br>
-
-&.bg 18 Nov &emsp; [Суичът изгоря!](/blog/switchut-izgorq)
-: `Shallow dive` | `Story` | `Networking` `Switch` `NetworkPartner`
-
-&.gb 06 Oct &emsp; [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; [Microsoft and FOSS: a fire to be extinguished](/blog/microsoft-and-foss-extinguish)
-: `Shallow dive` | `Opinion` | `Microsoft` `GitHub` `Linux` `FOSS`
-
-#### *2023*
-
-&.gb 30 Aug &emsp; [ThinkPad X270 - my favorite machine](/blog/thinkpad-x270-my-favorite-machine)
-: `Medium dive` | `Review` | `Lenovo` `ThinkPad` `Yoga`
-
-&.gb 19 July &emsp; [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 July &emsp; [ФМИ и висшето образование в програмистката индустрия](/blog/fmi-i-vissheto-obrazovanie-v-programistkata-industriq)
-: `Deep dive` | `University` | `FMI` `Education`
-
-&.gb 07 June &emsp; [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; [BASH is weird](/blog/bash-is-weird)
-: `Shallow dive` | `bash` | `Linux` `scripting`
-
-&.gb 18 Apr &emsp; [Sane explanation of compilers: Part 1](/blog/sane-explanation-of-compilers/part-1.html)
-: `Deep dive` | `Compilers` | `C` `yacc` `bison` `math` `Trees` `Regex` `Grammar` `Languages`
-
-&.gb 13 Jan &emsp; [Plan 9 in Linux: Mouse menus](/blog/plan9-in-linux-mouse-menus)
-: `Medium dive` | `Linux` | `Plan 9` `mouse` `bash` `script` `X11` `openbox` `jgmenu` `plumber`
-
-#### *2022*
-
-&.gb 23 Dec &emsp; [2.6 years of web design](/blog/2.6-years-of-web-design)
-: `Shallow dive` | `Web design`
-
-&.gb 13 Dec &emsp; [When a language forces simpler thinking](/blog/when-a-language-forces-simpler-thinking)
-: `Shallow dive` | `Common Lisp` | `Advent of Code`
-
-&.gb 04 Dec &emsp; [Taming The Fun-too](/blog/taming-the-fun-too)
-: `Story` | `Funtoo` | `Linux` `Gentoo` `packages`
-
-&.gb 10 Sep &emsp; [Encrypted email](/blog/encrypted-email)
-: `Medium dive` | `Email` | `Encryption` `Security` `PGP` `S/MIME` `Protonmail` `Tutanota`
-
-#### *2020*
-
-&.gb 20 May &emsp; [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/microsoft-and-foss-extinguish/index.md b/src/blog/microsoft-and-foss-extinguish/index.du
index ebd3ab5..5c4a9bf 100644
--- a/src/blog/microsoft-and-foss-extinguish/index.md
+++ b/src/blog/microsoft-and-foss-extinguish/index.du
@@ -1,18 +1,25 @@
# Microsoft and FOSS: a fire to be extinguished
-## Contents
+'define expected-reading 6 min
+'define created 20 February 2024
+'define edited 20 February 2024
+[$pagenav]
-1. [GitHub's embrace and extensions](#githubs-embrace-and-extensions)
-2. [Blowtorch to the penguin](#blowtorch-to-the-penguin)
-3. [But these are good things for the user](#but-these-are-good-things-for-the-user)
- 1. [The practical answer](#the-practical-answer)
- 2. [The moral answer](#the-moral-answer)
+.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]
+ .numbered
+ 1. [url #the-practical-answer The practical answer]
+ 2. [url #the-moral-answer The moral answer]
-A week ago [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 [EEE: Embrace, Extend, Extinguish](https://en.wikipedia.org/wiki/Embrace,_extend,_and_extinguish).
+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].
As it is explained on Wikipedia, this is a very old and successful tactic, where Microsoft would enter new markets by:
+.numbered
1. Embracing public standards and implementing all features the current product landscape offers, then
2. Extending their offering with proprietary features, which will be pushed to customers and finally
3. Extinguishing their competition, since the vast majority of consumers would be depending on the proprietary features of Microsoft's product
@@ -23,22 +30,23 @@ Thinking about the development of GitHub under Microsoft's rule, this pattern se
Open-source by itself is primarily about publishing the source code of your project, but GitHub isn't just about that.
Now we have:
-- [GitHub Octoverse](https://octoverse.github.com/), yearly reports on open-source globally, but quite often through the lens of GitHub
-- [GitHub Insider](https://resources.github.com/newsletter/), a monthly newsletter
-- [GitHub Copilot](https://github.com/features/copilot/), an AI developer tool
-- [GitHub Enterprise](https://github.com/enterprise), an AI developer platform
-- [GitHub blog](https://github.blog/), mostly a set of tutorials and informational articles regarding GitHub
+.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
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, [GitLab](https://gitlab.com/) doesn't offer a developer forum like [GitHub Discussions](https://docs.github.com/en/discussions/collaborating-with-your-community-using-discussions/about-discussions), you won't find a [sourcehut](https://sourcehut.org/)-branded FOSS newsletter, [SourceForge](https://sourceforge.net/) won't allow you to add [animations, graphics, games, etc. on your profile](https://github.com/abhisheknaiidu/awesome-github-profile-readme), there isn't a [codeberg](https://codeberg.org/) [command-line repository management app](https://cli.github.com/), so *obviously GitHub is where it's at for FOSS*.
+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]*.
-And you'll be introduced to GitHub before any of the others, thanks to the [GitHub Student Developer Pack](https://education.github.com/pack), where students can get free access to a variety of services, or to [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.
+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.
-Why learn to use the git terminal command when [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 [Hacker News](https://news.ycombinator.com/) or multiple different FOSS websites, when Microsoft provides.
+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 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".
@@ -46,16 +54,15 @@ 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 [WSL](https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux), Linux applications look and run like any other Windows app.
-Thanks to [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.
+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.
-I mean, they've added the sudo command for crying out loud, there is even an official [Windows package manager](https://en.wikipedia.org/wiki/Windows_Package_Manager)!
+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]!
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.
I'm certain over the coming decade, the true Linux desktop market share, as in machines running natively Linux, will shrink, but since WSL users will contribute to that number, we'll see the opposite.
-
## But these are good things for the user
It could be argued that Microsoft is creating something good for the user, that GitHub's extensions will pull more people into FOSS, it will make developers stronger and more connected than ever.
@@ -75,7 +82,7 @@ It's tempting to imagine Linux software or Linux projects turn into Windows soft
### The moral answer
-[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).
+[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].
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.md b/src/blog/mundus-first-shot-at-gamedev/basic-concepts.du
index ef8995e..e50c2dd 100644
--- a/src/blog/mundus-first-shot-at-gamedev/basic-concepts.md
+++ b/src/blog/mundus-first-shot-at-gamedev/basic-concepts.du
@@ -1,18 +1,25 @@
# Basic Concepts - Mundus: My first shot at game development
-## [*Due for rework*](/rework.html)
+'define expected-reading 5 min
+'define created 21 July 2020
+'define edited 25 November 2020
+[$pagenav]
-[`<<`](./) || [`< User Interface`](./user-interface.html)
+'define start_link ./
+'define prev_link ./user-interface.html User Interface
+[$pagination_end]
-<br>
+[$due_for_rework]
-## Contents
+\n
-1. [Tiles](#tiles)
-2. [Layers and superlayers](#layers-and-superlayers)
-3. [Inventory](#inventory)
-4. [Crafting](#crafting)
-5. [Event logs](#event-logs)
+.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]
Even though the game is quite unfinished, there are still a fair bit of mechanics I've developed.
@@ -20,8 +27,9 @@ 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
- defence - reduces or completely negates certain amounts of damage
@@ -46,6 +54,7 @@ Items, however, are divided into:
- Tool tiles: used for interacting (changing) the environment of the world. In your inventory they are surrounded in blue. There are four types, depending on their capabilities:
+ :unordered
- Shovels: you dig up (remove) ground tiles from ground layer
- Axes: used to break (remove) wooden structures (trees, ladders, ...)
@@ -54,28 +63,34 @@ Items, however, are divided into:
- Swords: used for damaging (killing) mobs
+
+
## Layers and superlayers
The in game world (map) is composed of superlayers. Superlayers represent each elevation level in the world. Conceptually, there are in total 5 superlayers: Space, Sky, Land, Underground and ???, although only Sky, Land and Underground are implemented.
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:
-- **Mobs cannot be on top of structures**, except if the structure is marked as "walkable"
+:unordered
+- =[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.
-- **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)
-- **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)
## Inventory
Each mob can store certain amount of item tiles. That is done in it's inventory. The inventory is comprised of 4 parts:
+:unordered
- Hotbar: a place for having access to a small amount of items at all times. It can contain all item tiles, except groundtiles
- Items: used for bulk storage, it can hold any type of item tile and is the largest part of the inventory
- Accessories and Gear: used only for storing gear tiles
+
## Crafting
Creating new item tiles is done through crafting. Each craftable item requires one to five different materials in different quantities. The item tiles must be inside the "items" part of your inventory.
@@ -83,4 +98,3 @@ Creating new item tiles is done through crafting. Each craftable item requires o
## Event logs
Certain actions you do in the game are stored in memory as messages (logs). They are also used to give you information that you couldn't get otherwise, for example, there is a log when you can't climb up a superlayer because a mob is blocking the way, or when you damage/kill a structure or mob.
-
diff --git a/src/blog/mundus-first-shot-at-gamedev/index.du b/src/blog/mundus-first-shot-at-gamedev/index.du
new file mode 100644
index 0000000..d6eeeec
--- /dev/null
+++ b/src/blog/mundus-first-shot-at-gamedev/index.du
@@ -0,0 +1,55 @@
+# Introduction - Mundus: My first shot at game development
+
+'define expected-reading 2 min
+'define created 21 July 2020
+'define edited 25 November 2020
+[$pagenav]
+
+'define next_link ./timeline.html Timeline
+[$pagination_start]
+
+[$due_for_rework]
+
+\n
+
+:contents
+:numbered
+1. [url ./timeline.html Timeline]
+2. [url ./user-interface.html User Interface]
+ .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]
+
+3. [url ./basic-concepts.html Basic Concepts]
+ .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]
+
+
+
+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.
+
+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.
+
+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]
+
+## Screenshots
+
+<div style="display: flex; overflow-x: scroll; align-items: center">
+ <img src="./img/small-game-window.png" style="height: 100%; flex: 1; margin-right: 0.5em">
+ <img src="./img/map-menu.png" style="height: 100%; flex: 1; margin-right: 0.5em">
+ <img src="./img/inventory-menu.png" style="height: 100%; flex: 1;">
+</div>
+
+*[Screenshots are made on Linux Mint Cinnamon with the Mint-Y theme]*
diff --git a/src/blog/mundus-first-shot-at-gamedev/index.md b/src/blog/mundus-first-shot-at-gamedev/index.md
deleted file mode 100644
index 2c623e5..0000000
--- a/src/blog/mundus-first-shot-at-gamedev/index.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# Introduction - Mundus: My first shot at game development
-
-[`Timeline >`](./timeline.html)
-
-<br>
-
-[*Due for rework*](/rework.html)
-
-## Contents
-
-1. [Timeline](./timeline.html)
-2. [User Interface](./user-interface.html)
- 1. [Main screen](./user-interface.html#main-screen)
- 2. [Create new game](./user-interface.html#create-new-game)
- 3. [Game Window](./user-interface.html#game-window)
- 4. [Map menu](./user-interface.html#map-menu)
- 5. [Inventory menu](./user-interface.html#inventory-menu)
- 6. [Crafting menu](./user-interface.html#crafting-menu)
-3. [Basic Concepts](./basic-concepts.html)
- 1. [Tiles](./basic-concepts.html#tiles)
- 2. [Layers and superlayers](./basic-concepts.html#layers-and-superlayers)
- 3. [Inventory](./basic-concepts.html#inventory)
- 4. [Crafting](./basic-concepts.html#crafting)
- 5. [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 [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 [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 [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**: [GitLab](https://gitlab.com/Syndamia/Mundus)
-
-## Screenshots
-
-<div style="display: flex; overflow-x: scroll; align-items: center">
- <img src="./img/small-game-window.png" style="height: 100%; flex: 1; margin-right: 0.5em">
- <img src="./img/map-menu.png" style="height: 100%; flex: 1; margin-right: 0.5em">
- <img src="./img/inventory-menu.png" style="height: 100%; flex: 1;">
-</div>
-
-*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
new file mode 100644
index 0000000..d6eeeec
--- /dev/null
+++ b/src/blog/mundus-first-shot-at-gamedev/introduction.du
@@ -0,0 +1,55 @@
+# Introduction - Mundus: My first shot at game development
+
+'define expected-reading 2 min
+'define created 21 July 2020
+'define edited 25 November 2020
+[$pagenav]
+
+'define next_link ./timeline.html Timeline
+[$pagination_start]
+
+[$due_for_rework]
+
+\n
+
+:contents
+:numbered
+1. [url ./timeline.html Timeline]
+2. [url ./user-interface.html User Interface]
+ .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]
+
+3. [url ./basic-concepts.html Basic Concepts]
+ .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]
+
+
+
+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.
+
+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.
+
+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]
+
+## Screenshots
+
+<div style="display: flex; overflow-x: scroll; align-items: center">
+ <img src="./img/small-game-window.png" style="height: 100%; flex: 1; margin-right: 0.5em">
+ <img src="./img/map-menu.png" style="height: 100%; flex: 1; margin-right: 0.5em">
+ <img src="./img/inventory-menu.png" style="height: 100%; flex: 1;">
+</div>
+
+*[Screenshots are made on Linux Mint Cinnamon with the Mint-Y theme]*
diff --git a/src/blog/mundus-first-shot-at-gamedev/introduction.md b/src/blog/mundus-first-shot-at-gamedev/introduction.md
deleted file mode 100644
index f88abff..0000000
--- a/src/blog/mundus-first-shot-at-gamedev/introduction.md
+++ /dev/null
@@ -1,44 +0,0 @@
-# Introduction - Mundus: My first shot at game development
-
-[`Timeline >`](./timeline.html)
-
-<br>
-
-## Contents
-
-[*Due for rework*](/rework.html)
-
-1. [Timeline](./timeline.html)
-2. [User Interface](./user-interface.html)
- 1. [Main screen](./user-interface.html#main-screen)
- 2. [Create new game](./user-interface.html#create-new-game)
- 3. [Game Window](./user-interface.html#game-window)
- 4. [Map menu](./user-interface.html#map-menu)
- 5. [Inventory menu](./user-interface.html#inventory-menu)
- 6. [Crafting menu](./user-interface.html#crafting-menu)
-3. [Basic Concepts](./basic-concepts.html)
- 1. [Tiles](./basic-concepts.html#tiles)
- 2. [Layers and superlayers](./basic-concepts.html#layers-and-superlayers)
- 3. [Inventory](./basic-concepts.html#inventory)
- 4. [Crafting](./basic-concepts.html#crafting)
- 5. [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 [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 [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 [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**: [GitLab](https://gitlab.com/Syndamia/Mundus)
-
-## Screenshots
-
-<div style="display: flex; overflow-x: scroll; align-items: center">
- <img src="./img/small-game-window.png" style="height: 100%; flex: 1; margin-right: 0.5em">
- <img src="./img/map-menu.png" style="height: 100%; flex: 1; margin-right: 0.5em">
- <img src="./img/inventory-menu.png" style="height: 100%; flex: 1;">
-</div>
-
-*Screenshots are made on Linux Mint Cinnamon with the Mint-Y theme*
diff --git a/src/blog/mundus-first-shot-at-gamedev/timeline.md b/src/blog/mundus-first-shot-at-gamedev/timeline.du
index cb3da01..5fd66b7 100644
--- a/src/blog/mundus-first-shot-at-gamedev/timeline.md
+++ b/src/blog/mundus-first-shot-at-gamedev/timeline.du
@@ -1,56 +1,65 @@
# Timeline - Mundus: My first shot at game development
-[`< Introduction`](./) || [`User Interface >`](./user-interface.html)
+'define expected-reading 6 min
+'define created 21 July 2020
+'define edited 25 November 2020
+[$pagenav]
-<br>
+'define prev_link ./ Introduction
+'define next_link ./user-interface.html User Interface
+[$pagination_second]
+
+[$due_for_rework]
+
+\n
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.
-> ***08.02.2020***&emsp;Day 0, Hour 0
+.quote *[=[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.
-> ***12.02.2020***&emsp;Day 4
+.quote *[=[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.
-> ***27.02.2020***&emsp;Day 19
+.quote *[=[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 [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 [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 [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 [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.
+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.
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.
-> ***28.03.2020***&emsp;Day 49
+.quote *[=[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: [the tree](https://gitlab.com/Syndamia/Mundus/-/blob/c47a34847e52ef76361394dba2c4f524a56d1b92/Mundus/Icons/Land/Items/tree.png) <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 https://gitlab.com/Syndamia/Mundus/-/blob/c47a34847e52ef76361394dba2c4f524a56d1b92/Mundus/Icons/Land/Items/tree.png the tree] <img src="./img/tree-tile.png" class="pixelated-render">.
-> ***06.04.2020***&emsp;Day 58
+.quote *[=[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.
-<br>
+\n
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.
-<br>
+\n
-> ***23.05.2020***&emsp;Day 105
+.quote *[=[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
new file mode 100644
index 0000000..53b8eca
--- /dev/null
+++ b/src/blog/mundus-first-shot-at-gamedev/user-interface.du
@@ -0,0 +1,92 @@
+# User Interface - Mundus: My first shot at game development
+
+'define expected-reading 4 min
+'define created 21 July 2020
+'define edited 25 November 2020
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./timeline.html Timeline
+'define next_link ./basic-concepts.html Basic Concepts
+[$pagination_middle]
+
+[$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]
+
+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].
+
+=[Note:]= all screenshots are made in Linux Mint Cinnamon with Mint-Y theme.
+
+## Main screen
+
+[image ./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.
+
+## Create new game
+
+[image ./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.
+
+`[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.
+
+`[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]`.
+
+## Game Window
+
+[image ./img/small-game-window.png]
+
+After the world is generated, the game window opens.
+
+At the top you have your (game) screen. Here you interact with the in-game world. Navigation is done by clicking on a place you want to go to. If you want to alter the environment, first click on an item, that can modify the world and click the thing you want to alter.
+
+Below that is your energy bar. Each mob, including the player, has an energy bar. Each action you do takes energy. If your energy gets depleted, you start taking damage for everything you do. Eating meat from killing mobs is the only way to replenish it.
+
+Then you have your health. It represents how much life you have. If it drops to zero, you die, although no end screen is developed.
+
+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.
+
+## Map menu
+
+[image ./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.
+
+## Inventory menu
+
+[image ./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]
+
+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.
diff --git a/src/blog/mundus-first-shot-at-gamedev/user-interface.md b/src/blog/mundus-first-shot-at-gamedev/user-interface.md
deleted file mode 100644
index 45fe7d1..0000000
--- a/src/blog/mundus-first-shot-at-gamedev/user-interface.md
+++ /dev/null
@@ -1,85 +0,0 @@
-# User Interface - Mundus: My first shot at game development
-
-## [*Due for rework*](/rework.html)
-
-[`<<`](./) || [`< Timeline`](./timeline.html) || [`Basic Concepts >`](./basic-concepts.html)
-
-<br>
-
-## Contents
-
-1. [Main screen](#main-screen)
-2. [Create new game](#create-new-game)
-3. [Game Window](#game-window)
-4. [Map menu](#map-menu)
-5. [Inventory menu](#inventory-menu)
-6. [Crafting menu](#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 [Basic Concepts](./basic-concepts.html).
-
-**Note:** all screenshots are made in Linux Mint Cinnamon with Mint-Y theme.
-
-## Main screen
-
-![](./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.
-
-## Create new game
-
-![](./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.
-
-`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.
-
-`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`.
-
-## Game Window
-
-![](./img/small-game-window.png)
-
-After the world is generated, the game window opens.
-
-At the top you have your (game) screen. Here you interact with the in-game world. Navigation is done by clicking on a place you want to go to. If you want to alter the environment, first click on an item, that can modify the world and click the thing you want to alter.
-
-Below that is your energy bar. Each mob, including the player, has an energy bar. Each action you do takes energy. If your energy gets depleted, you start taking damage for everything you do. Eating meat from killing mobs is the only way to replenish it.
-
-Then you have your health. It represents how much life you have. If it drops to zero, you die, although no end screen is developed.
-
-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.
-
-## Map menu
-
-![](./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.
-
-## Inventory menu
-
-![](./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
-
-![](./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.
-
diff --git a/src/blog/plan9-in-linux-mouse-menus/index.md b/src/blog/plan9-in-linux-mouse-menus/index.du
index a231a4a..ea1345f 100644
--- a/src/blog/plan9-in-linux-mouse-menus/index.md
+++ b/src/blog/plan9-in-linux-mouse-menus/index.du
@@ -1,21 +1,33 @@
# Plan 9 in Linux: Mouse menus
-## Contents
+'define expected-reading 17 min
+'define created 10 January 2023
+'define edited 28 March 2023
+[$pagenav]
-1. [Usefulness in Linux](#usefulness-in-linux)
-2. [Going about it](#going-about-it)
- - [\#1](#1)
- - [\#2](#2)
- - [\#3](#3)
- - [\#4](#4)
- + [Open files](#open-files)
- + [Send](#send)
- + [Window management](#window-management)
+.contents
+.numbered
+1. [url #usefulness-in-linux Usefulness in Linux]
+2. [url #going-about-it Going about it]
+ .bulleted
+ - [url #1 \#1]
+ - [url #2 \#2]
+ - [url #3 \#3]
+ - [url #4 \#4]
+ .bulleted
+ - [url #open-files Open files]
+ - [url #send Send]
+ - [url #window-management 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.
+'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]]*.
+
+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.
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[$acme] 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">
@@ -30,7 +42,7 @@ 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:
-![](./img/plan9-mouse3-menu.png)
+[image ./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).
@@ -39,17 +51,21 @@ For example, if you release it while hovering "New", you cursor will change, and
Your browser doesn't support the video tag
</video>
-"Opening" an application is always done via a command in the terminal, where the program will ["take over the window"](https://9p.io/wiki/plan9/Using_rio/index.html).
+"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"].
Finally, the middle mouse button (button 2), shows text-control options, which can be executed on selected text:
-![](./img/plan9-mouse2-menu.png)
+[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.
-You'll recognise `cut`, `paste` and `snarf`[^snarf], the latter being just another word for copy.
-Since every modern window manager supports those in some form, I'll concentrate on the others.
-`plumb` is the most interesting: it sends the selection to a "plumber" application, which practically[^plumber-in-apps] 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.
-`send` enters the selected text as a command in the current shell.
+You'll recognise `[cut]`, `[paste]` and `[snarf]` [$snarf], 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.
+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.
### Usefulness in Linux
@@ -75,49 +91,48 @@ 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, [tell me about it](/about)), 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 /about tell me about it]), 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 ([YouTube link](https://www.youtube.com/watch?v=RlMxbQmMz_4), [Odysee link](https://odysee.com/@Luke:7/plumbing-in-linux-la-plan-9-from-bell:e)) and an [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).
+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).
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.
The overall life cycle is split into four parts:
-
+.numbered
1. Run script
2. Get selection
3. Open menu
4. Execute action
-#### \#1
+#### #1
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 [blog post](https://tatsumoto-ren.github.io/blog/plumbing-for-language-learners.html)) is [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 ([Issue 198](https://github.com/baskerville/sxhkd/issues/198), and the workaround in didn't work).
+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).
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 [Space-cadet keyboard](https://en.wikipedia.org/wiki/Space-cadet_keyboard), but thanks to the popularity of the [Model M](https://en.wikipedia.org/wiki/Model_M_keyboard), 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 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.
-All that was left was to assign `Hyper` to some key that I don't use, and what better than Caps Lock!
-There are [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 [setxkbmap](https://gitlab.freedesktop.org/xorg/app/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 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]:
```
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
# Hyper_L + Middle mouse button
mod4 + button2
$HOME/.a/plumb.sh 1
@@ -125,50 +140,48 @@ mod4 + button2
# Hyper_L + Right mouse button
mod4 + button3
$HOME/.a/plumb.sh
-```
-For details about these options, refer to the [manpage](https://github.com/baskerville/sxhkd/blob/master/doc/sxhkd.1.asciidoc).
+
+For details about these options, refer to the [url https://github.com/baskerville/sxhkd/blob/master/doc/sxhkd.1.asciidoc manpage].
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.
Feel free to change this behaviour.
-#### \#2
+#### #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.
-[uninformativ.de](https://www.uninformativ.de/) has a great blog post about [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.
+[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.
-As for getting it inside our script, [xclip](https://github.com/astrand/xclip) is a perfect choice.
+As for getting it inside our script, [url https://github.com/astrand/xclip xclip] is a perfect choice.
In the very beginning, we'll just store the selection in a variable and work from there:
```bash
selection="$(xclip -o)"
-```
-#### \#3
+#### #3
With that out of the way, all we now need is an actual menu to appear.
-Luke Smith and Ren Tatsumoto both used [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: [jgmenu](https://jgmenu.github.io/).
+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].
-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:
```
Send,echo 1
Resize,echo 2
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):
-```
+:code
menu_width = 1
arrow_width = 1
icon_size = 0
@@ -187,13 +200,13 @@ color_menu_border = #88cc88 100
color_norm_fg = #000000 100
color_sel_bg = #448844 100
color_sel_fg = #000000 100
-```
-More info on these options can be found in the [manpage](https://jgmenu.github.io/jgmenu.1.html).
+
+More info on these options can be found in the [url https://jgmenu.github.io/jgmenu.1.html manpage].
Putting it all together, it looks something like this:
-```bash
+:code_bash
action=$(echo -ne "Send,echo 1\nResize,echo 2\nMove,echo 3\n" | jgmenu --at-pointer --simple --config-file="$HOME/.config/jgmenu/jgmenusimplerc")
case "$action" in
@@ -207,18 +220,18 @@ case "$action" in
...
;;
esac
-```
+
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
+:code_bash
menu=""
windowOptions=0
@@ -226,7 +239,7 @@ function matches() {
echo "$selection" | grep "$1" >/dev/null 2>&1
}
-[ windowOptions -eq 1 ] && menu+="Resize,echo 3\nMove,echo 4\nDelete,echo 5\n,....."
+[ windowOptions -eq 1 && menu+="Resize,echo 3\nMove,echo 4\nDelete,echo 5\n,....."
matches ".*\.cpp" && menu+="Compile and run,echo 10\n"
action=$(echo -ne "$menu" | jgmenu --at-pointer --simple --config-file="$HOME/.config/jgmenu/jgmenusimplerc")
@@ -234,24 +247,23 @@ action=$(echo -ne "$menu" | jgmenu --at-pointer --simple --config-file="$HOME/.c
case "$action" in
...
esac
-```
-#### \#4
-Finally, we need to execute a selected option, aka put commands in each case of `$action`.
+#### #4
+
+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
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')
cd "$(readlink /proc/"$pid1"/cwd)"
-```
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.
@@ -261,13 +273,17 @@ 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.
+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.
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[$escape-sequences]:
```bash
plumb-store-cwd () {
@@ -275,29 +291,26 @@ plumb-store-cwd () {
}
zle -N plumb-store-cwd
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:
```bash
wname="$(cat /proc/"$pid"/comm)"
-if [ $wname == "TERMINAL" ]; then # Replace with your terminal emulator name
+if [ $wname == "TERMINAL"; then # Replace with your terminal emulator name
xdotool key Control+Alt+Page_Up # Execute the shell-compatible combination
sleep 0.1 # Rework with inotify?
cd "$(cat /tmp/plumb-cwd)"
fi
-```
-For the uninitiated, [xdotool](https://github.com/jordansissel/xdotool) is a general X11 tool, which allows (amongst other things) to "execute" key presses via commands.
+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.
##### 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"
-```
It could be optimized if there was a way to make the selection be "pasted" into the shell (without being added to the clipboard), since that would mostly eliminate waiting times.
Sadly I couldn't figure out how to do anything like that.
@@ -311,29 +324,14 @@ For example, normally resizing is done via Alt+RightClick, so I'll just do this:
xdotool keydown Alt
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.
-<br>
+\n
With this our script if finished.
-You can find the whole thing (including some personal modifications) in my [dotfiles](https://gitlab.com/Syndamia/dotfiles/-/blob/main/.a/plumb.sh).
+You can find the whole thing (including some personal modifications) in my [url https://gitlab.com/Syndamia/dotfiles/-/blob/main/.a/plumb.sh dotfiles].
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.
-
-[^plan9-vs-rio]: When I say "Plan 9" in the context of graphical stuff, I usually refer to the default window system [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*^[citation ^needed]*.
-
-[^acme]: acme actually changes how the three mouse buttons work. Paraphrasing the [official page](https://9p.io/wiki/plan9/Using_acme/index.html), button 2 "executes things" and button 3 gets or searches for things.
-
-[^snarf]: It's hard to deduce why exactly it was named like this, but the most probable explanation comes from [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. <br> On an unrelated note, this might have played a part in the reasoning behind vim using the word "yank" for copy.
-
-[^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.
-
-[^9wm]: [9wm](https://github.com/9wm/9wm) is a window manager for X11, so if you use it these functionalities will be available, but I'm referring to (almost; 9wm has forks) every other window manager
-
-[^shell-cwd]: You could make a proper mechanism, which waits for the file to get updated ([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?
-
-[^escape-sequences]: The terminal emulator passes keyboard presses to the shell via [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.
diff --git a/src/blog/sane-explanation-of-compilers/index.md b/src/blog/sane-explanation-of-compilers/index.du
index cd0cf4b..40c6cff 100644
--- a/src/blog/sane-explanation-of-compilers/index.md
+++ b/src/blog/sane-explanation-of-compilers/index.du
@@ -3,4 +3,5 @@
This blogpost is split into multiple parts.
More information is available in the first part.
-- [Part 1](./part-1.html): Introduction and The frontend (aka How do we understand code)
+.bulleted
+- [url ./part-1.html Part 1]: Introduction and The frontend (aka How do we understand code)
diff --git a/src/blog/sane-explanation-of-compilers/part-1.md b/src/blog/sane-explanation-of-compilers/part-1.du
index 80426db..33d8a1a 100644
--- a/src/blog/sane-explanation-of-compilers/part-1.md
+++ b/src/blog/sane-explanation-of-compilers/part-1.du
@@ -1,26 +1,44 @@
# Sane explanation of compilers: Part 1
-## Contents
+'define expected-reading 48 min
+'define created 30 March 2023
+'define edited 24 April 2023
+[$pagenav]
+
+:contents
+:numbered
+1. [url #preface Preface]
+2. [url #i.-how-do-we-understand-code I. How do we understand code?]
+ :numbered
+ 1. [url #math Math]
+ .numbered
+ 1. [url #regular-expressions Regular expressions]
+ 2. [url #grammars Grammars]
+
+ 2. [url #lexers-and-parsers 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]
+ .numbered
+ 1. [url #ll LL]
+ 2. [url #lr LR]
+ 3. [url #lrs-family LR's family]
+ 4. [url #more-info More info]
+
+ 4. [url #abstract-syntax-tree Abstract syntax tree]
+
+
+ 3. [url #implementing-a-front-end Implementing a front-end]
+ .numbered
+ 1. [url #lex lex]
+ 2. [url #yacc yacc]
+ 3. [url #doing-it-properly Doing it properly]
+
+
+3. [url #appendix Appendinx]
+
-1. [Preface](#preface)
-2. [I. How do we understand code?](#i.-how-do-we-understand-code)
- 1. [Math](#math)
- 1. [Regular expressions](#regular-expressions)
- 2. [Grammars](#grammars)
- 2. [Lexers and parsers](#lexers-and-parsers)
- 1. [Implementational difficulties with grammars](#implementational-difficulties-with-grammars)
- 2. [Practical usage](#practical-usage)
- 3. [Parsing algorithms](#parsing-algorithms)
- 1. [LL](#ll)
- 2. [LR](#lr)
- 3. [LR's family](#lrs-family)
- 4. [More info](#more-info)
- 4. [Abstract syntax tree](#abstract-syntax-tree)
- 3. [Implementing a front-end](#implementing-a-front-end)
- 1. [lex](#lex)
- 2. [yacc](#yacc)
- 3. [Doing it properly](#doing-it-properly)
-3. [Appendinx](#appendix)
Recently I signed up for a small university course about compilers.
As I found out, most materials on the topic are either so surface level you barely learn anything, or so specific you need to already know the subject.
@@ -32,10 +50,13 @@ 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[$how-did-we-get-here], which is separated into three main layers/components:
+.numbered
1. Front-end: it understands the program, what the code is trying to do
2. Middle: does optimizations and simplifications, though this part is often inside the back-end
3. Back-end: generates the actual machine instructions
@@ -44,22 +65,22 @@ 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 [wikipedia](https://en.wikipedia.org/wiki/Most_vexing_parse)) this C++ snippet
+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
```
void f(double d) {
int i(int(d));
}
-```
could be interpreted either as a:
-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)`)
+.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)]`)
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 ["Colorless green ideas sleep furiously"](https://en.wikipedia.org/wiki/Colorless_green_ideas_sleep_furiously).
+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"].
The problem of semantics is extremely difficult, however in our case we only care about syntax.
And this is where math comes into play.
@@ -69,8 +90,8 @@ 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: [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.
+There is a special field in mathematics that deals with syntactical analysis: [url https://en.wikipedia.org/wiki/Formal_language formal language theory].
+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.
#### Regular expressions
@@ -81,146 +102,152 @@ 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:
-- [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.
+: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
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.
-- [alternation](https://en.wikipedia.org/wiki/Alternation_%28formal_language_theory%29) - allow different (alternative) strings in the same spot.
+ 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
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".
+ For example `[acce(n | p)t]`, matches both "acce=[n]=t" or "acce=[p]=t".\n
There is no limit on how many alternatives you can have and what their lengths are:
```regex
acc(ordingly | ent | urate)
- ```
matches
- + "acc**ordingly**"
- + "acc**ent**" and
- + "acc**urate**".
+ .bulleted
+ - "acc=[ordingly]="
+ - "acc=[ent]=" and
+ - "acc=[urate]=".
There is no limit on how many groups (with alternation) you can have:
```regex
ac(quirem | c | hievem)en(t | ts)
- ```
matches
- + "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**".
+ .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]=".
-- [Kleene star](https://en.wikipedia.org/wiki/Kleene_star) - repeat the preceding letter or group, 0 or more times.
- An asterisk is used to mark this operation (hence the name, "Kleene **star**").
+- [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]=").
```regex
accents*
- ```
+
will match
- + "accent"
- + "accent**s**
- + "accent**ss**
- + "accent**sss**
- + and so on
+ .bulleted
+ - "accent"
+ - "accent=[s]=
+ - "accent=[ss]=
+ - "accent=[sss]=
+ - and so on
Of course, the asterisk could also be in the middle of the regex, like
```regex
ac*ent
- ```
-
+
which matches
- + "acent"
- + "ac**c**ent"
- + "ac**cc**ent"
- + ...
+ .bulleted
+ - "acent"
+ - "ac=[c]=ent"
+ - "ac=[cc]=ent"
+ - ...
With a group we can repeat entire strings,
```regex
acc(ent)*s
- ```
matches
- + "accs"
- + "acc**ent**s"
- + "acc**entent**s
- + "acc**ententent**s"
- + ...
+ .bulleted
+ - "accs"
+ - "acc=[ent]=s"
+ - "acc=[entent]=s
+ - "acc=[ententent]=s"
+ - ...
- An alternation allows any alternative to be chosen at any point, so
+ An alternation allows any alternative to be chosen at any point, so
```regex
acce(n | p)*t
- ```
matches
- + "accet"
- + "acce**n**t
- + "acce**p**t
- + "acce**nn**t
- + "acce**np**t"
- + "acce**pn**t"
- + "acce**pp**t"
- + "acce**nnn**t"
- + ...
+ .bulleted
+ - "accet"
+ - "acce=[n]=t
+ - "acce=[p]=t
+ - "acce=[nn]=t
+ - "acce=[np]=t"
+ - "acce=[pn]=t"
+ - "acce=[pp]=t"
+ - "acce=[nnn]=t"
+ - ...
-In the modern day, regular expressions permit [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 [lookahead and lookbehind assertions](https://en.wikipedia.org/wiki/Regular_expression#Patterns_for_non-regular_languages).
+
+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].
#### Grammars
However, even then regular expressions are fairly weak, they can't match recursive structures.
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:
-- `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
+.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
-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[$terminals-and-nonterminals].
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]` [$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.
For an example, with the grammar
```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+
S ⇒ aSb ⇒ aaSbb ⇒ aaaSbbb ⇒ aaaaSbbbb ⇒ aaaaccbbbb
-```
-or `accb`:
+or `[accb]`:
```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:
@@ -228,33 +255,32 @@ As for our math expressions, we could create something like this:
```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+
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
N -> 0 | 1 | 2 | ... | 9 | 0N | 1N | 2N | ... | 9N
-```
-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].
+'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].
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:
-```cpp
+:code_cpp
bool matchesp(string str) {
string regex = "acce_t";
@@ -271,16 +297,16 @@ bool matchesp(string str) {
}
return true;
}
-```
+
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 [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).
+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].
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) {
@@ -291,47 +317,48 @@ bool matchesp(string str) {
else
return false;
}
-```
-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.
+'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.
Another difficulty with grammars is ambiguity, let's look at
```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+
E ⇒ E + E ⇒ n + E * E ⇒ n + n * n
-```
```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 [here](#grammars)) 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 #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.
-This is why we're going to separate and generalize the code into [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.
+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.
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.
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
@@ -346,11 +373,13 @@ In the last section we already talked about how easy implementing regexes (lexer
Proper algorithms that "implement" grammars are kind of complicated, and most can handle only specific types of grammars.
Generally we categorize them into:
-- [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
-- [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
+.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
Furthermore, if our algorithms allow for ambiguity (meaning we can replace a name with any one of multiple expressions), we divide them into:
+.bulleted
- left-most derivation algorithms, where we choose the left-most valid expression
- right-most derivation algorithms, where we chose the right-most valid expression
@@ -359,7 +388,7 @@ Looking at some of the more famous ones:
##### LL
-[LL](https://en.wikipedia.org/wiki/LL_parser): top-down left-most derivations algorithm that can parse only specific types of grammars.
+[url https://en.wikipedia.org/wiki/LL_parser LL]: 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.
@@ -367,63 +396,63 @@ An "LL(k) grammar" is, by extension, a grammar which can be parsed with an LL(k)
So, the way we'll check if an expression matches our grammar, is by starting with the start name and reading the next k character from the input.
We check the first k character of all expressions, and if anyone of them is a name, we try with substitution for every possibility with that name, essentially peeking into the name's possibilities.
+:unordered
- As an example, the grammar:
```grammar
F -> a
S -> F | (S + F)
- ```
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):
- ```
+ :code
I v
Input: (a + a)
I v
Production: S
- ```
- 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:
- ```
+ :code
I v
Input: (a + a)
-
- I v
+
+ I v
Production: (S + F)
- ```
- 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
+
+ :code
I v
Input: (a + a)
-
- I v
+
+ I v
Production: (S + F)
- ```
- 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!
+
+ :code
I v
Input: (a + a)
-
+
I v
Production: (a + F)
- ```
- 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 [Karl R. Abrahamson notes](http://www.cs.ecu.edu/karl/5220/spr16/Notes/Top-down/LL1.html).
+ 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].
- The grammar
@@ -431,43 +460,43 @@ We check the first k character of all expressions, and if anyone of them is a na
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 [recursive descent parsers](https://en.wikipedia.org/wiki/Recursive_descent_parser)
##### LR
-[LR](https://en.wikipedia.org/wiki/LR_parser): bottom-up right-most derivations algorithm.
+[url https://en.wikipedia.org/wiki/LR_parser LR]: 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.
It all boils down to using a whole bunch of conditional statements and tracing where we "came" from.
+:unordered
- Let's look at the first LL example:
-
+
```grammar
F -> a
S -> F | (S + F)
- ```
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.
We're going to track the state with different numbers, defined like this:
- |State (number)|Current expression ends with|
- |------|---------------|
- |0 |Nothing; this is the start|
- |1 |The name `S`; the final number should be this|
- |2 |The name `F`|
- |3 |The character "("|
- |4 |The character "a"|
- |5 |"(S"|
- |6 |"(S + "|
- |7 |"(S + F"|
- |8 |"(S + F)"; this is the one before the final|
+ .table
+ |=State (number)=||=Current expression ends with=|
+ |:0 :||:Nothing; this is the start:|
+ |:1 :||:The name `[S]`; the final number should be this:|
+ |:2 :||:The name `[F]`:|
+ |:3 :||:The character "(":|
+ |:4 :||:The character "a":|
+ |:5 :||:"(S":|
+ |:6 :||:"(S + ":|
+ |:7 :||:"(S + F":|
+ |:8 :||:"(S + F)"; this is the one before the final:|
You can think of every state number as the valid, but "unfinished" state of the current string.
For now don't think about the way this table is defined, it'll make sense later.
@@ -475,25 +504,22 @@ It all boils down to using a whole bunch of conditional statements and tracing w
Keep in mind that the way I'll show the algorithm step by step isn't really correct, but will suffice for the current moment.
Reading a character from the input means appending it to the right of String:
-
+
```
String : (
State : 0
- ```
We've read "(", so our string "ends" on a "(".
```
String : (a
State : 3
- ```
We've read "a", our string "ends" on an "a".
```
String : (a
State : 4
- ```
Here comes the clever bit, for certain states, we'll stop reading forward and do something else.
If we're on state 4, our string ends on an "a", so we're going to go backwards and replace it with an F, meaning the current state should be 2.
@@ -501,7 +527,6 @@ It all boils down to using a whole bunch of conditional statements and tracing w
```
String : (F
State : 2
- ```
Here is another such rule, if our state is 2, our string ends with an "F" and we replace it with an S, now the state is 5.
That's why we have a different state for "(S + F", if we didn't, our state would become 2 and we would make "(S + S", which isn't valid.
@@ -510,15 +535,13 @@ It all boils down to using a whole bunch of conditional statements and tracing w
```
String : (S
State : 5
- ```
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.
```
String : (S + a
State : 6
- ```
Now, our string ends with an "a", it's tempting to change our state to 4, but we shouldn't, this would remove our progress so far!
Better yet, this state will also be special, if we have a 6 and we end with "a", rather than going to 4, we'll substitute "a" with F now and change state to 7.
@@ -526,41 +549,39 @@ It all boils down to using a whole bunch of conditional statements and tracing w
```
String : (S + F
State : 7
- ```
And now it's trivial, we read ")", so we go to state 8.
But if we're at state 8, don't continue reading, replace with state 1.
Now that we're at state 1, if we read any character (including end of string), we'll say the string up to now matches and we're done!
-
+
It's also helpful to put what we do in different situations in another table:
- |State|If ends on|Change state to|Also do|
- |------|----------|----------------|-------|
- |0 |"(" |3 | |
- |1 | | |Nothing, we matched|
- |2 | |5 |Replace "F" with "S"|
- |3 |"a" |4 ||
- |4 | |2 |Replace "a" with "F"|
- |5 |" + " |6 | |
- |6 |"a" |7 |Replace "a" with "F"|
- |7 |")" |8 | |
- |8 | |1 |Replace "(S + F)" with "S"|
+ .table
+ |=State=||=If ends on=||=Change state to=||=Also do=|
+ |:0 :||:"(" :||:3 :||: :|
+ |:1 :||: :||: :||:Nothing, we matched:|
+ |:2 :||: :||:5 :||:Replace "F" with "S":|
+ |:3 :||:"a" :||:4 :||::|
+ |:4 :||: :||:2 :||:Replace "a" with "F":|
+ |:5 :||:" + " :||:6 :||: :|
+ |:6 :||:"a" :||:7 :||:Replace "a" with "F":|
+ |:7 :||:")" :||:8 :||: :|
+ |:8 :||: :||:1 :||:Replace "(S + F)" with "S":|
where, if there is a value in "If ends on", we read the next character, while otherwise we don't and we just execute "Change state to" and "Also do".
- 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 [stack](https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29).
+ 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].
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").
- Let's look at the same example, done with shift and reduce operations (without me showing the proper table), where pushing and popping items from the stack is done from the right side of the array:
-
+
```
String : (
State : [0]
- ```
We've read "(", add 3 on top of the stack aka shift(3).
Then we read the "a", shift(4).
@@ -568,28 +589,24 @@ It all boils down to using a whole bunch of conditional statements and tracing w
```
String : (a
State : [0, 3, 4]
- ```
With 4 we'll do a reduction, "a" gets replaced by F, 4 is removed:
```
String : (F
State : [0, 3]
- ```
If last state is 3 and last character is "F", we're doing shift(2).
```
String : (F
State : [0, 3, 2]
- ```
Now, we'll be doing a reduction, where F is replaced by S:
```
String : (S
State : [0, 3]
- ```
If last state is 3 and last character is "S", we're dong shift(5).
@@ -598,24 +615,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 [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=),
- or with a more pretty styling on [Grammophone](https://mdaines.github.io/grammophone/?s=UyAtPiBGIHwgIigiIFMgIisiIEYgIikiLgpGIC0+IGEu#/), opening "Parsing table" on the row "LR(0)".
+- 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)".
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: [CLR](https://en.wikipedia.org/wiki/Canonical_LR_parser), [SLR](https://en.wikipedia.org/wiki/Simple_LR_parser) and [LALR](https://en.wikipedia.org/wiki/LALR_parser).
+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].
-- CLR is an LR parser with 1 character lookahead (LR(1)), following [Knuth](TODO)'s original theory.
+.bulleted
+- CLR is an LR parser with 1 character lookahead (LR(1)), following [url TODO Knuth]'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
@@ -625,26 +645,29 @@ LALR is the most commonly used LR parser, however most compilers are custom-tail
If you want to learn more, I would highly suggest:
-- [LL and LR Parsing Demystified](https://blog.reverberate.org/2013/07/ll-and-lr-parsing-demystified.html) and [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 [Josh Haberman](https://blog.reverberate.org/about/)
-- [Parsing: Top-down versus bottom-up](http://jeffreykegler.github.io/Ocean-of-Awareness-blog/individual/2014/11/ll.html) by [Jeffrey Kegler](https://jeffreykegler.github.io/personal/)
-- [Which Parsing Approach?](https://tratt.net/laurie/blog/2020/which_parsing_approach.html) by [Laurence Tratt](https://tratt.net/laurie/)
-- [A Guide to Parsing: Algorithms and Terminology](https://tomassetti.me/guide-parsing-algorithms-terminology/) by [Gabriele Tomassetti](https://inre.me/)
-- [Parsing](http://www.cs.ecu.edu/karl/5220/spr16/Notes/Parsing/index.html), [Top-Down Parsers](http://www.cs.ecu.edu/karl/5220/spr16/Notes/Top-down/index.html) and [Bottom-Up Parsers](http://www.cs.ecu.edu/karl/5220/spr16/Notes/Bottom-up/index.html) from [Karl R. Abrahamson](http://www.cs.ecu.edu/karl/5220/spr16/Notes/Bottom-up/index.html)'s notes
-- [How to Impement an LR(1) Parser](https://serokell.io/blog/how-to-implement-lr1-parser) by Kirill Andreev
+.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
#### 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.
+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:
+'footnote nomnoml The graphics are made with [url https://nomnoml.com/ nomnoml] by [url https://github.com/skanaar Daniel Kallin]
-![](./img/tree-simple.svg)
+Let's draw out[$nomnoml] this relationship, where the left arrow connects to the left handside and the right accordingly:
-Hey, that looks an awful lot like a [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 **aren't** allowed:
+[image ./img/tree-simple.svg]
-![](./img/tree-cycle.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:
+
+[image ./img/tree-cycle.svg]
Great, but can we represent everything else with a tree?
Why, of course, for example we can represent:
@@ -654,11 +677,10 @@ if (a > b)
c = 5;
else
d += 10;
-```
as
-![](./img/tree-if.svg)
+[image ./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:
@@ -666,72 +688,73 @@ Let's look at a familiar example:
```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:
-- we read the `2`, that is a number, we add it as a node
+:unordered
+- we read the `[2]`, that is a number, we add it as a node
- ![](./img/tree-building-1.svg)
+ .p [image ./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,
+ =[If]= the topmost element in that tree is a brace,
- ![](./img/tree-building-ex1.svg)
+ .p [image ./img/tree-building-ex1.svg]
- we connect it to the left handside of `*`:
+ we connect it to the left handside of `[*]`:
- ![](./img/tree-building-ex2.svg)
+ .p [image ./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 `*`.
- For example, let's say we had `1 + 2 * 3`, and we've just read the `*`.
+ =[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,
- ![](./img/tree-building-ex3.svg)
+ .p [image ./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]`
- ![](./img/tree-building-ex4.svg)
+ .p [image ./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 `[*]`
- ![](./img/tree-building-2.svg)
+ .p [image ./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.
- ![](./img/tree-building-3.svg)
+ .p [image ./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 [visitor pattern](https://en.wikipedia.org/wiki/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 https://en.wikipedia.org/wiki/Visitor_pattern 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.
-[Compiler-compilers](https://en.wikipedia.org/wiki/Compiler-compiler) are tools that create parsers (and more) from their normal formal definition.
+[url https://en.wikipedia.org/wiki/Compiler-compiler Compiler-compilers] 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 [flex](https://github.com/westes/flex).
+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].
A lex source file is divided into three parts:
-```lex
+:code_lex
%{
// C code that will be put in the program verbatim
%}
@@ -745,19 +768,19 @@ A lex source file is divided into three parts:
%%
// C code
-```
-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 }`.
+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 }]`.
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.
+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.
Let's look at a very simple example program: every whole number is printed as "NUMBER", while everything else is printed as-is:
-```lex
+:code_lex
%{
%}
@@ -767,112 +790,107 @@ Let's look at a very simple example program: every whole number is printed as "N
[A-z]+ { printf("%s", yytext); }
%%
-```
-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:
+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:
```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:
-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.
+: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]`.
+
+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
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
```
The number 10 changed to 8, 38, and 19 sequentially, before becoming 0.
-```
will output
```
The number NUMBER changed to NUMBER, NUMBER, and NUMBER sequentially, before becoming NUMBER.
-```
Now let's try something more sophisticated, let's surround numbers and strings in HTML tags, the stuff that power webpages.
We would want numbers to be in the format:
```
<span class="num">number</span>
-```
and strings:
```
<span class="str">string</span>
-```
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
+:code_lex
%{
%}
-/* Only multiline comments are supported, not comments that start with // */
-/* This is a definition, it's in the format "NAME regex" */
+/* Only multiline comments are supported, not comments that start with // */
+/* This is a definition, it's in the format "NAME regex" */
DIGIT [0-9]
%%
/* Comments in here have to be indented, otherwise you'll get an error */
- /* ? means 0 or 1 of the preceding group*/
- /* + means 1 or more of the preceding group*/
- /* the backward slashes are used because . and + have special meaning in regexes*/
+ /* ? means 0 or 1 of the preceding group */
+ /* + means 1 or more of the preceding group */
+ /* the backward slashes are used because . and + have special meaning in regexes */
[\+-]?{DIGIT}+(\.{DIGIT}+)? { printf("<span class=\"num\">%s</span>", yytext); }
- /* [^] is a group of characters, like [], however it specifies "all characters except the ones given"*/
- /* this way if we have "This is a string with " three quotes" it's not going to match the whole thing*/
+ /* [^] is a group of characters, like [], however it specifies "all characters except the ones given" */
+ /* this way if we have "This is a string with " three quotes" it's not going to match the whole thing */
\"[^"]*\"|'[^']*' { printf("<span class=\"str\">%s</span>", yytext); }
%%
-```
+
With the input
```
John said 10 times "2 + 2 = 5" but '2 + 2 = 4'!
-```
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 [string interpolation](https://en.wikipedia.org/wiki/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 https://en.wikipedia.org/wiki/String_interpolation 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 [GNU Bison](https://www.gnu.org/software/bison/).
+Similarly to lex, yacc originates from 1975, and it's modern replacement is [url https://www.gnu.org/software/bison/ GNU Bison].
A yacc file looks very similarly to a lex one:
-```yacc
+:code_yacc
%{
// C code that will be put in the program verbatim
%}
@@ -886,25 +904,23 @@ A yacc file looks very similarly to a lex one:
%%
// C code
-```
+
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
%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
name : TOKEN1 TOKEN2 ...
;
-```
where alternation is defined like
@@ -913,9 +929,8 @@ 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
@@ -923,52 +938,51 @@ name : TOKEN1 { C code here }
| TOKEN2
| TOKEN3 { 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.
-Let's implement a parser for the grammar[^shift-reduce-conflicts]:
+'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[$shift-reduce-conflicts]:
```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
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
+:code_lex
%{
#include "parser.tab.h"
%}
%%
- /* Remember, [] is a group, [abcd] behaves like "(a | b | c | d)" and "\" escapes characters */
+ /* Remember, [] is a group, [abcd] behaves like "(a | b | c | d)" and "\\" escapes characters */
[123] { return NUMBER: }
-[\+\*] { return MATHOP; }
+[\+\\*] { return MATHOP; }
\( { return LBRACE; }
\) { return RBRACE: }
%%
-```
+
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
+:code_yacc
%{
#include "stdio.h"
int yylex();
@@ -986,16 +1000,16 @@ expr : NUMBER
%%
int yyerror(char *s) {
- printf("Error: %s\n", s);
+ printf("Error: %s\\n", s);
return 0;
}
int main() {
yyparse();
}
-```
-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.
@@ -1003,82 +1017,76 @@ First, the lexer:
```bash
flex lexer.l
-```
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
The way we created that lexer and parser worked, but it wasn't very useful and has multiple issues we have to address:
+: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
. { 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 ["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.
+ 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.
- By default it's type is `int` (in Bison), but usually you would want it to be a [union](https://en.wikipedia.org/wiki/Union_type#C/C++).
+ 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].
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
%union {
int num;
char chr;
}
- ```
Now, inside our lexer, rules would look like:
```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
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
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
%token <num> NUMBER <chr> MATHOP <chr> LBRACE <chr> RBRACE
- ```
-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].
+ '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].
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:
@@ -1086,17 +1094,15 @@ The way we created that lexer and parser worked, but it wasn't very useful and h
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
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:
@@ -1107,30 +1113,27 @@ The way we created that lexer and parser worked, but it wasn't very useful and h
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
extern FILE* yyin;
- ```
- and then put in our `main`:
+ and then put in our `[main]`:
```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.
I won't explain this in much detail, since it is just normal C code.
- ```c
+ :code_c
#include <stdlib.h>
#include <stdio.h>
@@ -1147,7 +1150,7 @@ The way we created that lexer and parser worked, but it wasn't very useful and h
out->right = right;
return out;
}
-
+
void printTree(node *n, int level) {
if (n == NULL) return;
// %*s will add level amounts of spaces (but with the "" string)
@@ -1155,18 +1158,18 @@ The way we created that lexer and parser worked, but it wasn't very useful and h
printTree(n->left, level + 1);
printTree(n->right, level + 1);
}
-
+
void freeNode(node *n) {
if (n == NULL) return;
freeNode(n->left);
freeNode(n->right);
free(n);
}
- ```
- 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
+ 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:
+
+ :code_c
#include <stdlib.h>
#include <stdio.h>
@@ -1179,35 +1182,37 @@ The way we created that lexer and parser worked, but it wasn't very useful and h
node* newNode(char val, node *left, node *right);
void printTree(node *n, int level);
void freeNode(node *n);
- ```
+
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:
-- `lexer.l`
+:unordered
+- `[lexer.l]`
- ```lex
+ :code_lex
%{
#include "tree.h"
#include "parser.tab.h"
%}
-
+
%option noyywrap
-
+
%%
-
+
[123] { yylval.num = atoi(yytext); return NUMBER; }
[\+\*] { yylval.chr = yytext[0] ; return MATHOP; }
\( { yylval.chr = '(' ; return LBRACE; }
@@ -1215,13 +1220,13 @@ All in all, we'll have 4 source files for our simple front-end:
\ { } /* Don't do anything on spaces */
. { yy_fatal_error("Bad character"); }
-
+
%%
- ```
-- `parser.y`
- ```yacc
+- `[parser.y]`
+
+ :code_yacc
%{
#include <stdio.h>
#include "tree.h"
@@ -1231,7 +1236,7 @@ All in all, we'll have 4 source files for our simple front-end:
int yylex();
int yyerror(const char *s);
%}
-
+
%union {
int num;
char chr;
@@ -1239,61 +1244,61 @@ All in all, we'll have 4 source files for our simple front-end:
}
%token <num> NUMBER <chr> MATHOP <chr> LBRACE <chr> RBRACE
%type <n> expr
-
+
%%
-
+
start : expr { printTree($1, 0); freeNode($1); }
| expr start { printTree($1, 0); freeNode($1); }
;
-
+
expr : NUMBER { $$ = newNode($1 + '0', NULL, NULL); }
| LBRACE expr MATHOP expr RBRACE { $$ = newNode($3, $2, $4); }
;
-
+
%%
-
+
int yyerror(const char *s) {
printf("Error: %s\n", s);
return 0;
}
-
+
int main(int argc, char* argv[]) {
FILE* input = fopen(argv[1], "r");
if (input == NULL) {
yyerror("reading input file!");
return 1;
}
-
+
yyin = input;
yyparse();
}
- ```
-- `tree.h`
- ```c
+- `[tree.h]`
+
+ :code_c
#ifndef TREE
#define TREE
-
+
#include <stdlib.h>
#include <stdio.h>
-
+
typedef struct node {
char val;
struct node *left;
struct node *right;
} node;
-
+
node* newNode(char val, node *left, node *right);
void printTree(node *n, int level);
void freeNode(node *n);
-
+
#endif
- ```
-- `tree.c`
- ```c
+- `[tree.c]`
+
+ :code_c
#include "tree.h"
node* newNode(char val, node *left, node *right) {
@@ -1303,39 +1308,37 @@ All in all, we'll have 4 source files for our simple front-end:
out->right = right;
return out;
}
-
+
void printTree(node *n, int level) {
if (n == NULL) return;
printf("%*s|-%c\n", level, "", n->val);
printTree(n->left, level + 1);
printTree(n->right, level + 1);
}
-
+
void freeNode(node *n) {
if (n == NULL) return;
freeNode(n->left);
freeNode(n->right);
free(n);
}
- ```
+
+
We compile everything:
```bash
flex lexer.l && bison parser.y && gcc lex.yy.c parse.tab.c tree.c
-```
-Now, let's create the file `test.txt`:
+Now, let's create the file `[test.txt]`:
```
((1+1) * ((3+3) * 2))
-```
and run our front-end on it:
```bash
./a.out test.txt
-```
Our output will be:
@@ -1349,7 +1352,6 @@ Our output will be:
|-3
|-3
|-2
-```
Perfect, we have a good looking tree!
@@ -1359,22 +1361,4 @@ 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 [Dimitar Tagarev](https://github.com/dtagarev) for his help with reviewing this post.
-
-[^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.
-
-[^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.
-
-[^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.
-
-[^regular-grammars]: Such grammars are called [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.
-
-[^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.
-
-[^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.
-
-[^nomnoml]: The graphics are made with [nomnoml](https://nomnoml.com/) by [Daniel Kallin](https://github.com/skanaar)
-
-[^shift-reduce-conflicts]: You might be tempted to try and make one for the grammar inside the [AST](#abstract-syntax-tree) section, but that one is ever so slightly problematic, because it's ambiguous (I showed why at the end of [Implementational difficulties with grammars](#implementational-difficulties-with-grammars)). Bison [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.
-
-[^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.
+Many thanks to [url https://github.com/dtagarev Dimitar Tagarev] for his help with reviewing this post.
diff --git a/src/blog/switchut-izgorq/index.md b/src/blog/switchut-izgorq/index.du
index c86e3ed..4df8f6b 100644
--- a/src/blog/switchut-izgorq/index.md
+++ b/src/blog/switchut-izgorq/index.du
@@ -1,27 +1,32 @@
# Суичът изгоря!
+'define expected-reading 2 min
+'define created 18 November 2024
+'define edited 18 November 2024
+[$pagenav]
+
Преди няколко месеца, интернетът у-нас спря.
Все още ползваме интернет "по медна свързаност", така че проблемът почти винаги се свежда до мрежовия шкаф на улицата, който всички компании оставят в безразбор.
Обаче, тъкмо като интернетът се върна и мрежарят беше готов да си тръгне, услугата взе че спря отново.
Вече доста изнервен, след като провери шкафът още един път, влезе в сградата, изтръгна старият суич (комутатор, но аз съм отраснал с английските наименования), замени го с нов и всичко тръгна.
-Неговият отговор, разбира се, беше че "Суичът е изгорял", заедно с един *любезен* коментар как "Тази инсталация вече е стара, трябва да си купите оптичен интернет, за да не ви горят суичовете и да не трябва да идвам аз!"
+Неговият отговор, разбира се, беше че "Суичът е изгорял", заедно с един *[любезен]* коментар как "Тази инсталация вече е стара, трябва да си купите оптичен интернет, за да не ви горят суичовете и да не трябва да идвам аз!"
Предвидимо, самият суич ни го беше оставил и си тръгна по пътя.
-Та по-късно през деня седнах с един [стар AC/DC адаптер](https://www.globalsources.com/AC-DC-adapter/plug-in-AC-DC-Adapter-1188075760p.htm) и какво намирам: устройството си работи перфектно.
+Та по-късно през деня седнах с един [url https://www.globalsources.com/AC-DC-adapter/plug-in-AC-DC-Adapter-1188075760p.htm стар AC/DC адаптер] и какво намирам: устройството си работи перфектно.
-![](./img/switch-on.JPG "Разбира се, тествах и самите портове дали пускат данни")
+[image ./img/switch-on.JPG "Разбира се, тествах и самите портове дали пускат данни"]
Отдолу си има етикет на който пише, че приема 12V на 0.5A, единствено не пише дали центърът е положителен или отрицателен.
След малко бърникане с мултицедът, лесно се вижда че първото е вярно.
-![](./img/switch-back.JPG "Хартиеното тиксо с полярността е моя добавка")
+[image ./img/switch-back.JPG "Хартиеното тиксо с полярността е моя добавка"]
-Благодарение на етикетът, бързо се намира и оригиналната [уебстраница на която NetworkPartner са го продавали](https://networkpartner.eu/product/8-port-gb-switch/).
+Благодарение на етикетът, бързо се намира и оригиналната [url https://networkpartner.eu/product/8-port-gb-switch/ уебстраница на която NetworkPartner са го продавали].
Единственият въпрос който остава, е какво е накарало интернетът да спре втория път?
-Оригиналната инсталация идва от М-Тел, и техния *талант* е решил да остави суичът да си виси във въздуха, държан само от кабелите, които се свързват към него, включително кабела за захранване.
+Оригиналната инсталация идва от М-Тел, и техния *[талант]* е решил да остави суичът да си виси във въздуха, държан само от кабелите, които се свързват към него, включително кабела за захранване.
Моето предположение е, че захранването просто се е изплъзнало с малко от буксата докато са го оглеждали.
diff --git a/src/blog/taming-the-fun-too/index.md b/src/blog/taming-the-fun-too/index.du
index 46ce820..bbaa677 100644
--- a/src/blog/taming-the-fun-too/index.md
+++ b/src/blog/taming-the-fun-too/index.du
@@ -1,46 +1,55 @@
# Taming the Fun-too
-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 [Funtoo](https://funtoo.org), a boutique fork of [Gentoo](https://gentoo.org).
+'define expected-reading 7 min
+'define created 04 December 2022
+'define edited 04 December 2022
+[$pagenav]
+
+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].
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! *[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: *[a lot could go wrong...]*
-<br>
+\n
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".
-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.
+'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.
This often means that using a Gentoo ebuild will make the problem even worse, but sometimes it does work out.
-<br>
+\n
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 *[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 [ccache](https://ccache.dev/) 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 https://ccache.dev/ ccache] at the time, everything would have to be compiled *[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 *[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!!]=
-<br>
+\n
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!
+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.
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 *[unsolvable]* circular dependency[^circular-dependency].
+Usually there are solutions to such situations, but I kid you not, I had tried =[everything]= and =[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.
-<br>
+\n
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.
@@ -52,25 +61,20 @@ That didn't work and there was another compiling issue (that I can't remember) w
Sanity check to keep you from breaking your system:
Downgrading glibc is not supported and a sure way to destruction.
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, *[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 [Timeshift](https://github.com/linuxmint/timeshift)'s system restore functionality or I would've had to rebuild my whole system.
+Thank goodness for [url https://github.com/linuxmint/timeshift Timeshift]'s system restore functionality or I would've had to rebuild my whole system.
-<br>
+\n
-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 =[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.
-Although I still need Gentoo packages, I install them from Funtoo's portage Gentoo kit.
-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).
-Although everything that has happened, for now, I'm still sticking with Funtoo.
-
-
-[^ebuilds]: Files with instructions and settings for the package manager (portage) on how to build a specific package
+'footnote mask All ebuilds that are "masked", will not be used (therefore, corresponding package will not be compiled and installed/upgraded)
-[^mask]: All ebuilds that are "masked", will not be used (therefore, corresponding package will not be compiled and installed/upgraded)
-
-[^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.
+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 everything that has happened, for now, I'm still sticking with Funtoo.
diff --git a/src/blog/the-physics-behind-a-black-hole-shader/index.md b/src/blog/the-physics-behind-a-black-hole-shader/index.du
index 13ca197..cd9f779 100644
--- a/src/blog/the-physics-behind-a-black-hole-shader/index.md
+++ b/src/blog/the-physics-behind-a-black-hole-shader/index.du
@@ -1,27 +1,38 @@
# The physics behind a black hole shader
-## Contents
+'define expected-reading 22 min
+'define created 12 December 2023
+'define edited 06 October 2024
+[$pagenav]
+
+:contents
+:numbered
+1. [url #what-do-the-physics-say 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?]
+
+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]
+ .numbered
+ 1. [url #properties-of-a-black-hole Properties of a black hole]
+
+4. [url #light-bending-algorithm Light-bending algorithm]
+5. [url #appendix Appendix]
+
-1. [What do the physics say?](#what-do-the-physics-say)
- 1. [What is gravity?](#what-is-gravity)
- 2. [What does it mean to bend space?](#what-does-it-mean-to-bend-space)
- 3. [How to handle the EFEs?](#how-to-handle-the-EFEs)
- 4. [What is a black hole?](#what-is-a-black-hole)
- 5. [What about speed and time?](#what-about-speed-and-time)
-2. [Finding a formula](#finding-a-formula)
-3. [Applying the formula to “bend” light’s path](#applying-the-formula-to-bend-lights-path)
- 1. [Properties of a black hole](#properties-of-a-black-hole)
-4. [Light-bending algorithm](#light-bending-algorithm)
-5. [Appendix](#appendix)
Back in August 2023 I had to submit a project for an elective WebGL programming course in university.
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 *[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 *[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.
@@ -36,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:
-Using [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 [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric) on a (Schwarzschild) black hole.
-To further simplify our calculations, we can make approximations using [celestial mechanics](https://en.wikipedia.org/wiki/Celestial_mechanics).
+'define EFE https://en.wikipedia.org/wiki/Einstein_field_equations
-[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].
-This is not *necessary* to understand, but it will make our goal **much** clearer.
+This is not *[necessary]* to understand, but it will make our goal =[much]= clearer.
Now, let's try and unravel everything.
@@ -51,70 +62,70 @@ 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 [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.
+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.
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 [Mercury's orbit](https://en.wikipedia.org/wiki/Mercury_%28planet%29#Advance_of_perihelion), but no new planet was found.
+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.
-As it turned out, Newton's formulae had only been approximations, they worked when light (and therefore [causality, or the speed at which changes propagate](https://www.youtube.com/watch?v=msVuCEs8Ydo)) had infinite speed.
+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.
-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 =[bent]= space.
+And that only happened because the (=[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].
-
-[^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.
+If you then extend that segment, so it has an infinite length, it becomes a line[$line-definition].
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 [great circle](https://en.wikipedia.org/wiki/Great_circle).
+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].
-![](./img/Illustration_of_great-circle_distance.svg.png)
-*Image by CheCheDaWaff on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=48187293)*
+[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]]*
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".
-Better yet, in geometry there are [geodesics](https://en.wikipedia.org/wiki/Geodesic), the general term for a curve on any surface which is the shortest[^geodesics-are-local] path between any two points.
+'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.
So now we can say "going forwards means going along a geodesic".
-[^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 [Wikipedia](https://en.wikipedia.org/wiki/Geodesic#Introduction).
+'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[$parallels-of-latitude].
-[^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.
-
-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 *[bends]*, and more precisely, it =[bends geodesics]=.
+Furthermore, we live in three spacial dimensions, so we can move in three *[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 =[photons]= (light) =[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 =[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 [Einstein Field Equations][EFE].
+Going back on track, Einstein gives us the necessary equations for those geodesics, the [url [$EFE] Einstein Field Equations].
### 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.
+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.
-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.
-There are plenty of other mathematical solutions, but we have been able to relate the "real" world to only those two.
+'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.
-[^schwm-assumptions]: He also assumed the body didn't have an electric charge and the [cosmological constant](https://en.wikipedia.org/wiki/Cosmological_constant) is zero.
+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.
+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, [>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.
+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.
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.
@@ -123,8 +134,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:
-![](https://upload.wikimedia.org/wikipedia/commons/thumb/0/0e/Marbles_from_Indonesia.jpg/1280px-Marbles_from_Indonesia.jpg)
-*Image from By Okkisafire on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=30338734)*
+[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]]*
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.
@@ -134,37 +145,37 @@ 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 [nuclear force](https://en.wikipedia.org/wiki/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 https://en.wikipedia.org/wiki/Nuclear_force 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.
-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 [elementary particles](https://en.wikipedia.org/wiki/Elementary_particle), meaning there are no "granules" into which the elementary particles can break down.
+'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.
-[^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.
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 =[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 =[a lot]=.
So much so, if you get too close, you will not be able to overwhelm gravity and "merge" into that infinitesimal point:
-![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/CNX_UPhysics_13_07_spacetime.png/800px-CNX_UPhysics_13_07_spacetime.png?20171124170318)
-*The white lines are our geodesics*
-*Image by OpenStax University Physics on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=64307901)*
+[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]]*
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 [gravitational lensing](https://en.wikipedia.org/wiki/Gravitational_lens).
+We call that effect [url https://en.wikipedia.org/wiki/Gravitational_lens gravitational lensing].
Though not unique to black holes, that's when the effect is strongest:
-![](https://upload.wikimedia.org/wikipedia/commons/0/02/Gravitational_lens-full.jpg)
-*Notice how the gray arrows show the path light travels from a galaxy that is behind (obstructed by) the black hole*
+[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]*
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".
@@ -176,38 +187,39 @@ 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 =[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 [Schwarzschild metric](https://en.wikipedia.org/wiki/Schwarzschild_metric), in Schwarzschild coordinates, looks like this:
+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:
-![](./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png)
+[image ./img/Schwarzschild-metric-in-Schwarzschild-coordinates-wikipedia.png]
-**YOUCH!**
+=[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 =[too slow]= to render in real time.
-Thankfully [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:
+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:
-![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png)
+[image ./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 [here](http://spiro.fisica.unipd.it/~antonell/schwarzschild/).
+He explains it in more mathematical detail [url http://spiro.fisica.unipd.it/~antonell/schwarzschild/ here].
But now, finally, we can get a plan for our simulation:
+.bulleted
- represent light as particles
- move each particle in a direction and amount specified by the EFE-based formula
- 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 [Ricardo Antonelli's](https://github.com/rantonels/starless/blob/7a0c3c4efdc0666f53dcfa48d310fb2164be2d1a/tracer.py) and [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.
+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.
## Applying the formula to "bend" light's path
@@ -215,68 +227,82 @@ The direction, alongside the amount by which the particle moves, can be represen
Referring to the formula again:
-![](./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png)
+[image ./img/riccardo-antonelli-schwarzschild-black-hole-force-field-formula.png]
-<code>F<sup>&rarr;</sup></code> returns a force vector (`F` for "force" and <code><sup>&rarr;</sup></code> 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 <code>r<sup>\^</sup></code> 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 **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 ["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).
Imagine a big heavy train on a perfectly straight rails going at a fast speed.
How do you forcefully stop it?
-
- You can put a *really* heavy barrier on the tracks, in front of the train.
+
+ .p
+ You can put a *[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[$hitting-trains].
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
The property with which we can "prove" why both a larger mass at no speed, and a smaller mass at a faster speed, can stop the train, is the momentum.
-
+
+ .p
Angular momentum specifies how much "force" at what speed it takes to stop (or change) the speed and direction of a rotating object.
Imagine the train scenario but on a circular track.
-
+
+ .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.
-
- 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:
+ 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.
+
+ .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:
+
+ .p [image ./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.
- ![](./img/specific-angular-momentum-wikipedia.png)
-
- where **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 =[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.
-[^hitting-trains]: Of course, I'm assuming the trains are strong enough they won't break upon the collision.
-[^angular-momentum]: Angular momentum is actually [defined using the cross product](https://en.wikipedia.org/wiki/Specific_angular_momentum#Definition)
-[^light-has-no-mass]: As mentioned, light has no mass, so this version of the formula wouldn't work.
+ .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.
-
-- <code>r<sup>&#94;</sup></code> is the normalized ([unit](https://en.wikipedia.org/wiki/Unit_vector), hence the `^` on top) vector from the center of the black hole to the light particle:
-
- ![](./img/normalize-vector-wikipedia.png)
+
+- `[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:
+
+ .p [image ./img/normalize-vector-wikipedia.png]
+
Finally, putting all needed variables together in one proper function, we get:
-![Refer to "Antonelli’s formula - explained" in the Appendix](./img/variables-expanded.png)
+[image ./img/variables-expanded.png Refer to "Antonelli’s formula - explained" in the Appendix]
-As you may notice, this can be simplified, if we substitute <code>r<sup>&#94;</sup></code>:
+As you may notice, this can be simplified, if we substitute `[r^[&#94;]^]`:
-![Refer to "Antonelli’s formula - simplified" in the Appendix](./img/antonelli-formula-expanded.png)
+[image ./img/antonelli-formula-expanded.png Refer to "Antonelli’s formula - simplified" in the Appendix]
In effect, we pass the distance from the black hole to the corpuscle and the function returns how light's velocity changes.
@@ -286,44 +312,45 @@ 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[$no-hair-theorem].
Everything else can be derived from it.
-[^no-hair-theorem]: The [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.
-
-There are three radii, which will be the backbone of our black hole: the event horizon, the photon sphere and [ISCO](https://en.wikipedia.org/wiki/Innermost_stable_circular_orbit).
+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].
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:
-![r_s = (2GM)/(c^2)](./img/Schwarzschild-radius-wikipedia.png)
+[image ./img/Schwarzschild-radius-wikipedia.png r_s = (2GM)/(c^2)]
-where `G` is the [gravitational constant](https://en.wikipedia.org/wiki/Gravitational_constant) and `M` is the mass of the black hole (in kg).
+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).
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:
-![r = r_s * 3/2](./img/photon-sphere-wikipedia.png)
+[image ./img/photon-sphere-wikipedia.png r = r_s * 3/2]
+
+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.
-where `G` and `M` are the same as before, `c` is the speed of light in vacuum and <code>r<sub>s</sub></code> 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.
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[$isco] and objects aren't affected.
Formula:
-[^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.
-
-![](./img/isco-wikipedia.png)
+[image ./img/isco-wikipedia.png]
Putting them all together, we should expect light to travel like this:
-![](https://upload.wikimedia.org/wikipedia/commons/2/27/Black_Hole_Shadow.gif)
-*Animation by Hugo Spinelli on [Wikipedia](https://commons.wikimedia.org/w/index.php?curid=138168679)*
+[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]]*
## Light-bending algorithm
Finally, now we have everything we need to devise an algorithm for our simulation.
+.bulleted
- For light we'll store two vectors: one for it's position and one for it's velocity.
- For the black hole we'll store a vector and a quantity: the position of the black hole's center and it's mass.
For convenience, we could just store the Schwarzschild radius, since all of our radii can be expressed only by it.
@@ -339,13 +366,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):
-![Refer to "Algorithm" section of the Appendix](./img/algorithm.png)
+[image ./img/algorithm.png Refer to "Algorithm" section of the Appendix]
-as a reminder, here is the definition of <code>F<sup>&rarr;</sup></code>:
+as a reminder, here is the definition of `[F^[&rarr;]^]`:
-![](./img/antonelli-formula-expanded.png)
+[image ./img/antonelli-formula-expanded.png]
-<br>
+\n
That's it!
We have all of our theoretical background, formulae and algorithm to start work on our actual program.
@@ -356,7 +383,7 @@ To Be Continued!
### LaTeX source for equations
-The images for my custom LaTeX equations were created on [latexeditor.lagrida.com](https://latexeditor.lagrida.com/), by using Firefox's built-in ability to screenshot HTML nodes, in particular the [MathJax](https://www.mathjax.org/) node with the equation.
+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.
#### Antonelli's formula - explained
@@ -369,7 +396,6 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co
& r_l = \text{vector from black hole center to light "particle"}\\
& v_l = \text{velocity of light "particle"}
\end{align*}
-```
#### Antonelli's formula - simplified
@@ -381,7 +407,6 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co
& r_l = \text{vector from black hole center to light "particle"}\\
& v_l = \text{velocity of light "particle"}
\end{align*}
-```
#### Algorithm
@@ -411,4 +436,3 @@ The images for my custom LaTeX equations were created on [latexeditor.lagrida.co
& \qquad v_l = v_l + \overrightarrow{F}(r_l,h) \quad \text{(update light velocity)} \\
& \quad \text{return "Light stuck in photon sphere, never escapes"}
\end{align*}
-```
diff --git a/src/blog/thinkpad-x270-my-favorite-machine/index.md b/src/blog/thinkpad-x270-my-favorite-machine/index.du
index 6e958cc..978d8b4 100644
--- a/src/blog/thinkpad-x270-my-favorite-machine/index.md
+++ b/src/blog/thinkpad-x270-my-favorite-machine/index.du
@@ -1,32 +1,41 @@
# ThinkPad X270 - my favorite machine
-## Contents
+'define expected-reading 17 min
+'define created 30 August 2023
+'define edited 30 August 2023
+[$pagenav]
+
+:contents
+:numbered
+1. [url #context Context]
+2. [url #what-i-think 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]
+
+3. [url #conclusion Conclusion]
+
-1. [Context](#context)
-2. [What I Think](#what-i-think)
- 1. [Display](#display)
- 2. [CPU and RAM](#cpu-and-ram)
- 3. [Hardware support and chassis](#hardware-support-and-chassis)
- 4. [Ports](#ports)
- 5. [Batteries](#batteries)
- 6. [Keyboard and power button](#keyboard-and-power-button)
- 7. [Trackpoint and mouse pad](#trackpoint-and-mouse-pad)
- 8. [Repairability](#repairability)
- 9. [Cooling](#cooling)
- 10. [Pricing](#pricing)
-3. [Conclusion](#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 [Thinkpad X270](https://www.thinkwiki.org/wiki/X270_Detailed_Hardware_Information).
+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].
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.*
+*[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 [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 [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 [Lenovo Yoga S730](https://www.lenovo.com/gb/en/p/laptops/yoga/yoga-slim-series/yoga-s730/88ygs701077) with an [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 [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.
+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.
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.
@@ -35,20 +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 [the perfect size](https://youtu.be/Za_Ul08dtj8?t=1208) and [they should even make laptops that are any bigger](https://youtu.be/Q0h8wWlBxY0?t=1672).
+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].
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 *[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 =[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
+- *[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
@@ -56,17 +66,17 @@ 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 [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).
+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).
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.
-[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!
+[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!
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
+:code_bash
# 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
@@ -77,25 +87,25 @@ modename=$(echo $displayparams | cut -f 1 -d ' ')
xrandr --newmode $displayparams
xrandr --addmode $displayname $modename
xrandr --output $displayname --mode $modename
-```
+
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 [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 [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 [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.
+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.
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.
-[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.
+[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.
### Hardware support and chassis
-ThinkPad laptops generally have [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.
+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.
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.
@@ -113,7 +123,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, =[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?
@@ -126,7 +136,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, [you could probably put an old one in the laptop](https://www.youtube.com/watch?v=Fzmm87oVQ6c)).
+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]).
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.
@@ -136,7 +146,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 [hold it down for 1-3 seconds](https://bbs.archlinux.org/viewtopic.php?pid=1193137#p1193137), 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 https://bbs.archlinux.org/viewtopic.php?pid=1193137#p1193137 hold it down for 1-3 seconds], 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
@@ -174,10 +184,10 @@ 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 [thinkfan](https://github.com/vmatare/thinkfan).
+Of course, as already mentioned, we have drivers for everything, so I installed [url https://github.com/vmatare/thinkfan 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:
-```
+:code
sensors:
- tpacpi: /proc/acpi/ibm/thermal
indices: [0]
@@ -190,26 +200,26 @@ levels:
- [1, 35, 38]
- [3, 38, 53]
- ["level auto", 53, 255]
-```
+
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 [subincho.com](https://subincho.com/index.php), with only a few cosmetic issues; it's practically brand new.
+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.
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 [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).
+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).
So, 340 * 2 = 640 euro, or roughly 1300 Bulgarian Lev.
-At the time of writing, [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 [Microsoft Surface Laptop Go 2](https://www.jarcomputers.com/microsoft-surface-laptop-go-2-8qc-00024-prod-nbmicrosoft8qc00024.html) and [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).
+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).
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 [2.3](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-1035G1+%40+1.00GHz&id=3558) and [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.
+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.
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 [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 [double the CPU mark](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-10510U+%40+1.80GHz&id=3549).
+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].
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/when-a-language-forces-simpler-thinking/index.md b/src/blog/when-a-language-forces-simpler-thinking/index.du
index baee84c..d725e3d 100644
--- a/src/blog/when-a-language-forces-simpler-thinking/index.md
+++ b/src/blog/when-a-language-forces-simpler-thinking/index.du
@@ -1,10 +1,15 @@
# When a language forces simpler thinking
-This year I decided to join the [2022 Advent of Code](https://adventofcode.com/2022) event.
-The exercise [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.
+'define expected-reading 5 min
+'define created 13 December 2022
+'define edited 13 December 2022
+[$pagenav]
+
+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.
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 [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.
+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.
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:
```
@@ -15,11 +20,11 @@ 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 =[current]= folder =[and]= in the =[parent]= folder.
To do such a thing, you would either need to
+.bulleted
- iterate from "/" to that folder, find/store all folders in between, and update them, or
- store some way to access the parent folder, and just travel upwards
@@ -43,16 +48,17 @@ Name | File size sum
Name | Name | Name |
| | |
At index 0 is parent "/" Parent is "a" Parent is "/"
-```
-Now this solution worked great! With this I was able to [solve](https://gitlab.com/Syndamia/advent-of-code/-/tree/main/2022/Day07) both tasks easily.[^day7]
+'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]
#### 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 *[and]* parent index.
-Surprisingly enough, in my solution [(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.
+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.
This works fine for this exact task and exact inputs, however in general this isn't correct. In a structure like this:
```
@@ -63,7 +69,6 @@ This works fine for this exact task and exact inputs, however in general this is
- b (dir)
- a (dir)
- file2.txt (file, size=2)
-```
with an input like this:
@@ -86,13 +91,9 @@ $ ls
$ cd ..
$ cd ..
$ cd 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.
+'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.
-[^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.
-
-[^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 [Solaris](https://docs.oracle.com/cd/E26502_01/html/E29031/mkfile-1m.html) (as a system administration command) and [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.
+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.
diff --git a/src/index.md b/src/index.du
index c4da21c..6f1c137 100644
--- a/src/index.md
+++ b/src/index.du
@@ -4,16 +4,16 @@ My name is Kamen and this is my personal website.
Here I share/store certain parts of my work and write about whatever I find interesting in the computing world.
Have a look around and enjoy your stay!
-<br>
+\n
----
+[$line]
-**Shortcuts:**
-[Source repository](https://gitlab.com/Syndamia/syndamiadotcom) | [Contact information](/about) | Resume in [English](/files/resume-en.pdf) &amp; [Български](/files/resume-bg.pdf)
+=[Shortcuts:]=
+[url https://gitlab.com/Syndamia/syndamiadotcom Source repository] | [url /about Contact information] | Resume in [url /files/resume-en.pdf English] &amp; [url /files/resume-bg.pdf Български]
----
+[$line]
-<br>
+\n
<a class="borderless" href="https://www.vim.org/"><img class="oldschool-badge" src="./img/created.with.vim.gif" alt="Created With VIM"></a>
<a class="borderless" href="https://www.anybrowser.org/campaign/"><img class="oldschool-badge" src="./img/abasat.gif" alt="Viewable With Any Browser"></a>
@@ -24,14 +24,14 @@ Have a look around and enjoy your stay!
### Keyboard navigation (requires javascript)
-|Key|Available|Action|
-|---|---------|------|
-|C |Everywhere|Toggles the theme between light and dark|
-|W |Everywhere|Toggles the page width|
-|E |Everywhere|Expands/shrinks the sidebar|
-|K, Backspace, PageUp, Left arrow, Up arrow|Presentations|Go to previous slide|
-|J, Spacebar, Enter key, PageDown, Right arrow, Down arrow|Presentations|Go to next slide|
-|P, T|Presentations|Start or stop (toggle) presenting|
-|Escape key|Presentations|Stop presenting|
-|Home|Presentations|Go to first slide|
-|End|Presentations|Go to last slide|
+.table
+|=Key=||=Available=||=Action=|
+|:C :||:Everywhere:||:Toggles the theme between light and dark:|
+|:W :||:Everywhere:||:Toggles the page width:|
+|:E :||:Everywhere:||:Expands/shrinks the sidebar:|
+|:K, Backspace, PageUp, Left arrow, Up arrow:||:Presentations:||:Go to previous slide:|
+|:J, Spacebar, Enter key, PageDown, Right arrow, Down arrow:||:Presentations:||:Go to next slide:|
+|:P, T:||:Presentations:||:Start or stop (toggle) presenting:|
+|:Escape key:||:Presentations:||:Stop presenting:|
+|:Home:||:Presentations:||:Go to first slide:|
+|:End:||:Presentations:||:Go to last slide:|
diff --git a/src/license.du b/src/license.du
new file mode 100644
index 0000000..fe8c98c
--- /dev/null
+++ b/src/license.du
@@ -0,0 +1,12 @@
+# License
+
+This project uses two licenses, depending on the item.
+
+For articles and pictures/diagrams/etc. that have been made by me, the license is [url https://creativecommons.org/licenses/by-sa/4.0/ CC BY-SA] (also found in [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/LICENSE-CONTENT LICENSE-CONTENT]).
+Everything under [url /assets assets], unless stated otherwise, also falls in this category.
+
+For source code, like all JavaScript or AWK generation scripts (those aren't on the website but are in the [url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/awk-edits repository]), the license is [url https://www.gnu.org/licenses/gpl-3.0.html GNU GPLv3] (also found in [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/LICENSE-CODE LICENSE-CODE]).
+
+Content in [url /archives Archives] and [url /archived-websites Archived Web] =[isn't made by me and it's respective creator must be asked for licensing]=. This content is not saved in the [url https://gitlab.com/Syndamia/syndamiadotcom GitLab repository].
+
+*[If you feel like something is infringing on your own Copyright, please contact me immediately with any listed contact channel inside [url /about /about]!]*
diff --git a/src/license.md b/src/license.md
deleted file mode 100644
index 92f3501..0000000
--- a/src/license.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# License
-
-This project uses two licenses, depending on the item.
-
-For articles and pictures/diagrams/etc. that have been made by me, the license is [CC BY-SA](https://creativecommons.org/licenses/by-sa/4.0/) (also found in [LICENSE-CONTENT](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/LICENSE-CONTENT)).
-Everything under [assets](/assets), unless stated otherwise, also falls in this category.
-
-For source code, like all JavaScript or AWK generation scripts (those aren't on the website but are in the [repository](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/awk-edits)), the license is [GNU GPLv3](https://www.gnu.org/licenses/gpl-3.0.html) (also found in [LICENSE-CODE](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/LICENSE-CODE)).
-
-Content in [Archives](/archives) and [Archived Web](/archived-websites) **isn't made by me and it's respective creator must be asked for licensing**. This content is not saved in the [GitLab repository](https://gitlab.com/Syndamia/syndamiadotcom).
-
-*If you feel like something is infringing on your own Copyright, please contact me immediately with any listed contact channel inside [/about](/about)!*
diff --git a/src/misc.md b/src/misc.du
index 876a4ee..3746bd8 100644
--- a/src/misc.md
+++ b/src/misc.du
@@ -2,12 +2,13 @@
Other types of content I've made, including documents, images, videos and web demos.
-<br>
+\n
#### 2022
-&.ft-text 19.09 &emsp; [Университетски бележки](/misc/universitetski-belejki)
+:defs
+; [$ft-text] 19.09 &emsp; [url /misc/universitetski-belejki Университетски бележки]
: Различни материали, които съм правил през следването ми във ФМИ
-&.ft-photo 16.07 &emsp; [Layout engines and browsers](/files/misc/Layout%20engines%20and%20browsers.svg)
+; [$ft-photo] 16.07 &emsp; [url /files/misc/Layout%20engines%20and%20browsers.svg Layout engines and browsers]
: A diagram which roughly outlines the main layout engines throughout the web's history
diff --git a/src/misc/index.md b/src/misc/index.du
index 876a4ee..3746bd8 100644
--- a/src/misc/index.md
+++ b/src/misc/index.du
@@ -2,12 +2,13 @@
Other types of content I've made, including documents, images, videos and web demos.
-<br>
+\n
#### 2022
-&.ft-text 19.09 &emsp; [Университетски бележки](/misc/universitetski-belejki)
+:defs
+; [$ft-text] 19.09 &emsp; [url /misc/universitetski-belejki Университетски бележки]
: Различни материали, които съм правил през следването ми във ФМИ
-&.ft-photo 16.07 &emsp; [Layout engines and browsers](/files/misc/Layout%20engines%20and%20browsers.svg)
+; [$ft-photo] 16.07 &emsp; [url /files/misc/Layout%20engines%20and%20browsers.svg Layout engines and browsers]
: A diagram which roughly outlines the main layout engines throughout the web's history
diff --git a/src/misc/universitetski-belejki/index.du b/src/misc/universitetski-belejki/index.du
new file mode 100644
index 0000000..3370baf
--- /dev/null
+++ b/src/misc/universitetski-belejki/index.du
@@ -0,0 +1,41 @@
+# Университетски бележки
+
+На тази уебстраница ще пазя връзки към разнообразни материали, които съм правел през следването ми във [url https://www.fmi.uni-sofia.bg/ ФМИ].
+
+=[В тези файлове със сигурност може да има грешки/недостатъци!]=
+Не гарантирам нищо, ако намерите проблеми може [url /about да ми пишете].
+
+
+
+## 1 курс (2021/2022)
+
+\n
+
+### Алгебра 1
+
+.defs
+; [$ft-text] [url /files/misc/uni-notes/algebra1/topics.pdf Разписани теми за устен изпит] &emsp; [url https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Algebra/Topics/ източник *]
+: Всичките теми, които имах да разписвам за устния изпит. Нещата са взети кажи-речи директно от лекции.
+
+### Диференциално и интегрално смятане 1
+
+:defs
+; [$ft-text] [url /files/misc/uni-notes/dis1/notes.pdf Записки върху материала] &emsp; [url https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Calculus/ източник *]
+: Главните дефиниции, формулировки на теореми и формули, които поне аз сметнах за достатъчни по ДИС 2. Обхваща материала от лекция 1 до 13 включително.
+
+; [$ft-text] [url /files/misc/uni-notes/dis1/notes-appendix.pdf Основни доказателства] &emsp; [url https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Calculus/ източник *]
+: По-важните доказателства от лекции, като съм се опитал да ги формулирам по по-разбираем за мен начин. Не е завършено, напълно обхваща само лекции 1 до 5 и от части лекции 6, 8 и 9.
+
+
+### Дискретни структури
+
+.defs
+; [$ft-text] [url /files/misc/uni-notes/dstr/notes.pdf Записки върху материала] &emsp; [url https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Discrete%20math/ източник *]
+: Съществените за мен дефиниции, формулировки на теореми и формули. Обхваща лекции 1 до 7 включително.
+
+\n
+
+[$line]
+
+<sup id="*">*</sup>: Източници със зезда до тях са свързани с изходния LaTeX код на самите документи, обаче се намират в git хранилище, което за сега не е публично през академичната година.
+Ако Ви трябва, [url /about пишете ми], няма проблем да го пратя.
diff --git a/src/misc/universitetski-belejki/index.md b/src/misc/universitetski-belejki/index.md
deleted file mode 100644
index 560e63e..0000000
--- a/src/misc/universitetski-belejki/index.md
+++ /dev/null
@@ -1,37 +0,0 @@
-# Университетски бележки
-
-На тази уебстраница ще пазя връзки към разнообразни материали, които съм правел през следването ми във [ФМИ](https://www.fmi.uni-sofia.bg/).
-
-**В тези файлове със сигурност може да има грешки/недостатъци!**
-Не гарантирам нищо, ако намерите проблеми може [да ми пишете](/about).
-
-
-
-## 1 курс (2021/2022)
-
-<br>
-
-### Алгебра 1
-
-&.ft-text [Разписани теми за устен изпит](/files/misc/uni-notes/algebra1/topics.pdf) &emsp; [източник](https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Algebra/Topics/) [\*](#*)
-: Всичките теми, които имах да разписвам за устния изпит. Нещата са взети кажи-речи директно от лекции.
-
-### Диференциално и интегрално смятане 1
-
-&.ft-text [Записки върху материала](/files/misc/uni-notes/dis1/notes.pdf) &emsp; [източник](https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Calculus/) [\*](#*)
-: Главните дефиниции, формулировки на теореми и формули, които поне аз сметнах за достатъчни по ДИС 2. Обхваща материала от лекция 1 до 13 включително.
-
-&.ft-text [Основни доказателства](/files/misc/uni-notes/dis1/notes-appendix.pdf) &emsp; [източник](https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Calculus/) [\*](#*)
-: По-важните доказателства от лекции, като съм се опитал да ги формулирам по по-разбираем за мен начин. Не е завършено, напълно обхваща само лекции 1 до 5 и от части лекции 6, 8 и 9.
-
-### Дискретни структури
-
-&.ft-text [Записки върху материала](/files/misc/uni-notes/dstr/notes.pdf) &emsp; [източник](https://gitlab.com/Syndamia/uni-projects/-/blob/main/Year%201/Discrete%20math/) [\*](#*)
-: Съществените за мен дефиниции, формулировки на теореми и формули. Обхваща лекции 1 до 7 включително.
-
-<br>
-
----
-
-<sup id="*">\*</sup>: Източници със зезда до тях са свързани с изходния LaTeX код на самите документи, обаче се намират в git хранилище, което за сега не е публично през академичната година.
-Ако Ви трябва, [пишете ми](/about), няма проблем да го пратя.
diff --git a/src/preserved-media.du b/src/preserved-media.du
new file mode 100644
index 0000000..90866a6
--- /dev/null
+++ b/src/preserved-media.du
@@ -0,0 +1,14 @@
+# Preserved media
+
+An assortment of documents, videos, etc. which are =[not]= made by me, but aren't archived on the internet or have the potential of permanently disappearing.
+
+If you are an owner of something listed here, [url /about contact me] and I'll remove it immediately.
+
+\n
+
+:defs
+; [$ft-zip] 22.09.2022 &emsp; [url /files/media/BrilliantButtonMaker-LucaZappa-updated.zip Reconstructed source] of Luca Zappa's Brilliant Button Maker
+: Using what archive.org had, I reconstructed most of the source code for the "Brilliant Button Maker" by [url https://www.linkedin.com/in/lucazappa/ Luca Zappa]. I also host it [url https://hob.syndamia.com/brilliant-button-maker/ here].
+
+; [$ft-text] 14.10.1991 &emsp; [url /files/media/43208-%D0%A3/43208-%D0%A3.pdf Прибор электроизмерительный комбинированный типа 43208-У]
+: A scanned manual (in Russian) for the Soviet Analog Multimeter [url http://radioamator.ru/izmereniya/multimetry-testery/221-kombinirovannyj-pribor-43208-u-osobennosti-skhemy-i-remonta 43208-У]
diff --git a/src/preserved-media.md b/src/preserved-media.md
deleted file mode 100644
index c7ada8e..0000000
--- a/src/preserved-media.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Preserved media
-
-An assortment of documents, videos, etc. which are **not** made by me, but aren't archived on the internet or have the potential of permanently disappearing.
-
-If you are an owner of something listed here, [contact me](/about) and I'll remove it immediately.
-
-<br>
-
-&.ft-zip 22.09.2022 &emsp; [Reconstructed source](/files/media/BrilliantButtonMaker-LucaZappa-updated.zip) of Luca Zappa's Brilliant Button Maker
-: Using what archive.org had, I reconstructed most of the source code for the "Brilliant Button Maker" by [Luca Zappa](https://www.linkedin.com/in/lucazappa/). I also host it [here](https://hob.syndamia.com/brilliant-button-maker/).
-
-&.ft-text 14.10.1991 &emsp; [Прибор электроизмерительный комбинированный типа 43208-У](/files/media/43208-%D0%A3/43208-%D0%A3.pdf)
-: A scanned manual (in Russian) for the Soviet Analog Multimeter [43208-У](http://radioamator.ru/izmereniya/multimetry-testery/221-kombinirovannyj-pribor-43208-u-osobennosti-skhemy-i-remonta)
diff --git a/src/preserved-media/index.du b/src/preserved-media/index.du
new file mode 100644
index 0000000..90866a6
--- /dev/null
+++ b/src/preserved-media/index.du
@@ -0,0 +1,14 @@
+# Preserved media
+
+An assortment of documents, videos, etc. which are =[not]= made by me, but aren't archived on the internet or have the potential of permanently disappearing.
+
+If you are an owner of something listed here, [url /about contact me] and I'll remove it immediately.
+
+\n
+
+:defs
+; [$ft-zip] 22.09.2022 &emsp; [url /files/media/BrilliantButtonMaker-LucaZappa-updated.zip Reconstructed source] of Luca Zappa's Brilliant Button Maker
+: Using what archive.org had, I reconstructed most of the source code for the "Brilliant Button Maker" by [url https://www.linkedin.com/in/lucazappa/ Luca Zappa]. I also host it [url https://hob.syndamia.com/brilliant-button-maker/ here].
+
+; [$ft-text] 14.10.1991 &emsp; [url /files/media/43208-%D0%A3/43208-%D0%A3.pdf Прибор электроизмерительный комбинированный типа 43208-У]
+: A scanned manual (in Russian) for the Soviet Analog Multimeter [url http://radioamator.ru/izmereniya/multimetry-testery/221-kombinirovannyj-pribor-43208-u-osobennosti-skhemy-i-remonta 43208-У]
diff --git a/src/preserved-media/index.md b/src/preserved-media/index.md
deleted file mode 100644
index c7ada8e..0000000
--- a/src/preserved-media/index.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Preserved media
-
-An assortment of documents, videos, etc. which are **not** made by me, but aren't archived on the internet or have the potential of permanently disappearing.
-
-If you are an owner of something listed here, [contact me](/about) and I'll remove it immediately.
-
-<br>
-
-&.ft-zip 22.09.2022 &emsp; [Reconstructed source](/files/media/BrilliantButtonMaker-LucaZappa-updated.zip) of Luca Zappa's Brilliant Button Maker
-: Using what archive.org had, I reconstructed most of the source code for the "Brilliant Button Maker" by [Luca Zappa](https://www.linkedin.com/in/lucazappa/). I also host it [here](https://hob.syndamia.com/brilliant-button-maker/).
-
-&.ft-text 14.10.1991 &emsp; [Прибор электроизмерительный комбинированный типа 43208-У](/files/media/43208-%D0%A3/43208-%D0%A3.pdf)
-: A scanned manual (in Russian) for the Soviet Analog Multimeter [43208-У](http://radioamator.ru/izmereniya/multimetry-testery/221-kombinirovannyj-pribor-43208-u-osobennosti-skhemy-i-remonta)
diff --git a/src/preserved-web-pages.du b/src/preserved-web-pages.du
new file mode 100644
index 0000000..38f3c59
--- /dev/null
+++ b/src/preserved-web-pages.du
@@ -0,0 +1,11 @@
+# Preserved Web pages
+
+Similarly to [url /preserved-media preserved media], these are web pages/sites with endangered archival, =[not]= made by me, that I've decided to host.
+
+If you are an owner of something listed here, [url /about contact me] and I'll remove it immediately.
+
+\n
+
+:defs
+; [$ft-browser] 2005 &emsp; [url https://hob.syndamia.com/brilliant-button-maker/ Brilliant Button Maker] by Luca Zappa &emsp; [url https://syndamia.com/files/hob/BrilliantButtonMaker-LucaZappa-updated.zip source code]
+: A nice web button maker from the 2000s, written in PHP. Since it was no longer available, I found and fixed up most of the PHP that archive.org saved.
diff --git a/src/preserved-web-pages.md b/src/preserved-web-pages.md
deleted file mode 100644
index db3fa83..0000000
--- a/src/preserved-web-pages.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Preserved Web pages
-
-Similarly to [preserved media](/preserved-media), these are web pages/sites with endangered archival, **not** made by me, that I've decided to host.
-
-If you are an owner of something listed here, [contact me](/about) and I'll remove it immediately.
-
-<br>
-
-&.ft-browser 2005 &emsp; [Brilliant Button Maker](https://hob.syndamia.com/brilliant-button-maker/) by Luca Zappa &emsp; [source code](https://syndamia.com/files/hob/BrilliantButtonMaker-LucaZappa-updated.zip)
-: A nice web button maker from the 2000s, written in PHP. Since it was no longer available, I found and fixed up most of the PHP that archive.org saved.
diff --git a/src/preserved-web-pages/index.du b/src/preserved-web-pages/index.du
new file mode 100644
index 0000000..38f3c59
--- /dev/null
+++ b/src/preserved-web-pages/index.du
@@ -0,0 +1,11 @@
+# Preserved Web pages
+
+Similarly to [url /preserved-media preserved media], these are web pages/sites with endangered archival, =[not]= made by me, that I've decided to host.
+
+If you are an owner of something listed here, [url /about contact me] and I'll remove it immediately.
+
+\n
+
+:defs
+; [$ft-browser] 2005 &emsp; [url https://hob.syndamia.com/brilliant-button-maker/ Brilliant Button Maker] by Luca Zappa &emsp; [url https://syndamia.com/files/hob/BrilliantButtonMaker-LucaZappa-updated.zip source code]
+: A nice web button maker from the 2000s, written in PHP. Since it was no longer available, I found and fixed up most of the PHP that archive.org saved.
diff --git a/src/preserved-web-pages/index.md b/src/preserved-web-pages/index.md
deleted file mode 100644
index db3fa83..0000000
--- a/src/preserved-web-pages/index.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Preserved Web pages
-
-Similarly to [preserved media](/preserved-media), these are web pages/sites with endangered archival, **not** made by me, that I've decided to host.
-
-If you are an owner of something listed here, [contact me](/about) and I'll remove it immediately.
-
-<br>
-
-&.ft-browser 2005 &emsp; [Brilliant Button Maker](https://hob.syndamia.com/brilliant-button-maker/) by Luca Zappa &emsp; [source code](https://syndamia.com/files/hob/BrilliantButtonMaker-LucaZappa-updated.zip)
-: A nice web button maker from the 2000s, written in PHP. Since it was no longer available, I found and fixed up most of the PHP that archive.org saved.
diff --git a/src/privacy.du b/src/privacy.du
new file mode 100644
index 0000000..0ff8c03
--- /dev/null
+++ b/src/privacy.du
@@ -0,0 +1,32 @@
+# Privacy policy
+
+[url https://syndamia.com syndamia.com] and [url https://tiny.syndamia.com tiny.syndamia.com] offer no user data submission (user accounts, reply forms, etc.).
+Also, there is [url #no-collection-with-javascript no form of data collection with Javascript].
+
+Some [url #third-party-services third-party services] as well as some [url #http-logs essential server-side programs] may collect data.
+Any data I'm responsible for =[is NEVER collected to be sold!]=
+
+### HTTP logs
+
+General HTTP requests to the server (and data surrounding them) are saved, which may include: IP address, timestamps, exact page request, user agent, etc.
+My current web server software (program, which handles website requests) of choice is [url https://httpd.apache.org/ apache2], and the data format (mostly) corresponds to it's defaults.
+
+One such data line would look something like:
+
+```
+1.1.1.1 - - [11/Jul/2023:14:28:11 +0300] "GET / HTTP/1.1" 200 668 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0"
+
+These logs could be useful for certain issues, like bad server performance or malicious webpage access.
+
+### Third-party services
+
+My domain is bought with [url https://www.namecheap.com/ namecheap] and it's associated DNS entries are managed with namecheap servers.
+This means that DNS entries, or in simpler terms - domain configurations, first go through namecheap, and that may or may not mean they can collect data from you.
+
+Analogously, my website is hosted on [url https://www.hetzner.com/ hetzner] servers, which may or may not be doing some sort of data collection, outside of my control.
+
+### No collection with Javascript
+
+[url /regarding-js.html This site uses Javascript], so some feature configuration information may be temporarily stored in your browser.
+For what exactly that data is, read [url /regarding-js.html#data-in-browser-storage here].
+However, for now there are no plans on integrating any sort of statistics or personal data collection.
diff --git a/src/privacy.md b/src/privacy.md
deleted file mode 100644
index 072e2db..0000000
--- a/src/privacy.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Privacy policy
-
-[syndamia.com](https://syndamia.com) and [tiny.syndamia.com](https://tiny.syndamia.com) offer no user data submission (user accounts, reply forms, etc.).
-Also, there is [no form of data collection with Javascript](#no-collection-with-javascript).
-
-Some [third-party services](#third-party-services) as well as some [essential server-side programs](#http-logs) may collect data.
-Any data I'm responsible for **is NEVER collected to be sold!**
-
-### HTTP logs
-
-General HTTP requests to the server (and data surrounding them) are saved, which may include: IP address, timestamps, exact page request, user agent, etc.
-My current web server software (program, which handles website requests) of choice is [apache2](https://httpd.apache.org/), and the data format (mostly) corresponds to it's defaults.
-
-One such data line would look something like:
-
-```
-1.1.1.1 - - [11/Jul/2023:14:28:11 +0300] "GET / HTTP/1.1" 200 668 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/113.0"
-```
-
-These logs could be useful for certain issues, like bad server performance or malicious webpage access.
-
-### Third-party services
-
-My domain is bought with [namecheap](https://www.namecheap.com/) and it's associated DNS entries are managed with namecheap servers.
-This means that DNS entries, or in simpler terms - domain configurations, first go through namecheap, and that may or may not mean they can collect data from you.
-
-Analogously, my website is hosted on [hetzner](https://www.hetzner.com/) servers, which may or may not be doing some sort of data collection, outside of my control.
-
-### No collection with Javascript
-
-[This site uses Javascript](/regarding-js.html), so some feature configuration information may be temporarily stored in your browser.
-For what exactly that data is, read [here](/regarding-js.html#data-in-browser-storage).
-However, for now there are no plans on integrating any sort of statistics or personal data collection.
diff --git a/src/regarding-js.du b/src/regarding-js.du
new file mode 100644
index 0000000..ddcbea8
--- /dev/null
+++ b/src/regarding-js.du
@@ -0,0 +1,34 @@
+# Regarding usage of JavaScript
+
+On 20.02.2022 I decided to lift the "ban" on usage of JavaScript in this website. This gives me the freedom to implement some useful features for those that have it enabled. =[Any content that doesn't depend on JavaScript will be perfectly consumable without it!]=
+
+Any user data that might be saved isn't, and never will be, used for purposes not listed here. There isn't, and won't ever be, any form of tracking or data collection that isn't required for some feature (listed here).
+
+## Implemented features
+
+.table
+|=Script=||=Description=||=GitLab source=||=Size=||=Lines=|
+|:[url /scripts/image-show.js image-show.js]:||:Click to zoom on images:||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/image-show.js Link]:||:551B:||:24:|
+|:[url /scripts/back-to-top.js back-to-top.js]:||:Automatically appearing button to scroll to top:||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/back-to-top.js Link]:||:378B:||:15:|
+|:[url /scripts/styling-preload.js styling-preload.js]:||:Disable/enable certain stylesheets before page rendering:||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/styling-preload.js Link]:||:385B:||:13:|
+|:[url /scripts/theme-changer.js theme-changer.js]:||:Change theme between light and dark (split in two files):||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/theme-changer.js Link]:||:468B:||:18:|
+|:[url /scripts/page-width.js page-width.js]:||:Change whether text covers the whole width of the page or only the middle (applicable to wide screens):||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/page-width.js Link]:||:640B:||:23:|
+|:[url /scripts/expand-navbar.js expand-navbar.js]:||:Button to shrink and expand the sidebar:||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/expand-navbar.js Link]:||:728B:||:20:|
+|:[url /scripts/presentation.js presentation.js]:||:Presentation logic (button capabilities and other) =[Loaded only on pages with presentations!]=:||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/presentation.js Link]:||:5.0KB:||:154:|
+|:[url /scripts/keyboard.js keyboard.js]:||:Implements keyboard shortcuts:||:[url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/keyboard.js Link]:||:810B:||:40:|
+|::||:Total without presentation.js:||::||:4.0KB:||:153:|
+|::||:Total with presentation.js:||::||:9.0KB:||:307:|
+
+## Data in browser storage
+
+.p
+
+### Local storage
+
+.table
+|=Key=||=Values=||=Description=|
+|:`[theme]`:||:`[dark]` | `[light]`:||:Saves which theme should be loaded:|
+|:`[width]`:||:`[norm]` | `[wide]`:||:Saves in which width pages should be shown:|
+|:`[navbar]`:||:`[norm]` | `[hidden]`:||:Saves whether the navbar should be expanded or shrunk:|
+
+.p
diff --git a/src/regarding-js.md b/src/regarding-js.md
deleted file mode 100644
index f03e326..0000000
--- a/src/regarding-js.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# Regarding usage of JavaScript
-
-On 20.02.2022 I decided to lift the "ban" on usage of JavaScript in this website. This gives me the freedom to implement some useful features for those that have it enabled. **Any content that doesn't depend on JavaScript will be perfectly consumable without it!**
-
-Any user data that might be saved isn't, and never will be, used for purposes not listed here. There isn't, and won't ever be, any form of tracking or data collection that isn't required for some feature (listed here).
-
-## Implemented features
-
-|Script|Description|GitLab source|Size|Lines|
-|---|---|---|---|---|
-|[image-show.js](/scripts/image-show.js)|Click to zoom on images|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/image-show.js)|551B|24|
-|[back-to-top.js](/scripts/back-to-top.js)|Automatically appearing button to scroll to top|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/back-to-top.js)|378B|15|
-|[styling-preload.js](/scripts/styling-preload.js)|Disable/enable certain stylesheets before page rendering|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/styling-preload.js)|385B|13|
-|[theme-changer.js](/scripts/theme-changer.js)|Change theme between light and dark (split in two files)|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/theme-changer.js)|468B|18|
-|[page-width.js](/scripts/page-width.js)|Change whether text covers the whole width of the page or only the middle (applicable to wide screens)|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/page-width.js)|640B|23|
-|[expand-navbar.js](/scripts/expand-navbar.js)|Button to shrink and expand the sidebar|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/expand-navbar.js)|728B|20|
-|[presentation.js](/scripts/presentation.js)|Presentation logic (button capabilities and other) **Loaded only on pages with presentations!**|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/presentation.js)|5.0KB|154|
-|[keyboard.js](/scripts/keyboard.js)|Implements keyboard shortcuts|[Link](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/src/scripts/keyboard.js)|810B|40|
-||Total without presentation.js:||4.0KB|153|
-||Total with presentation.js:||9.0KB|307|
-
-## Data in browser storage
-
-<p></p>
-
-### Local storage
-
-|Key|Values|Description|
-|---|---|---|
-|`theme`|`dark` \| `light`|Saves which theme should be loaded|
-|`width`|`norm` \| `wide`|Saves in which width pages should be shown|
-|`navbar`|`norm` \| `hidden`|Saves whether the navbar should be expanded or shrunk|
-
-<p></p>
diff --git a/src/rework.du b/src/rework.du
new file mode 100644
index 0000000..21f9033
--- /dev/null
+++ b/src/rework.du
@@ -0,0 +1,5 @@
+# Rework
+
+Pages that have the message [url ./rework.html =[Due for Rework]=] are in some form =[outdated]=. They might have bad formatting, bad wording, contain outdated information or something else is wrong with them.
+
+In any case, =[these pages shouldn't be taken at face value, as they will be updated and fixed soon enough]=.
diff --git a/src/rework.md b/src/rework.md
deleted file mode 100644
index dd3e93b..0000000
--- a/src/rework.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Rework
-
-Pages that have the message [**Due for Rework**](./rework.html) are in some form **outdated**. They might have bad formatting, bad wording, contain outdated information or something else is wrong with them.
-
-In any case, **these pages shouldn't be taken at face value, as they will be updated and fixed soon enough**.
-
diff --git a/src/setup.du b/src/setup.du
new file mode 100644
index 0000000..fee0bc7
--- /dev/null
+++ b/src/setup.du
@@ -0,0 +1,62 @@
+# Setup
+
+Everyone that is really interested in technology has custom configurations for everything they use.
+Here are mine.
+
+## Hardware I own
+
+.table
+|=Designation=||=OS =||=Motherboard / device=||=CPU=||=GPU=||=RAM=|
+|:Main desktop tower:||:NixOS (24.11):||:ASRock B550 Phantom Gaming 4:||:[url https://www.amd.com/en/products/processors/desktops/ryzen/5000-series/amd-ryzen-9-5900x.html AMD Ryzen 9 5900X]:||:[url https://www.amd.com/en/products/graphics/desktops/radeon/6000-series/amd-radeon-rx-6800-xt.html AMD Radeon RX 6800 XT]:||:1x Corsair CMK32GX4M2E3200C16:|
+|::||::||:Bought: 2024:||:[url https://www.cpubenchmark.net/cpu.php?cpu=AMD+Ryzen+9+5900X&id=3870 39125 mark], 12 cores, 24 threads, 3.70 GHz, L1: 768 KB, L2: 6 MB, L3: 64 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+RX+6800+XT&id=4312 25027 mark], 2000 MHz, 16 GB memory:||:DDR4, 32 GB (2x 16GB), 3200 MHz:|
+|:Old desktop tower:||:NixOS (24.05):||:ASRock Z97 Anniversary:||:[url https://www.intel.com/content/www/us/en/products/sku/77488/intel-core-i34160-processor-3m-cache-3-60-ghz/specifications.html Intel Core i3-4160]:||:AMD Sapphire Radeon R7 265:||:2x Corsair CMV8GX3M1A1600C11:|
+|::||::||:Bought: 2015:||:[url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317 3510 mark], 2 cores, 4 threads, 3.60 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+HD+7850&id=323 3849 mark], 900 MHz, 2 GB memory:||:DDR3, 16 GB (2x 8GB), 1600 MHz:|
+|:Main laptop:||:NixOS (24.11):||:Lenovo ThinkPad X270:||:Intel Core i5-6300U:||:Intel HD Graphics 520:||:1x Samsung M471A2k43BB1-CRC:|
+|::||::||:Bought: 2023\nReleased: 2017:||:[url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-6300U+%40+2.40GHz&id=2609 3240 mark], 2 cores, 4 threads, 2.40 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Intel+HD+520&id=3255 871 mark], 300 MHz:||:DDR4, SODIMM, 16 GB, 2133 MHz:|
+|:Second laptop:||:NixOS (23.05):||:Lenovo Yoga S730:||:Intel Core i7-8565U:||:Intel UHD Graphics 620:||:2x Samsung K4EBE304EC-EGCG:|
+|::||::||:Bought: 2019\nReleased: 2018:||:[url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-8565U+%40+1.80GHz&id=3308 6152 mark], 4 cores, 8 threads, 4.60 GHz, L1: 128 KB, L2: 1 MB, L3: 8 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Intel+UHD+Graphics+620&id=3805 1039 mark], 300 MHz:||:LPDDR3 (soldered), 16 GB, 2133 MHz:|
+
+.comment
+|:Main smartphone:||:Fresh Android ROM:||:Samsung Galaxy A50:|
+|:Old smartphone:||:?:||:Samsung Galaxy A5 (2016)
+|:Old smartphone:||:Android ?:||:Samsung ?
+|:Retro PC:||:Windows 98 SE:||:?:||:Intel Pentium ?:||:GeForce GTX 100:||:256 MB
+|:Retro laptop:||:Dell ?
+|:VPS:||:?
+
+*[Yes, I stole the idea for this from [url https://hacktivis.me/about Haelwenn Monnier]]*
+
+## OS setup
+
+.table
+|=Distro=||=Fully switched=||=Configuration files/scripts=|
+|:=[Desktop OS]=:||::||::|
+|:NixOS:||:11.2023:||:[url https://gitlab.com/Syndamia/nix NixOS configuration]:|
+|:Gentoo:||:03.2023:||:[url https://gitlab.com/Syndamia/dotfiles/-/tree/main/.b/etc/portage portage configuration files], [url https://gitlab.com/Syndamia/application-setup/-/blob/main/gentoo/Makefile Installation Makefile]:|
+|:Funtoo:||:12.2021:||:[url https://gitlab.com/Syndamia/dotfiles/-/tree/ef18469c90c8e90d3db436a1a204aec5c92cac73/.b/etc/portage portage configuration files]:|
+|:Fedora 33-34:||:12.2020:||:[url https://gitlab.com/Syndamia/application-setup/-/blob/main/scratch-fedora-setup.sh Installation from Minimal], [url https://gitlab.com/Syndamia/application-setup/-/blob/main/fedora-setup.sh Installation from Cinnamon], [url https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup Cinnamon setup], [url https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/fedora-openbox.sh openbox setup]:|
+|:Linux Mint 19.3-20:||:01.2020:||:[url https://gitlab.com/Syndamia/application-setup/-/blob/main/linux-mint-setup.sh Installation script], [url https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup Cinnamon setup]:|
+|:Manjaro Cinnamon 18.1.4-18.1.5:||:12.2019:||:-:|
+|:=[Server OS]=:||::||::|
+|:Debian 10:||:06.2021:||:-:|
+|:Ubuntu 20.04 LTS:||:07.2020:||:-:|
+
+[url https://gitlab.com/Syndamia/dotfiles Dotfiles here].
+Primary shell is [url https://www.zsh.org/ zsh].
+
+### Desktop environment
+
+.table
+|=Name=||=Fully switched=||=List of apps=|
+|:[url http://openbox.org/wiki/Main_Page openbox wm] + custom apps:||:06.2021:||:[url https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/Application%20Stack.md Application Stack]:|
+|:[url https://projects.linuxmint.com/cinnamon/ Cinnamon]:||:12.2019:||:-:|
+
+## Text editor
+
+.table
+|=Name=||=Fully switched=||=Configuration files=|
+|:[url https://neovim.io/ neovim]:||:08.2024:||:[url https://gitlab.com/Syndamia/anderson/ anderson]:|
+|:[url https://www.vim.org/ vim]:||:10.2020:||:[url https://gitlab.com/Syndamia/dotfiles/-/tree/main/.vim dotfiles]:|
+|:[url https://en.wikipedia.org/wiki/Atom_%28text_editor%29 Atom]:||:05.2020 - 07.2020:||:Switched back after:|
+|:[url https://www.monodevelop.com/ Monodevelop]:||:01.2020:||:-:|
+|:[url https://visualstudio.microsoft.com/ Visual Studio 2017]:||:11.2018:||:-:|
diff --git a/src/setup.md b/src/setup.md
deleted file mode 100644
index 8e19e8f..0000000
--- a/src/setup.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Setup
-
-Everyone that is really interested in technology has custom configurations for everything they use.
-Here are mine.
-
-## Hardware I own
-
-|Designation|OS |Motherboard / device|CPU|GPU|RAM|
-|-----------|---|------------------|---|---|---|
-|Main desktop tower|NixOS (24.11)|ASRock B550 Phantom Gaming 4|[AMD Ryzen 9 5900X](https://www.amd.com/en/products/processors/desktops/ryzen/5000-series/amd-ryzen-9-5900x.html)|[AMD Radeon RX 6800 XT](https://www.amd.com/en/products/graphics/desktops/radeon/6000-series/amd-radeon-rx-6800-xt.html)|1x Corsair CMK32GX4M2E3200C16|
-|||Bought: 2024|[39125 mark](https://www.cpubenchmark.net/cpu.php?cpu=AMD+Ryzen+9+5900X&id=3870), 12 cores, 24 threads, 3.70 GHz, L1: 768 KB, L2: 6 MB, L3: 64 MB, 64-bit|[25027 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+RX+6800+XT&id=4312), 2000 MHz, 16 GB memory|DDR4, 32 GB (2x 16GB), 3200 MHz|
-|Old desktop tower|NixOS (24.05)|ASRock Z97 Anniversary|[Intel Core i3-4160](https://www.intel.com/content/www/us/en/products/sku/77488/intel-core-i34160-processor-3m-cache-3-60-ghz/specifications.html)|AMD Sapphire Radeon R7 265|2x Corsair CMV8GX3M1A1600C11|
-|||Bought: 2015|[3510 mark](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317), 2 cores, 4 threads, 3.60 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit|[3849 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+HD+7850&id=323), 900 MHz, 2 GB memory|DDR3, 16 GB (2x 8GB), 1600 MHz
-|Main laptop|NixOS (24.11)|Lenovo ThinkPad X270|Intel Core i5-6300U|Intel HD Graphics 520|1x Samsung M471A2k43BB1-CRC|
-|||Bought: 2023<br>Released: 2017|[3240 mark](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-6300U+%40+2.40GHz&id=2609), 2 cores, 4 threads, 2.40 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit|[871 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Intel+HD+520&id=3255), 300 MHz|DDR4, SODIMM, 16 GB, 2133 MHz|
-|Second laptop|NixOS (23.05)|Lenovo Yoga S730|Intel Core i7-8565U|Intel UHD Graphics 620|2x Samsung K4EBE304EC-EGCG|
-|||Bought: 2019<br>Released: 2018|[6152 mark](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-8565U+%40+1.80GHz&id=3308), 4 cores, 8 threads, 4.60 GHz, L1: 128 KB, L2: 1 MB, L3: 8 MB, 64-bit|[1039 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Intel+UHD+Graphics+620&id=3805), 300 MHz|LPDDR3 (soldered), 16 GB, 2133 MHz|
-<!--
-|Main smartphone|Fresh Android ROM|Samsung Galaxy A50|
-|Old smartphone|?|Samsung Galaxy A5 (2016)
-|Old smartphone|Android ?|Samsung ?
-|Retro PC|Windows 98 SE|?|Intel Pentium ?|GeForce GTX 100|256 MB
-|Retro laptop|Dell ?
-|VPS|?
--->
-
-*Yes, I stole the idea for this from [Haelwenn Monnier](https://hacktivis.me/about)*
-
-## OS setup
-
-|Distro|Fully switched|Configuration files/scripts|
-|------|--------------|-------------|
-|**Desktop OS**|||
-|NixOS|11.2023|[NixOS configuration](https://gitlab.com/Syndamia/nix)
-|Gentoo|03.2023|[portage configuration files](https://gitlab.com/Syndamia/dotfiles/-/tree/main/.b/etc/portage), [Installation Makefile](https://gitlab.com/Syndamia/application-setup/-/blob/main/gentoo/Makefile)
-|Funtoo|12.2021|[portage configuration files](https://gitlab.com/Syndamia/dotfiles/-/tree/ef18469c90c8e90d3db436a1a204aec5c92cac73/.b/etc/portage)
-|Fedora 33-34|12.2020|[Installation from Minimal](https://gitlab.com/Syndamia/application-setup/-/blob/main/scratch-fedora-setup.sh), [Installation from Cinnamon](https://gitlab.com/Syndamia/application-setup/-/blob/main/fedora-setup.sh), [Cinnamon setup](https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup), [openbox setup](https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/fedora-openbox.sh)
-|Linux Mint 19.3-20|01.2020|[Installation script](https://gitlab.com/Syndamia/application-setup/-/blob/main/linux-mint-setup.sh), [Cinnamon setup](https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup)
-|Manjaro Cinnamon 18.1.4-18.1.5|12.2019|-|
-|**Server OS**|||
-|Debian 10|06.2021|-|
-|Ubuntu 20.04 LTS|07.2020|-|
-
-[Dotfiles here](https://gitlab.com/Syndamia/dotfiles).
-Primary shell is [zsh](https://www.zsh.org/).
-
-### Desktop environment
-
-|Name|Fully switched|List of apps|
-|----|--------------|------------|
-|[openbox wm](http://openbox.org/wiki/Main_Page) + custom apps|06.2021|[Application Stack](https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/Application%20Stack.md)
-|[Cinnamon](https://projects.linuxmint.com/cinnamon/)|12.2019|-|
-
-## Text editor
-
-|Name|Fully switched|Configuration files|
-|----|--------------|-------------------|
-|[neovim](https://neovim.io/)|08.2024|[anderson](https://gitlab.com/Syndamia/anderson/)|
-|[vim](https://www.vim.org/)|10.2020|[dotfiles](https://gitlab.com/Syndamia/dotfiles/-/tree/main/.vim)|
-|[Atom](https://en.wikipedia.org/wiki/Atom_%28text_editor%29)|05.2020 - 07.2020|Switched back after|
-|[Monodevelop](https://www.monodevelop.com/)|01.2020|-
-|[Visual Studio 2017](https://visualstudio.microsoft.com/)|11.2018|-
diff --git a/src/setup/index.du b/src/setup/index.du
new file mode 100644
index 0000000..fee0bc7
--- /dev/null
+++ b/src/setup/index.du
@@ -0,0 +1,62 @@
+# Setup
+
+Everyone that is really interested in technology has custom configurations for everything they use.
+Here are mine.
+
+## Hardware I own
+
+.table
+|=Designation=||=OS =||=Motherboard / device=||=CPU=||=GPU=||=RAM=|
+|:Main desktop tower:||:NixOS (24.11):||:ASRock B550 Phantom Gaming 4:||:[url https://www.amd.com/en/products/processors/desktops/ryzen/5000-series/amd-ryzen-9-5900x.html AMD Ryzen 9 5900X]:||:[url https://www.amd.com/en/products/graphics/desktops/radeon/6000-series/amd-radeon-rx-6800-xt.html AMD Radeon RX 6800 XT]:||:1x Corsair CMK32GX4M2E3200C16:|
+|::||::||:Bought: 2024:||:[url https://www.cpubenchmark.net/cpu.php?cpu=AMD+Ryzen+9+5900X&id=3870 39125 mark], 12 cores, 24 threads, 3.70 GHz, L1: 768 KB, L2: 6 MB, L3: 64 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+RX+6800+XT&id=4312 25027 mark], 2000 MHz, 16 GB memory:||:DDR4, 32 GB (2x 16GB), 3200 MHz:|
+|:Old desktop tower:||:NixOS (24.05):||:ASRock Z97 Anniversary:||:[url https://www.intel.com/content/www/us/en/products/sku/77488/intel-core-i34160-processor-3m-cache-3-60-ghz/specifications.html Intel Core i3-4160]:||:AMD Sapphire Radeon R7 265:||:2x Corsair CMV8GX3M1A1600C11:|
+|::||::||:Bought: 2015:||:[url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317 3510 mark], 2 cores, 4 threads, 3.60 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+HD+7850&id=323 3849 mark], 900 MHz, 2 GB memory:||:DDR3, 16 GB (2x 8GB), 1600 MHz:|
+|:Main laptop:||:NixOS (24.11):||:Lenovo ThinkPad X270:||:Intel Core i5-6300U:||:Intel HD Graphics 520:||:1x Samsung M471A2k43BB1-CRC:|
+|::||::||:Bought: 2023\nReleased: 2017:||:[url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-6300U+%40+2.40GHz&id=2609 3240 mark], 2 cores, 4 threads, 2.40 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Intel+HD+520&id=3255 871 mark], 300 MHz:||:DDR4, SODIMM, 16 GB, 2133 MHz:|
+|:Second laptop:||:NixOS (23.05):||:Lenovo Yoga S730:||:Intel Core i7-8565U:||:Intel UHD Graphics 620:||:2x Samsung K4EBE304EC-EGCG:|
+|::||::||:Bought: 2019\nReleased: 2018:||:[url https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-8565U+%40+1.80GHz&id=3308 6152 mark], 4 cores, 8 threads, 4.60 GHz, L1: 128 KB, L2: 1 MB, L3: 8 MB, 64-bit:||:[url https://www.videocardbenchmark.net/gpu.php?gpu=Intel+UHD+Graphics+620&id=3805 1039 mark], 300 MHz:||:LPDDR3 (soldered), 16 GB, 2133 MHz:|
+
+.comment
+|:Main smartphone:||:Fresh Android ROM:||:Samsung Galaxy A50:|
+|:Old smartphone:||:?:||:Samsung Galaxy A5 (2016)
+|:Old smartphone:||:Android ?:||:Samsung ?
+|:Retro PC:||:Windows 98 SE:||:?:||:Intel Pentium ?:||:GeForce GTX 100:||:256 MB
+|:Retro laptop:||:Dell ?
+|:VPS:||:?
+
+*[Yes, I stole the idea for this from [url https://hacktivis.me/about Haelwenn Monnier]]*
+
+## OS setup
+
+.table
+|=Distro=||=Fully switched=||=Configuration files/scripts=|
+|:=[Desktop OS]=:||::||::|
+|:NixOS:||:11.2023:||:[url https://gitlab.com/Syndamia/nix NixOS configuration]:|
+|:Gentoo:||:03.2023:||:[url https://gitlab.com/Syndamia/dotfiles/-/tree/main/.b/etc/portage portage configuration files], [url https://gitlab.com/Syndamia/application-setup/-/blob/main/gentoo/Makefile Installation Makefile]:|
+|:Funtoo:||:12.2021:||:[url https://gitlab.com/Syndamia/dotfiles/-/tree/ef18469c90c8e90d3db436a1a204aec5c92cac73/.b/etc/portage portage configuration files]:|
+|:Fedora 33-34:||:12.2020:||:[url https://gitlab.com/Syndamia/application-setup/-/blob/main/scratch-fedora-setup.sh Installation from Minimal], [url https://gitlab.com/Syndamia/application-setup/-/blob/main/fedora-setup.sh Installation from Cinnamon], [url https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup Cinnamon setup], [url https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/fedora-openbox.sh openbox setup]:|
+|:Linux Mint 19.3-20:||:01.2020:||:[url https://gitlab.com/Syndamia/application-setup/-/blob/main/linux-mint-setup.sh Installation script], [url https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup Cinnamon setup]:|
+|:Manjaro Cinnamon 18.1.4-18.1.5:||:12.2019:||:-:|
+|:=[Server OS]=:||::||::|
+|:Debian 10:||:06.2021:||:-:|
+|:Ubuntu 20.04 LTS:||:07.2020:||:-:|
+
+[url https://gitlab.com/Syndamia/dotfiles Dotfiles here].
+Primary shell is [url https://www.zsh.org/ zsh].
+
+### Desktop environment
+
+.table
+|=Name=||=Fully switched=||=List of apps=|
+|:[url http://openbox.org/wiki/Main_Page openbox wm] + custom apps:||:06.2021:||:[url https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/Application%20Stack.md Application Stack]:|
+|:[url https://projects.linuxmint.com/cinnamon/ Cinnamon]:||:12.2019:||:-:|
+
+## Text editor
+
+.table
+|=Name=||=Fully switched=||=Configuration files=|
+|:[url https://neovim.io/ neovim]:||:08.2024:||:[url https://gitlab.com/Syndamia/anderson/ anderson]:|
+|:[url https://www.vim.org/ vim]:||:10.2020:||:[url https://gitlab.com/Syndamia/dotfiles/-/tree/main/.vim dotfiles]:|
+|:[url https://en.wikipedia.org/wiki/Atom_%28text_editor%29 Atom]:||:05.2020 - 07.2020:||:Switched back after:|
+|:[url https://www.monodevelop.com/ Monodevelop]:||:01.2020:||:-:|
+|:[url https://visualstudio.microsoft.com/ Visual Studio 2017]:||:11.2018:||:-:|
diff --git a/src/setup/index.md b/src/setup/index.md
deleted file mode 100644
index 8e19e8f..0000000
--- a/src/setup/index.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Setup
-
-Everyone that is really interested in technology has custom configurations for everything they use.
-Here are mine.
-
-## Hardware I own
-
-|Designation|OS |Motherboard / device|CPU|GPU|RAM|
-|-----------|---|------------------|---|---|---|
-|Main desktop tower|NixOS (24.11)|ASRock B550 Phantom Gaming 4|[AMD Ryzen 9 5900X](https://www.amd.com/en/products/processors/desktops/ryzen/5000-series/amd-ryzen-9-5900x.html)|[AMD Radeon RX 6800 XT](https://www.amd.com/en/products/graphics/desktops/radeon/6000-series/amd-radeon-rx-6800-xt.html)|1x Corsair CMK32GX4M2E3200C16|
-|||Bought: 2024|[39125 mark](https://www.cpubenchmark.net/cpu.php?cpu=AMD+Ryzen+9+5900X&id=3870), 12 cores, 24 threads, 3.70 GHz, L1: 768 KB, L2: 6 MB, L3: 64 MB, 64-bit|[25027 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+RX+6800+XT&id=4312), 2000 MHz, 16 GB memory|DDR4, 32 GB (2x 16GB), 3200 MHz|
-|Old desktop tower|NixOS (24.05)|ASRock Z97 Anniversary|[Intel Core i3-4160](https://www.intel.com/content/www/us/en/products/sku/77488/intel-core-i34160-processor-3m-cache-3-60-ghz/specifications.html)|AMD Sapphire Radeon R7 265|2x Corsair CMV8GX3M1A1600C11|
-|||Bought: 2015|[3510 mark](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i3-4160+%40+3.60GHz&id=2317), 2 cores, 4 threads, 3.60 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit|[3849 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Radeon+HD+7850&id=323), 900 MHz, 2 GB memory|DDR3, 16 GB (2x 8GB), 1600 MHz
-|Main laptop|NixOS (24.11)|Lenovo ThinkPad X270|Intel Core i5-6300U|Intel HD Graphics 520|1x Samsung M471A2k43BB1-CRC|
-|||Bought: 2023<br>Released: 2017|[3240 mark](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i5-6300U+%40+2.40GHz&id=2609), 2 cores, 4 threads, 2.40 GHz, L1: 128 KB, L2: 512 KB, L3: 3 MB, 64-bit|[871 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Intel+HD+520&id=3255), 300 MHz|DDR4, SODIMM, 16 GB, 2133 MHz|
-|Second laptop|NixOS (23.05)|Lenovo Yoga S730|Intel Core i7-8565U|Intel UHD Graphics 620|2x Samsung K4EBE304EC-EGCG|
-|||Bought: 2019<br>Released: 2018|[6152 mark](https://www.cpubenchmark.net/cpu.php?cpu=Intel+Core+i7-8565U+%40+1.80GHz&id=3308), 4 cores, 8 threads, 4.60 GHz, L1: 128 KB, L2: 1 MB, L3: 8 MB, 64-bit|[1039 mark](https://www.videocardbenchmark.net/gpu.php?gpu=Intel+UHD+Graphics+620&id=3805), 300 MHz|LPDDR3 (soldered), 16 GB, 2133 MHz|
-<!--
-|Main smartphone|Fresh Android ROM|Samsung Galaxy A50|
-|Old smartphone|?|Samsung Galaxy A5 (2016)
-|Old smartphone|Android ?|Samsung ?
-|Retro PC|Windows 98 SE|?|Intel Pentium ?|GeForce GTX 100|256 MB
-|Retro laptop|Dell ?
-|VPS|?
--->
-
-*Yes, I stole the idea for this from [Haelwenn Monnier](https://hacktivis.me/about)*
-
-## OS setup
-
-|Distro|Fully switched|Configuration files/scripts|
-|------|--------------|-------------|
-|**Desktop OS**|||
-|NixOS|11.2023|[NixOS configuration](https://gitlab.com/Syndamia/nix)
-|Gentoo|03.2023|[portage configuration files](https://gitlab.com/Syndamia/dotfiles/-/tree/main/.b/etc/portage), [Installation Makefile](https://gitlab.com/Syndamia/application-setup/-/blob/main/gentoo/Makefile)
-|Funtoo|12.2021|[portage configuration files](https://gitlab.com/Syndamia/dotfiles/-/tree/ef18469c90c8e90d3db436a1a204aec5c92cac73/.b/etc/portage)
-|Fedora 33-34|12.2020|[Installation from Minimal](https://gitlab.com/Syndamia/application-setup/-/blob/main/scratch-fedora-setup.sh), [Installation from Cinnamon](https://gitlab.com/Syndamia/application-setup/-/blob/main/fedora-setup.sh), [Cinnamon setup](https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup), [openbox setup](https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/fedora-openbox.sh)
-|Linux Mint 19.3-20|01.2020|[Installation script](https://gitlab.com/Syndamia/application-setup/-/blob/main/linux-mint-setup.sh), [Cinnamon setup](https://gitlab.com/Syndamia/application-setup/-/tree/main/cinnamon-setup)
-|Manjaro Cinnamon 18.1.4-18.1.5|12.2019|-|
-|**Server OS**|||
-|Debian 10|06.2021|-|
-|Ubuntu 20.04 LTS|07.2020|-|
-
-[Dotfiles here](https://gitlab.com/Syndamia/dotfiles).
-Primary shell is [zsh](https://www.zsh.org/).
-
-### Desktop environment
-
-|Name|Fully switched|List of apps|
-|----|--------------|------------|
-|[openbox wm](http://openbox.org/wiki/Main_Page) + custom apps|06.2021|[Application Stack](https://gitlab.com/Syndamia/dotfiles/-/blob/main/.c/Application%20Stack.md)
-|[Cinnamon](https://projects.linuxmint.com/cinnamon/)|12.2019|-|
-
-## Text editor
-
-|Name|Fully switched|Configuration files|
-|----|--------------|-------------------|
-|[neovim](https://neovim.io/)|08.2024|[anderson](https://gitlab.com/Syndamia/anderson/)|
-|[vim](https://www.vim.org/)|10.2020|[dotfiles](https://gitlab.com/Syndamia/dotfiles/-/tree/main/.vim)|
-|[Atom](https://en.wikipedia.org/wiki/Atom_%28text_editor%29)|05.2020 - 07.2020|Switched back after|
-|[Monodevelop](https://www.monodevelop.com/)|01.2020|-
-|[Visual Studio 2017](https://visualstudio.microsoft.com/)|11.2018|-
diff --git a/src/slides.du b/src/slides.du
new file mode 100644
index 0000000..35a9ddd
--- /dev/null
+++ b/src/slides.du
@@ -0,0 +1,17 @@
+# Slides
+
+These are the different presentations I've made and possibly presented.
+
+\n
+
+#### *[2023]*
+
+.defs
+; [$gb] 19 Jan &emsp; [url ./linuxgraphy-by-strabo Linuxgraphy by Strabo] &emsp; *[Last presented: 22.01.2023]*
+: A presentation talking about some of the history of UNIX and how Linux works
+
+#### *[2022]*
+
+.defs
+; [$gb] 27 Sep &emsp; [url ./demo Demo presentation] &emsp; *[Won't be presented]*
+: Showcase of my presentation system
diff --git a/src/slides.md b/src/slides.md
deleted file mode 100644
index 0a23cca..0000000
--- a/src/slides.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Slides
-
-These are the different presentations I've made and possibly presented.
-
-<br>
-
-#### *2023*
-
-&.gb 19 Jan &emsp; [Linuxgraphy by Strabo](./linuxgraphy-by-strabo) &emsp; *Last presented: 22.01.2023*
-: A presentation talking about some of the history of UNIX and how Linux works
-
-#### *2022*
-
-&.gb 27 Sep &emsp; [Demo presentation](./demo) &emsp; *Won't be presented*
-: Showcase of my presentation system
diff --git a/src/slides/demo/index.du b/src/slides/demo/index.du
new file mode 100644
index 0000000..fe71321
--- /dev/null
+++ b/src/slides/demo/index.du
@@ -0,0 +1,216 @@
+# Demo presentation
+
+'define expected-reading 6 min
+'define created 27 September 2022
+'define edited 22 February 2023
+[$pagenav]
+
+This is a small presentation, explaining how my custom system for making presentations works.
+
+.important
+This page is [url /rework.html due for rework], I've switched to dunbar from ftags (and MEL)
+
+[$presentation-controller]
+
+:title_slide35
+
+# My presentation system
+
+.font18 *[Syndamia AT [url https://syndamia.com syndamia.com]]*
+
+.p
+Before we go any further, click the =[icon in the middle]= right above this rectangle, to the left.
+
+.p
+Now the presentation should fill out the entire page. On the bottom right are your controls.
+
+.p
+Press the *[right arrow]* in the controls to go to the next slide.
+
+
+:slide27
+
+# Key bindings
+
+[$br3]
+
+.table
+|=Action =||=Keyboard keys =|
+|:Go to previous slide:||:Backspace, Page up, Left arrow, Up arrow :|
+|:Go to next slide :||:Space, Enter, Page down, Right arrow, Down arrow:|
+|:Toggle presenting :||:P, T :|
+|:Stop presenting :||:Esc :|
+|:Go to first slide :||:Home :|
+|:Go to last slide :||:End :|
+
+
+:slide
+
+# Introduction
+
+[$br1]
+
+.p
+I created a simple system for making presentations with slides in them.
+The gist of it is: different [url https://en.wikipedia.org/wiki/Markdown Markdown] paragraphs are put into a rectangle, each rectangle representing a slide, with some added options for layout and format.
+
+## ftags
+
+.p
+An ftag ([url https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/awk-edits#ftags "format tag"]) is what I call a short string of characters, that starts with two ampersands (&&).
+Each ftag is a "marker" that gets replaced by some other text (usually [url https://en.wikipedia.org/wiki/HTML HTML tags]).
+
+.p
+An easy example is the image of the Great Britain flag (part of [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/awk-edits/Flags.awk Flags.awk], not the presentation system!): typing out &&GB (in lowecase), gets replaced by the actual image - &&gb.
+
+
+:slide
+
+## Why?
+
+:unordered
+- Programs like Microsoft PowerPoint and LibreOffice Impress have very poor compatibility, between programs, versions, languages and even operating systems.
+ A web-based solution is significantly more consistent and flexible.
+
+- Ideally, the system would be made well enough that creating a presentation would be significantly faster than with one of those.
+
+- Making my own system means I can tailor it to my needs and preferences.
+ Looking around other [url https://gist.github.com/vasilisvg/1611562 HTML-based presentation tools]:
+
+ .bulleted
+ - [url https://revealjs.com/ reveal.js] is way too heavy and fancy for my needs (animations are nice, but I'm fine going without them)
+ - [url https://paulrouget.com/dzslides/ DZSlides] and [url https://meyerweb.com/eric/tools/s5/ S5] are really nice, however both are HTML-centric, and I want my slides to be written in Markdown.
+ Creating ftags that are transformed to DZSlide HTML is possible, but at that point I should just make my own system.
+ - and pretty much everything else falls into either category
+
+
+
+:slide
+
+# Formatting
+
+.p
+Every (presentation-specific) ftag is listed and explained in [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/awk-edits/Presentation.awk Presentation.awk].
+To summarize, each slide is wrapped in `[&&slide]` and `[&&/slide]` (or `[&&clide]` and `[&&/clide]`), you can change font size for specific portions, you can add basic (without formatting) tables for fancy layout, you can align text and elements and you can add line breaks.
+
+.p
+And they can work together in most different combination.
+
+[$br1]
+
+.p
+Though, remember that everything gets translated to HTML, so don't do (even if it works)
+
+```
+&&slide &&font20 &&/slide &&/font
+
+.p
+Enough talking, here are examples!
+
+
+:slide
+
+.font18 Font-size 18px
+
+.font20 Font-size 20px
+
+.font22 Font-size 22px
+
+.font25 Font-size 25px
+
+Font-size 30px (default)
+
+.font35 Font-size 35px
+
+[$br5]
+
+.fright
+This text is floated to the right
+
+[$br2]
+
+.centered While this one is centered
+
+[$br2]
+
+.fright Floated right\nFloated right\nFloated right
+
+.p
+But you may realize that text floated to the right will make other text wrap around it!
+Maybe this should be changed?
+
+
+:slide18
+
+.p
+The source Markdown for the predvious slide is:
+
+```dunbar
+'snippet 111 142 ./index.du
+
+
+:middle_slide
+
+:row
+ You can also easily tabularize
+
+ .column
+ .fright
+ .bulleted
+ - List Element 1
+ - List Element 2
+
+ [$newrow]
+
+ .p
+ =[any]= sort of content
+
+
+[$br1]
+
+:sqrow
+ .p
+ So you can very easily put images next to your text
+
+ .centered [image /tutorials/fix-no-frame-buffer-plan9/img/rio-default-login.png]
+
+
+
+:slide18
+
+.p
+The source Markdown for the predvious slide is:
+
+```dunbar
+'snippet 152 178 ./index.du
+
+
+:slide27
+
+# Other features
+
+.p
+As you've obviously noticed, the presentation "system" also adds a navigation bar, with which to present and navigate slides.
+You can also print very easily the whole presentation on A4 sheets of paper, since that's the exact size of each slide.
+
+.p
+Pretty much all other website functionalities, like themes and click-to-zoom images, aren't inhibited.
+The slides are easily scrollable/browseable and if you don't have JavaScript enabled, everything will be shown as a normal(-ish) article, without any *[major]* styling issues.
+
+## Setup
+
+.p
+Everything is contained in 3 files: [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/awk-edits/Presentation.awk Presentation.awk], [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/src/scripts/presentation.js presentation.js] and [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/src/presentation.css presentation.css], which pretty much work on your "compiled" HTML.
+
+.p
+`[Presentation.awk]` handles replacement of ftags (only in `[/talks]` pages!).
+`[presentation.js]` is inserted into the HTML by `[&&presentation]`, and handles the navigation bar as well as insertion of `[presentation.css]` (the overall presentation-specific styling).
+
+
+:title_slide
+
+# Thats All. Thank you for your time!
+
+.fright
+.font18
+*[P.S. Press the same button (next to the print button) with which you started presenting, to stop presenting ;)]*
diff --git a/src/slides/demo/index.md b/src/slides/demo/index.md
deleted file mode 100644
index c9e26de..0000000
--- a/src/slides/demo/index.md
+++ /dev/null
@@ -1,265 +0,0 @@
-# Demo presentation
-
-This is a small presentation, explaining how my custom system for making presentations works.
-
-&:important This page is [due for rework](/rework.html), I've switched to MEL from ftags
-
-&.presentation
-
-&[title35
-
-# My presentation system
-&(font18 *Syndamia AT [syndamia.com](https://syndamia.com)* &)
-
-Before we go any further, click the **icon in the middle** right above this rectangle, to the left.
-
-Now the presentation should fill out the entire page. On the bottom right are your controls.
-
-Press the *right arrow* in the controls to go to the next slide.
-
-&]
-
-
-
-&[slide27
-
-# Key bindings
-
-&.br3
-
-|Action |Keyboard keys |
-|--------------------|-------------------------------------------------|
-|Go to previous slide| Backspace, Page up, Left arrow, Up arrow |
-|Go to next slide | Space, Enter, Page down, Right arrow, Down arrow|
-|Toggle presenting | P, T |
-|Stop presenting | Esc |
-|Go to first slide | Home |
-|Go to last slide | End |
-
-&]
-
-
-
-&[slide
-
-# Introduction
-
-&.br1
-
-I created a simple system for making presentations with slides in them.
-The gist of it is: different [Markdown](https://en.wikipedia.org/wiki/Markdown) paragraphs are put into a rectangle, each rectangle representing a slide, with some added options for layout and format.
-
-## ftags
-
-An ftag (["format tag"](https://gitlab.com/Syndamia/syndamiadotcom/-/tree/master/awk-edits#ftags)) is what I call a short string of characters, that starts with two ampersands (&&).
-Each ftag is a "marker" that gets replaced by some other text (usually [HTML tags](https://en.wikipedia.org/wiki/HTML)).
-
-An easy example is the image of the Great Britain flag (part of [Flags.awk](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/awk-edits/Flags.awk), not the presentation system!): typing out &&GB (in lowecase), gets replaced by the actual image - &&gb.
-
-&]
-
-
-
-&[slide
-
-## Why?
-
-- Programs like Microsoft PowerPoint and LibreOffice Impress have very poor compatibility, between programs, versions, languages and even operating systems.
- A web-based solution is significantly more consistent and flexible.
-
-- Ideally, the system would be made well enough that creating a presentation would be significantly faster than with one of those.
-
-- Making my own system means I can tailor it to my needs and preferences.
- Looking around other [HTML-based presentation tools](https://gist.github.com/vasilisvg/1611562):
- + [reveal.js](https://revealjs.com/) is way too heavy and fancy for my needs (animations are nice, but I'm fine going without them)
- + [DZSlides](https://paulrouget.com/dzslides/) and [S5](https://meyerweb.com/eric/tools/s5/) are really nice, however both are HTML-centric, and I want my slides to be written in Markdown.
- Creating ftags that are transformed to DZSlide HTML is possible, but at that point I should just make my own system.
- + and pretty much everything else falls into either category
-
-&]
-
-
-
-&[slide
-
-# Formatting
-
-Every (presentation-specific) ftag is listed and explained in [Presentation.awk](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/awk-edits/Presentation.awk).
-To summarize, each slide is wrapped in `&&slide` and `&&/slide` (or `&&clide` and `&&/clide`), you can change font size for specific portions, you can add basic (without formatting) tables for fancy layout, you can align text and elements and you can add line breaks.
-
-And they can work together in most different combination.
-
-&.br1
-
-Though, remember that everything gets translated to HTML, so don't do (even if it works)
-
-```
-&&slide &&font20 &&/slide &&/font
-```
-
-Enough talking, here are examples!
-
-&]
-
-
-
-&[slide
-
-&(font18 Font-size 18px &)
-&(font20 Font-size 20px &) &(font22 Font-size 22px &) &(font25 Font-size 25px &)
-Font-size 30px (default)
-&(font35 Font-size 35px &)
-
-&.br5
-
-&(fright
-This text is floated to the right
-&)
-
-&.br2
-
-&(centered While this one is centered &)
-
-&.br2
-
-&(fright Floated right<br>Floated right<br>Floated right &)
-
-But you may realize that text floated to the right will make other text wrap around it!
-Maybe this should be changed?
-
-&]
-
-
-
-&[slide18
-
-The source Markdown for the predvious slide (without the pipes to the left) is:
-
-```
-&&slide
-
-&&font18 Font-size 18px &&/font
-&&font20 Font-size 20px &&/font &&font22 Font-size 22px &&/font &&font25 Font-size 25px &&/font
-Font-size 30px (default)
-&&font35 Font-size 35px &&/font
-
-&&lineb5
-
-&&fright
-This text is floated to the right
-&&/fright
-
-&&lineb2
-
-&&centered While this one is centered &&/centered
-
-&&lineb2
-
-&&fright Floated right<br>Floated right<br>Floated right &&/fright
-
-But you may realize that text floated to the right will make other text wrap around it!
-Maybe this should be changed?
-
-&&/slide
-```
-
-&]
-
-
-
-&[middle &{row
-
-You can also easily tabularize
-
-&{column &(fright
-
-- List Element 1
-- List Element 2
-
-&) &}
-
-&.newrow
-
-**any** sort of content
-
-&}
-
-&.br1
-
-&{sqrow
-
-So you can very easily put images next to your text
-
-&(centered ![](/tutorials/fix-no-frame-buffer-plan9/img/rio-default-login.png =120x) &)
-
-&} &]
-
-
-
-&[slide18
-
-The source Markdown for the predvious slide (without the pipes to the left) is:
-
-```
-&&clide &&table
-
-You can also easily tabularize
-
-&&cont &&fright
-
-- List Element 1
-- List Element 2
-
-&&/fright &&/cont
-
-&&tarow
-
-**any** sort of content
-
-&&/table
-
-&&lineb1
-
-&&ftable
-
-So you can very easily put images next to your text
-
-&&centered ![](/tutorials/fix-no-frame-buffer-plan9/img/rio-default-login.png =120x) &&/centered
-
-&&/table &&/clide
-```
-
-&]
-
-
-
-&[slide27
-
-# Other features
-
-As you've obviously noticed, the presentation "system" also adds a navigation bar, with which to present and navigate slides.
-You can also print very easily the whole presentation on A4 sheets of paper, since that's the exact size of each slide.
-
-Pretty much all other website functionalities, like themes and click-to-zoom images, aren't inhibited.
-The slides are easily scrollable/browseable and if you don't have JavaScript enabled, everything will be shown as a normal(-ish) article, without any *major* styling issues.
-
-## Setup
-
-Everything is contained in 3 files: [Presentation.awk](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/awk-edits/Presentation.awk), [presentation.js](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/src/scripts/presentation.js) and [presentation.css](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/master/src/presentation.css), which pretty much work on your "compiled" HTML.
-
-`Presentation.awk` handles replacement of ftags (only in `/talks` pages!).
-`presentation.js` is inserted into the HTML by `&&presentation`, and handles the navigation bar as well as insertion of `presentation.css` (the overall presentation-specific styling).
-
-&]
-
-
-
-&[title
-
-# Thats All. Thank you for your time!
-
-&(fright &(font18
-*P.S. Press the same button (next to the print button) with which you started presenting, to stop presenting ;)*
-&) &)
-
-&]
diff --git a/src/slides/index.du b/src/slides/index.du
new file mode 100644
index 0000000..35a9ddd
--- /dev/null
+++ b/src/slides/index.du
@@ -0,0 +1,17 @@
+# Slides
+
+These are the different presentations I've made and possibly presented.
+
+\n
+
+#### *[2023]*
+
+.defs
+; [$gb] 19 Jan &emsp; [url ./linuxgraphy-by-strabo Linuxgraphy by Strabo] &emsp; *[Last presented: 22.01.2023]*
+: A presentation talking about some of the history of UNIX and how Linux works
+
+#### *[2022]*
+
+.defs
+; [$gb] 27 Sep &emsp; [url ./demo Demo presentation] &emsp; *[Won't be presented]*
+: Showcase of my presentation system
diff --git a/src/slides/index.md b/src/slides/index.md
deleted file mode 100644
index 0a23cca..0000000
--- a/src/slides/index.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Slides
-
-These are the different presentations I've made and possibly presented.
-
-<br>
-
-#### *2023*
-
-&.gb 19 Jan &emsp; [Linuxgraphy by Strabo](./linuxgraphy-by-strabo) &emsp; *Last presented: 22.01.2023*
-: A presentation talking about some of the history of UNIX and how Linux works
-
-#### *2022*
-
-&.gb 27 Sep &emsp; [Demo presentation](./demo) &emsp; *Won't be presented*
-: Showcase of my presentation system
diff --git a/src/slides/linuxgraphy-by-strabo/index.du b/src/slides/linuxgraphy-by-strabo/index.du
new file mode 100644
index 0000000..1e7dfb1
--- /dev/null
+++ b/src/slides/linuxgraphy-by-strabo/index.du
@@ -0,0 +1,1420 @@
+# Linuxgraphy by Strabo
+
+'define expected-reading 38 min
+'define created 19 January 2023
+'define edited 04 March 2023
+[$pagenav]
+
+### Custom assets
+
+*[Licensing information in the last slide, at the bottom of the page]*
+
+.bulleted
+- [url ./img/unix-layers.png UNIX layers image]
+- [url ./img/unix-dir-tree.png UNIX directory tree]
+- [url ./mll-set.sh mll-set.sh]
+
+### Presented at
+
+:defs
+; [$bg] Unofficial [url https://fmi.uni-sofia.bg/en FMI] Computer Science Discord server &emsp; *[04.03.2023 || 14:50 - 17:20]*
+: In front of a tiny audience of other uni students. Exact revision [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/6feed223ff48fe00cf12fcd63f3f56179c298cae/src/talks/linuxgraphy-by-strabo/index.md here].
+
+; [$bg] Unofficial [url https://fmi.uni-sofia.bg/en FMI] Computer Science Discord server &emsp; *[22.01.2023 || 18:00 - 21:00]*
+: In front of a tiny audience of other uni students. Exact revision [url https://gitlab.com/Syndamia/syndamiadotcom/-/blob/6eb7a8fff01c6814253a0e738efb53734d297be9/src/talks/linuxgraphy-by-strabo/index.md here].
+
+
+[$presentation-controller]
+
+:title_slide
+
+# Linuxgraphy by Strabo
+
+*[Made by [url https://syndamia.com Syndamia]]*
+
+[$br4]
+
+:sqrow
+ [$br1]
+
+ :font22
+ 2000 years ago [url https://en.wikipedia.org/wiki/Strabo Strabo] published [url https://en.wikipedia.org/wiki/Geography Geography], in which he laid out the world as it was known to the Romans and Greeks.
+
+ [$br1]
+
+ Today, I'll lay out Linux as it is known to me.
+
+
+ [image https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Strabo.jpg/199px-Strabo.jpg]
+
+ [$br1]
+
+
+
+:slide35
+
+# Contents
+
+:sqrow
+ :column
+ :numbered
+ 1. Historical context
+ 2. Structure of UNIX-likes
+ .numbered
+ 1. Shell
+ 2. UNIX-style file system
+ 2. Kernel
+
+ [$br2]
+
+ 3. Linux from the inside
+ .numbered
+ 1. Shells
+ 2. Files and directories
+ 3. Common configuration files
+ 4. System management
+
+ 4. Software licensing
+
+
+
+ :column
+ :numbered
+ 5. What makes up a useful OS
+ .numbered
+ 1. Bootloader
+ 2. Init system
+ 3. Package manager
+ 4. Desktop manager
+
+ 6. War on distros
+ [$br4]
+
+ 7. Demos - virtual machine and setup from zero
+
+
+
+
+
+:slide
+
+# 1. Historical context
+
+[$br1]
+
+#### 1945 - 1955
+
+.p
+You directly loaded instructions into memory and let it execute your "code" (processor instructions).
+Nothing else ran on the machine.
+
+.p
+This process was labor intensive: a qualified operator loaded your program, dumped the memory contents, remove any external media, reset the machine and load the next job.
+
+#### 1956 - 1959
+
+.p
+Computers became faster, but a lot of time was spend on managing jobs.
+
+.p
+[url https://en.wikipedia.org/wiki/Resident_monitor resident monitors]: very small programs, which always *[resided]* in memory, and *[monitored]* what the state of the current job was.\n
+Jobs were loaded in series ([url https://en.wikipedia.org/wiki/Batch_processing batches]).
+When the current job finished, memory would be dumped and the next one would automatically be loaded and started.
+
+
+:slide
+
+#### 1960s
+
+[$br1]
+
+.p
+Peripherals (tapes, punch cards, ...) were extremely slow.\n
+[url https://en.wikipedia.org/wiki/Computer_multitasking#Multiprogramming Multiprogramming]: the current job is waiting for a peripheral, another job would be started.
+
+.p
+[url https://en.wikipedia.org/wiki/Sabre_%28travel_reservation_system%29 Travel reservation system] by American Airlines: where travel agents would search, price and book services.
+A computer system now had to support:
+
+.bulleted
+- User accounts with concurrent access
+- Fast response time and ease of use
+- Storage organization, also following the rise of disks
+- Data communication links (often phone lines)
+
+[$br1]
+
+.p
+More and more business started using computers, thanks to [url https://en.wikipedia.org/wiki/Minicomputer minicomputers], so demand for OS software increased.
+
+
+:slide
+
+#### 1964 - 1969
+
+.p
+IBM's [url https://en.wikipedia.org/wiki/IBM_System/360 System/360] line of computers, each with expansion capabilities, backwards compatibility, all under one instruction set and operating system.
+
+.p
+[url https://en.wikipedia.org/wiki/Multics Multics], an influential operating system that was designed for a General Electric mainframe.
+Some of it's novel ideas include, but are not limited to:
+
+:bulleted
+- [url https://en.wikipedia.org/wiki/Time-sharing Time-sharing]:
+ sharing resources of a singular machine among many users
+ (via [url https://en.wikipedia.org/wiki/Multiprogramming multiprogramming] and [url https://en.wikipedia.org/wiki/Computer_multitasking multi-tasking])
+
+- [url https://en.wikipedia.org/wiki/Single-level_store Single level store] (aka [url https://en.wikipedia.org/wiki/Virtual_memory virtual memory]):
+ Processes would write into contiguous memory, but in reality it is scattered and managed by the operating system.
+
+- [url https://en.wikipedia.org/wiki/Protection_ring Protection rings]:
+ Allowing different levels of access to different resources (programs).
+ In general, this also often requires a [url https://en.wikipedia.org/wiki/Protected_mode CPU protected mode].
+
+- [url https://en.wikipedia.org/wiki/Directory_%28computing%29 Hierarchical file system]:
+ Arbitrary directories with subdirectories, rather than just having files next to each other or having directories which could only contain files.
+- [url https://en.wikipedia.org/wiki/Shell_%28computing%29 Command processor] (that is separated from the OS):
+ More on that later
+
+
+
+:slide
+
+#### 1969: Death of Multics and birth of UNIX
+
+.p
+Ultimately Multics grew too large, becoming unusable and unmaintainable.\n
+In the beginning, programming was done mostly by [url https://en.wikipedia.org/wiki/Bell_Labs Bell Labs], with [url https://en.wikipedia.org/wiki/Ken_Thompson Ken Thompson] being one of the developers.
+
+[$br1]
+
+:sqrow
+ .font18
+ [image https://upload.wikimedia.org/wikipedia/commons/f/f8/Ken-Thompson-2019.png]\n
+ *[Ken Thompson image by National Inventors Hall of Fame]*
+ [image https://upload.wikimedia.org/wikipedia/commons/1/1b/Ken_Thompson_and_Dennis_Ritchie--1973.jpg ]\n
+ *[Ken Thompson and Dennis Ritchie in 1973]*
+
+ :column
+ .p
+ Thompson still had some desire to work on operating systems, after Bell Labs pulled out.
+ The tools he made while rewriting [url https://en.wikipedia.org/wiki/Space_Travel_%28video_game%29 his own video game] on a PDP-7 lead to a whole operating system: UNIX.
+
+ .p
+ Based, expanded on and improved upon many of Multic's ideas, UNIX became the father of modern OSs.
+
+
+
+
+:slide
+
+# 2. Structure of UNIX-likes
+
+.p
+Ignoring [url https://unix.stackexchange.com/questions/14368/difference-between-posix-single-unix-specification-and-open-group-base-specifi/14415 standards] and [url https://unix.stackexchange.com/questions/87686/what-makes-an-operating-system-unix-like specifications], in my opinion, from the point of a user, a UNIX-like OS has the following components:
+
+[$br2]
+
+.ordered
+1. =[shell]=: A programmable replaceable command-line interpreter, with utilities for managing the whole system and support for pipelines and I/O redirection
+2. =[UNIX-style file system]=: [url https://en.wikipedia.org/wiki/Unix_filesystem Filesystem] as a single rooted tree, objects (nodes) in the file system are [url https://en.wikipedia.org/wiki/Inode inodes] and an inode can be [url https://en.wikipedia.org/wiki/Unix_file_types (at least)] either a regular file, directory or devices. Permissions per users and group.
+3. =[kernel]=: Program that manages all communication and operations between the hardware and software
+
+[$br2]
+
+.font18 *[For now we'll generally just look over some of the common stuff and go into detail later, while in Linux.]*
+
+
+:slide35
+
+## 2.1. shell
+
+[$br1]
+
+:sqrow
+ :column
+ The operating system is divided into layers, [url https://youtu.be/-FtCTW2rVFM?t=57 like an onion].\n
+ Only the kernel has access to the hardware.\n
+ shells and executables (binaries) have access to the kernel.
+
+ .p
+ shells provide user interfaces, [url http://en.wikipedia.org/wiki/Shell_%28computing%29 both] command-line and graphical.
+ While on the topic of UNIX, we'll only discuss the former.
+
+
+ .centered [image ./img/unix-layers.png]
+
+
+
+:slide
+
+### Command-line shells
+
+.p
+Command-line shells operate solely with text, often only with ASCII characters.
+Usually connecting to a computer (to the shell) is said to be done with either a "terminal" ("console") or "teleprinter" ("teletype").
+
+:row
+ .p
+ Video displays became widely available in the late 1970s, so before that access was done with a "teleprinter", a typewriter-printer combo.
+
+ .width25%
+ .font18
+ [image https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/ASR-33_at_CHM.agr.jpg/1280px-ASR-33_at_CHM.agr.jpg]\n
+ *[Teletype Model 33 by [url https://commons.wikimedia.org/wiki/User:ArnoldReinhold Arnold Reinhold]]*
+
+ [$newrow]
+
+ .p
+ With the advent of computer displays, teleprinters were replaced with terminals, video display-keyboard combo.
+ Thanks to the widely popular [url https://en.wikipedia.org/wiki/VT100 VT100], almost all terminals support [url https://en.wikipedia.org/wiki/ANSI_escape_code ANSI escape codes].
+
+ .font18
+ [image https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/DEC_VT100_terminal.jpg/675px-DEC_VT100_terminal.jpg?20131106192408]\n
+ *[DEC VT100 by [url https://www.flickr.com/people/54568729@N00 Jason Scott]]*
+
+
+
+:slide
+
+.p
+Today we don't usually use such specialised hardware, but the names persist with slightly different meanings.
+
+.p
+[url https://en.wikipedia.org/wiki/Virtual_console Virtual Terminal] (Console, tty): on some modern UNIX-likes (like Linux), the kernel/OS provides special devices, where a console is directly implemented/simulated with the connected computer and display.
+
+.bulleted
+- systems that don't provide it usually expose another way to connect a console (now external hardware and/or software is required), like a [url https://en.wikipedia.org/wiki/Serial_port serial] port
+
+.p
+[url https://en.wikipedia.org/wiki/Terminal_emulator Terminal Emulator]: a special program that emulates a virtual terminal (within another display system)
+
+.p
+[url https://en.wikipedia.org/wiki/Pseudoterminal Pseudoterminal] (pty): a program that sits between a terminal and a shell (or other program), and makes them both think they're directly connected
+
+.bulleted
+- ssh, a program to remotely connect to a device's shell, establishes a pseudoterminal. Your local terminal thinks it's connected to a local shell and vice versa with the remote shell, however the pty in between handles the true communication.
+
+
+:middle_slide
+
+### Command location and parameters
+
+.p
+Most commands are regular programs, which exist somewhere on the system.
+When entering a command name, the shell searches for an executable with that name.
+Searching the whole drive is very inefficient, so the search is limited to the few directories, listed in a variable called "PATH".
+
+.p
+You can give a full or relative path, and that will be executed directly.
+
+.p
+Each command can be given parameters, separated by spaces, each (by convention) being either text values or options (switches).
+
+.p
+Options usually start with a hyphen `[-]` (like `[-c]` or `[-current-time]`) and often support abbreviations (`[-a -b -c]` to `[-abc]`).
+Newer conventions also allow start with two hyphens `[--]` (`[--current-time]`), though if shown as-is indicate the rest is a string.
+More rarely you might see `[--OPTION=VALUE]` or just `[OPTION=VALUE]`.
+
+
+:middle_slide
+
+### Thompson shell
+
+.p
+The first UNIX shell is the [url https://en.wikipedia.org/wiki/Thompson_shell Thompson shell].
+The two major features that every other shell supports are:
+
+:bulleted
+- I/O redirection: redirection of input and output, allowing insertion of input from a file or storage of output into a file:
+
+ ```
+command [args...] < filepath
+command [args...] > filepath
+
+- pipelines: being able to redirect the output from one command to another without limit
+
+ ```
+command1 [args...] | command2 [args...] | ...
+
+
+
+:slide
+
+## 2.2. UNIX-style file system
+
+.bulleted
+- Rooted singular tree of directories (the root folder of which is called "root", denoted with a "/")
+- Each tree object (node) is an [url https://en.wikipedia.org/wiki/Inode i(ndex)node], containing type, ownership, access, internal data and any other metadata, but =[not]= name!
+- Directory inodes (files) contain a table with rows of names and inode numbers, mapping a file name to it's contents. Each row is called a [url https://en.wikipedia.org/wiki/Hard_link hard link]. Every directory has a hard link to itself, called ".", and a hard link to it's parent, called "..".
+
+.p [image ./img/unix-dir-tree.png ]
+
+
+:middle_slide
+
+### Attributes of an inode
+
+:bulleted
+- [url https://en.wikipedia.org/wiki/Unix_file_types file type]:
+ Each inode represents some sort of file (data), but a "file" can also be a directory or device, so we need to know how to handle it.\n
+ There are 7 main types (but there can exist more, depending on OS):
+
+ [$br2]
+
+ .bulleted
+ - =[regular]=: just a plain old file
+ - =[directory]=: as explained, a file containing hard links to other files. Each directory is allowed to appear *[only once]* in a single parent.
+ - =[symbolic link]=: points to any file (or directory). It contains the (relative) path to that object (as a simple string), so a symlink not could even be valid.
+ Think of a C++ pointer (pseudocode).
+
+ ```
+symlink /bin/mprog = "/usr/local/bin/mprog";
+exec(/bin/mprog); -> Executes /usr/local/bin/mprog
+
+
+
+:slide
+:bulleted
+ - =[FIFO special]=: aka [url https://en.wikipedia.org/wiki/Named_pipe named pipe], a special type of regular file, where at any moment only one process can read from it and one can write to it. It takes the concept of shell pipes to inter-process communication.
+
+ ```
+[Process] --write-> [FIFO] x-write-- [Process]
+[ A ] x--read-- [ ] --read--> [ B ]
+
+ - =[block special]=: a device which is randomly accessible, like a hard drive or cdrom drive.
+ Think of a C++ array (pseudocode):
+
+ ```
+BlockSpecial[438] = 1 ; var = BlockSpecial[438]
+
+ - =[character special]=: devices which are accessed via serial streams of input or output, like keyboards, mice, graphics cards and teletypes.\n
+ Think of a C++ stream (pseudocode):
+
+ ```
+CharacterSpecial << 1 ; CharacterSpecial >> var
+
+
+
+:middle_slide
+:bulleted
+ - =[sockets]=: file for inter-process communication. Compared to FIFO specials, they can be used by more than two processes, used in both directions and support [url https://en.wikipedia.org/wiki/File_descriptor file descriptors] and packets
+
+ [$br1]
+
+ ```
+[Process A] <--read&write--> [Socket 1]
+[Process B] <--read&write--> [Socket 1]
+...
+[Process A] --write--> [Socket 1] --read--> [Process B]
+ --read--> [Process C]
+
+
+
+:slide
+
+#### Side-step into users and groups
+
+[$br3]
+
+.p
+A user in UNIX is essentially a small collection of data, most important of it being a =[unique ID]= (number), a =[name]= (string), a =[group id]= (number; files created by the user are in that group) and a =[password]=.
+
+.p
+Groups are also small collections of data, but much simpler, comprised only of a =[unique ID]= (number), a =[name]= (string) and a =[list of users]= that are "in" the group. Their main purpose is to simplify access control.
+
+.p
+User with ID 0 is called root, it is the "system administrator", all actions made by the system itself are done as that user.
+Every user has their own "home" folder (under "/home/USERNAME/", except for root, which is "/root/"), in which they store personal files, as well as user-specific configuration files.
+
+
+:slide
+:bulleted
+- [url https://en.wikipedia.org/wiki/File_system_permissions file permissions]:
+ control the freedom of a user to read (navigate for directories), change and execute files\n
+
+ File permissions are split into three sets: what the =[owner]= can do, what =[group]= members can do and what =[anyone else]= can do.\n
+
+ Each set contains a mix of three permissions: =[r]=ead, =[w]=rite and e=[x]=ecute, and each set stores some combination of them.
+
+ [$br1]
+
+ .p
+ Each is represented by a bit in the order above (`[101]` means you *[can]* read, *[cannot]* write, *[can]* execute) and the overall permissions are often shown as a three digit number or character string.\n
+ Example: `[111101100]` will be shown as `[754]` or `[rwxr-xr--]`
+
+- link count:
+ the count of hard links that point to the inode. A file is deleted =[only when there are no hard links left to it]=.
+ Every directory inode has at least two - one from parent and one from itself ("."), though the latter =[isn't]= counted.
+ Child and parent directories also =[add]= to the count.
+
+ [$br1]
+
+- User ID of owner, Group ID, file size and timestamps
+
+
+
+:slide
+
+## 2.3. Kernel
+
+.font18
+[$br1]
+
+.p
+The kernel has the core functionality of the operating system and bridges the gap between programs and hardware.
+Some important subsystems include scheduling, file, device, process and memory management.
+
+.p
+To preserve the [url https://en.wikipedia.org/wiki/Everything_is_a_file everything is a file] methodology, devices and processes can be handled as files (inside `[/dev]` and `[/proc]`).
+They (most of the time, in modern kernels) aren't actual files on a hard drive, but "virtual" files, where operations on them are handled in a different manner than normal by the kernel.
+
+[$br2]
+
+.font35 Linux is =[not]= an operating system, it is a kernel!!!
+
+[$br2]
+
+.p
+Two of the important things a kernel does is manage =[processes]= and =[memory]=.
+
+
+:slide35
+
+### 2.3.1 Processes
+
+[$br1]
+
+.p
+A program is some collection of code and other data, stored in a file (or noncompiled code).\n
+A process is the program in motion, the program itself *[alongside]* certain system states.
+
+.p
+The system states include (but are not limited to):
+.bulleted
+- the processor state, including the program counter and register values
+- memory map, indicating what regions of memory are allocated (to the process)
+- [url https://en.wikipedia.org/wiki/File_descriptor file descriptors], unique identifiers for files
+
+
+:middle_slide35
+
+.p
+On a multitasking (multiprocessing) system, which is any modern desktop system, multiple processes are always running "at once".
+
+.p
+In reality, constantly one process is stopped and another is ran, switching between all of them ([url https://en.wikipedia.org/wiki/Context_switch context switching]).
+All "waiting" processes are put in a prioritized queue ([url https://en.wikipedia.org/wiki/Run_queue run queue]).
+
+.p
+Stopping is either done by the process itself (more on that later), or by the system when the process has been actively running for too much time.
+
+
+:slide35
+
+#### Process Control Block
+
+.p
+All process information is stored in a data structure, called a *[process control block]* (or process descriptor).
+Not to be confused with a [url https://en.wikipedia.org/wiki/Printed_circuit_board printed circuit board]!\n
+A PCB's data can be split into three categories:
+
+.numbered
+1. =[Process identification]= - the ID of the process itself, of it's parent process, of it's owner (user), etc.
+2. =[Process state]= - as described, the processor state, etc.\n
+ On a context switch, values in registers are put into the stopped PCB and then are loaded from the running PCB.
+3. =[Process control information]= - process state, memory map, privileges, etc.
+
+.p
+A process can be =[forked]=, meaning a new process is created, with the same underlying code (but not process states and ...).
+
+
+:middle_slide35
+
+#### Process states
+
+.bulleted
+- =[Created]=: This is the initial state given to a new process. In this state, the process awaits a "ready" state.
+- =[Ready]= (Waiting): A process is put in the run queue and awaits being executed ("running" state).
+- =[Running]=: When the process's program is being currently executed by the CPU. The process can run in either *[kernel mode]*, having access to the kernel and user addresses, or *[user mode]*, having access only to it's own code and data.
+- =[Blocked]=: When a process cannot continue without external change, usually when waiting for an I/O device.
+- =[Terminated]=: The process has either completed execution or has been killed. The process itself is called a [url https://en.wikipedia.org/wiki/Zombie_process "zombie process"] (until it is removed).
+
+
+:middle_slide35
+
+#### Exit status
+
+.p
+Every process, before being deleted (and after being in a Terminated state) passes a small number, called the [url https://en.wikipedia.org/wiki/Exit_status exit status] (exit code), to it's parent process.
+For all intents and purposes, this number is an 8bit unsigned integer, meaning it's value is between 0 and 255.
+
+.p
+Pretty much universally, an exit code of 0 signifies a successful termination, and anything else specifies some sort of error code.
+Different programs specify the meaning of an exit code in different ways, some assign each number to a specific error, other use the bits representing the number as flags.
+
+
+:slide35
+
+### 2.3.2 Memory management
+
+[$br2]
+
+.p
+In ye olde days, you would save a bit of memory for the operating system and give all of the rest to the current process ([url https://en.wiktionary.org/wiki/monoprogramming monoprogramming]), which we wait until completion.
+
+.p
+This doesn't allow for context switching (disks are slow) and a blocked state forces the CPU to wait.
+
+.p
+Some bad ideas include: depending on the code of all processes to not use the same addresses, use only [url https://en.wikipedia.org/wiki/Position-independent_code relative addresses] (`[-fPIC]` option in `[gcc]`) or use a [url https://en.wikipedia.org//wiki/Relocation_%28computing%29#Relocation_table table] that the kernel fills out with addresses.
+
+
+:slide35
+
+### Virtual memory
+
+[$br2]
+
+.fright
+ [image ./img/virtual-memory-by-Ehamberg.png]\n
+ .font18
+ *[Image by [url https://commons.wikimedia.org/wiki/File:Virtual_memory.svg Ehamberg]]*
+
+.p
+A program (process) works with some (sequential) addresses, and the OS (with the help of [url https://en.wikipedia.org/wiki/Memory_management_unit hardware]) translates/maps the process' addresses (logical/[url https://en.wikipedia.org/wiki/Virtual_address_space virtual addresses]) to real ones (physical addresses).
+
+.p
+Simplified memory management for the program, protected address space for each process and improved flexibility.
+
+
+:slide35
+
+#### Segmentation (without paging)
+
+[$br2]
+
+.p
+Initially, virtual memory was implemented with segmentation, where a process' memory is divided into segments for code, stack, heap, etc.
+Each segment is given a chunk of contiguous memory, which can be resized, and addresses are defined as the base segment (physical) address with an offset.
+
+.p
+In the modern day, segmentation isn't used by itself, since resizing segments could require reordering of memory and [url https://en.wikipedia.org/wiki/Fragmentation_%28computing%29#External_fragmentation external fragmentation], where there simply isn't enough contiguous memory, could occur.
+
+
+:slide35
+
+#### Paging
+
+[$br3]
+
+.p
+The virtual and physical memory is divided into fixed-sized chunks of consecutive addresses.
+A virtual memory chunk is called a =[page]=, while a physical memory chunk is called a (page) =[frame]=.
+Usually both have the same size of (at least) 4 KiB.
+
+.p
+Every process has a [url https://en.wikipedia.org/wiki/Page_table page table], which maps the process' pages to system frames.
+Thus every memory address is translated from it's page location to a frame location.
+
+
+:slide35
+
+.p Advantages include:
+
+.bulleted
+- elimination of [url https://en.wikipedia.org/wiki/Fragmentation_%28computing%29#External_fragmentation external fragmentation]
+- increased flexibility, allowed sharing of memory between processes (useful for shared libraries)
+- finding free memory is fast and easy, just use the first free pages you see
+- frames can be scattered
+- more efficient swapping, moving of memory from RAM to disk and back
+
+.p Disadvantages include:
+
+.bulleted
+- longer memory access, because of the page table
+- [url https://en.wikipedia.org/wiki/Fragmentation_%28computing%29#Internal_fragmentation internal fragmentation], where one or multiple pages might be partially empty, leaving free space that cannot be used
+
+
+:slide
+
+# 3. Linux from the inside
+
+.p
+Enough theory, time to have some fun and learn Linux!
+
+.p
+We'll be using [url https://ivandavidov.github.io/minimal/#home Linux Minimal Live] (just a bootable ISO) because it's:
+
+.bulleted
+- very small, comprised of only the Linux kernel, GNU C library and Busybox\n
+- made by a fellow Bulgarian [$bg]
+
+.p
+We're going to explore and look around the following stuff:
+
+.bulleted
+- =[Shells]=: What a modern shell would often support on a Linux based OS
+- =[Files and directories]=: Naming conventions and commands to work with them
+- =[Common configuration files]=: Relevant configuration files, their purpose and syntax
+- =[System management]=: Other commands with which to modify your system
+
+
+:middle_slide18
+
+#### If you're following at home
+
+.p
+Owing to it's size, not everything we need comes out of the box, so I created [url ./mll-set.sh a script] which installs what's needed.
+If you want to try it out yourself, after booting up Minimal Linux Live, type out and run:
+
+```
+wget -q http://unsecure.syndamia.com/mll-set.sh && chmod +x mll-set.sh && ./mll-set.sh
+
+.p
+You might've noticed that the command above doesn't use the normal [url ./mll-set.sh https://syndamia.com/talks/linuxgraphy-by-strabo/mll-set.sh] link.
+That is because, out of the box, MLL doesn't really support secure connections (https), so I've made only that file available without it.
+
+.p
+The script, in summary, installs bash, coreutils and shadow "packages" (from [url http://s.minos.io/archive/bifrost/x86_64 http://s.minos.io/archive/bifrost/x86\_64]) to /usr/local/bin, creates /etc/passwd, /etc/bashrc and /etc/profile with some values in them and starts bash.
+
+
+:slide
+
+## 3.1. Shells
+
+[$br2]
+
+### Variables and data types
+
+.p
+Before talking about the different features newer shells support, we'll roughly cover variables and data types (mostly [url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameters bash] specifics).
+
+.p
+A variable, also called parameter, is created with the syntax (NO spaces between the =):
+
+```
+name=value
+
+.p
+Where `[name]` is either a combination of letters (upper and lower case), numbers and the underscore character, which cannot begin with a number, or one of select few =[positional]= and =[special]= parameters.
+
+
+:slide35
+
+#### Positional and special parameters
+
+.p
+[url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Positional-Parameters Positional parameters] are numbers from 1 to N, where each one corresponds to a shell (or function, or script) argument.
+
+.p
+Some of the [url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Special-Parameters special parameters] are:
+
+.bulleted
+- `[0]`, corresponding to the shell's or script's name,
+- `[@]` is all positional parameters, separated by spaces
+- `[#]` is the number of positional parameters
+- `[?]` is the last executed (foreground) process
+- `[$]` is process ID of the current shell.
+
+.p
+`[value]`, without any special surrounding characters (more on that later), is treated as a string (but it mustn't have spaces!), however it may also be omitted, in which case it is the empty string `[""]`.
+
+
+:slide35
+
+#### Data types
+
+.p
+In most shells, there are 3 data types: strings, integers and (one-dimensional) indexed arrays.
+[url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#index-declare bash has more], like references and associative arrays, but those aren't universal.
+
+.p
+A value is a =[string]= when surrounded by single `[']` or double `["]` quotes,\n
+an =[integer]= when it isn't surrounded by anything and composed only of digits (if there are letters, it is a string; it's [url https://tldp.org/LDP/abs/html/untyped.html quite tricky] when a value is interpreted as a string or integer) and\n
+an =[array]= when surrounded by braces `[()]`, where inside elements are strings or integers, separated by spaces.
+An indexed array can also be created by specifying the value at any index:
+
+```
+name[index\]=value
+
+
+:slide
+
+#### Mixing types and operations
+
+[$br1]
+
+```
+name=value
+
+.table
+|= Type =||= string operation =||= integer operation =||= array operation =|
+|:string:|
+ |:value:|
+ |:0:|
+ |:value when index is 0, empty string otherwise:|
+|:integer:|
+ |:empty string, but sometimes value:|
+ |:value:|
+ |:value when index is 0, empty string otherwise:|
+|:array:|
+ |:operation is done on element at index 0:|
+ |:operation is done on element at index 0:|
+ |:value:|
+
+
+:slide
+
+#### Parameter expansion
+
+.p
+With [url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion parameter expansion], actions are done with the general variable (entity) or on strings and arrays values.
+Operations on integers are done with [url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Arithmetic-Expansion arithmetic expansion].
+
+.p
+Parameter expansion is started with the character `[\$]` and either a name or curly braces.
+Retrieving a value is done with the forms `[\$name]`, `[\${name}]` and `[\${name[index]}]` for arrays.
+
+.p
+Some parameter expansions in bash:
+.bulleted
+- `[\${#parameter}]` length of characters
+- `[\${parameter:offset}]` and `[\${parameter:offset:length}]` return substring from index offset
+- `[\${parameter/pattern/string}]` return a string, where every match on pattern is replaced by string
+- `[\${name[@]}]` a (space separated) sequence of indices from 0 to length (for defined values) of array name
+
+
+:slide
+
+#### Arithmetic expansion
+
+.p
+Arithmetic expansions allow evaluation of [url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Arithmetic arithmetic expressions].
+They're in the form `[\$(( expression ))]`.
+
+.p
+Some useful expressions are:
+.bulleted
+- `[++name]`, `[name++]`, `[--name]`, `[name++]` postfix and prefix incrementation and decrementation
+- `[+]`, `[-]`, `[*]`, `[/]`, `[%]` normal arithmetic operators, `[**]` exponentiation
+- `[~]`, `[<<]`, `[>>]`, `[&]`, `[^]`, `[|]` bitwise operators
+- `[==]`, `[!=]`, `[>]`, `[>=]`, `[<]`, `[<=]` logical comparison
+- `[!]`, `[&&]`, `[||]` logical not, and, or
+- `[expr ? exprTrue : exprFalse]` conditional
+- `[=]`, `[+=]`, ..., `[<<=]`, ... assignment operators
+- `[expr1 , expr2]` consecutive expressions and `[(expr)]` bracing
+
+.p
+Expressions work with both variable names and integers.
+
+
+:middle_slide
+
+### Bourne shell
+
+.p
+Most modern shells support a lot of the more defying features of the [url https://en.wikipedia.org/wiki/Bourne_shell Bourne Shell], which include:
+
+:bulleted
+- [url https://en.wikipedia.org/wiki/Job_control_%28Unix%29 Job control]: Management of currently running groups of processes\n
+ :bulleted
+ - `[&]`: A process can be ran in the background with an ampersand (&) at the end of the command:
+ ```
+command [args...] &
+
+ - `[Ctrl+z]`: suspend the currently running (foreground) job
+ - `[bg]`: start a suspended job in the background
+ - `[fg]`: resume the last job to be put in the background and make it the current job with which we're interacting
+ - `[jobs]`: list all active (background) jobs
+
+
+
+
+:middle_slide
+:bulleted
+- &emsp;
+ :bulleted
+ - Every job is identified with a =[Job ID]= (number), which you can use by prepending a percentage sign. Example, to resume the job with JID 4:
+
+ ```
+fg %4
+
+ - For managing everything, usually there is a *[job table]*.
+ Upon shell termination, the shell tells all jobs in that table to terminate and waits for them.\n
+ `[disown]`: remove a job from the job table
+
+ - `[kill]`: send a signal to the process or job. Then that process will have to handle it accordingly.\n
+ Common ones are `[-KILL]` to immediately stop the process, `[-QUIT]` to quit it, `[-ABRT]` to cancel the current action, `[-TERM]` shut down (orderly), `[-STOP]` shut down (forcefully)
+
+
+
+
+:middle_slide27
+:bulleted
+- [url https://en.wikipedia.org/wiki/Here_document heredoc]: File literal, meaning it is a user "string" which is interpreted as a file
+ .bulleted
+ - start with `[<< NAME]`, where NAME can be anything you want, it is used to mark the beginning and end of a heredoc. `[<<]` is also a redirection symbol
+ - on every new line write out your text, all characters will be preserved
+ - to end it, write out `[NAME]` on the beginning of a new empty line. Example:
+ ```
+cat << MYFILE
+This is
+ some
+ text
+MYFILE
+
+- control operators: Control what command is executed, depending on [url https://en.wikipedia.org/wiki/Exit_status exit status]
+ .bulleted
+ - `[expr1 && expr2]`: Run expr2, only if expr1 exited successfully
+ - `[expr1 || expr2]`: Run expr2 if expr1 exited unsuccessfully
+ - `[expr1 ; expr2]`: Run expr2 after expr1 (sequential execution)
+
+
+
+:middle_slide27
+:bulleted
+- [url https://en.wikipedia.org/wiki/Redirection_%28computing%29 redirection]: Outside of having `[<]` and `[>]` for I/O redirection, often there is also
+ :bulleted
+ - `[>>]`: Acts like `[>]`, putting text into a file, but rather than overwriting everything, it appends it
+ - `[<<]`: As explained, for heredocs
+ - `[<<<]`: To the right is a string ([url https://en.wikipedia.org/wiki/Here_document#Here_strings herestring]), and it is interpreted as a file
+
+ ```
+cat <<< "Hello World!"
+
+ - =[Standard input]=, =[standard output]= and =[standard error]= are all =[files]= with which the shell works.
+ Typing text in the shell puts it into stdin, command output are put into stdout (and shown to the user) and errors are put into stderr (also shown to the user).
+ .p
+ Each one of them is numbered from 0 to 2, and you can specify redirection by appending or prepending it to the redirection symbol.\n
+ .p
+ .bulleted
+ - `[N>outputfile]`: redirects the output from standard stream N into outputfile
+ - `[N>&M]`: redirects the output from standard stream N into standard stream M
+ - `[N&lt;inputfile]`: redirects input file contents to standard stream N
+ - `[N&lt;&M]`: redirects standard stream M to standard stream N
+
+
+
+
+:middle_slide27
+:bulleted
+- [url https://en.wikipedia.org/wiki/Test_%28Unix%29 built-in test command]: With `[test]` you can do conditional expressions. You can also often use brackets `[[ args... ]]` instead of `[test args...]`
+
+ :p
+ :bulleted
+ - Some of the available file checks
+ .bulleted
+ - `[-e FILENAME]`: FILENAME exists
+ - `[-d FILENAME]`: if FILENAME is a directory
+ - `[-h FILENAME]`: if FILENAME is a symbolic link
+ - `[-w FILENAME]`: you can write in FILENAME
+
+ - Some of the available string checks
+ .bulleted
+ - `[-n STR]`: string STR has nonzero length
+ - `[-z STR]`: string STR has length zero
+ - `[STR1 = STR2]` and `[STR1 != STR2]`: self explanatory
+
+ - Some of the available number checks
+ .bulleted
+ - `[INT1 -eq INT2]`: equal integers
+ - `[INT1 -gt INT2]`: INT1 > INT2
+ - `[INT1 -gt INT2]`: INT1 >= INT2
+
+ - Operators: `[!]` - negation, `[-a]` - binary AND, `[-o]` - binary OR, parentheses for grouping (escaped with `[\\]`)
+
+
+
+
+
+:slide
+:bulleted
+- [url https://en.wikipedia.org/wiki/Shell_script scripting support]: Running commands from top to bottom of a file
+ .p
+ .bulleted
+ - `[#]`: Everything between a # and the end of the line denotes a comment
+ - `[#!]`: If on the first line of the file, is treated as a [url https://en.wikipedia.org/wiki/Shebang_%28Unix%29 shebang], which specifies what interpreter to be used for the script
+
+- compound commands: Structures for flow control\n
+ In all examples, `[test-command]` is any command (or combination with control operators), and logic is based on exit code.
+
+ :p
+ :bulleted
+ - conditional (if)
+
+ ```
+if test-command ; then commands-if-true
+elif test-command ; then commands-if-true
+else commands-if-true
+fi
+
+ `[elif]` statements can appear multiple times, both elif and else are optional
+
+
+
+
+
+:slide
+:bulleted
+- &emsp;
+ [$br1]
+
+ :bulleted
+ - conditional (case)
+
+ ```
+case word in (pattern | ...) commands-if-true ;; ... esac
+
+ .p
+ Where the beginning brace can be ommited.\n
+ Patterns are according to [url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Pattern-Matching bash's pattern matching]
+
+ - loops
+
+ ```
+while test-command; do commands-if-true; done
+
+ ```
+for name in words...; do commands-if-true; done
+
+ If `[in words...]` is ommited, positional arguments are used
+
+
+
+
+:middle_slide35
+
+## 3.2. Files and directories
+
+.bulleted
+- `[/dev]`: devices
+- `[/proc]`: process information
+
+[$br3]
+
+.bulleted
+- `[/bin]`: main command programs (binaries), used by users
+- `[/sbin]`: command programs, used for the system operation
+- `[/usr]`: other system resources
+ .bulleted
+ - `[/usr/bin]`: all other user command binaries
+
+
+:slide
+
+#### Everyday file system commands
+
+.bulleted
+- `[mkdir]`: create directories
+- `[rm]`: remove a (hardlink to) file or directory
+- `[mv]`: move file (or directory) to another directory
+- `[cp]`: copy a file
+- `[ln]`: create hard (or soft, with `[-s]`) links to files (inodes)
+- `[ls]`: list directory contents
+
+#### Other useful file system commands
+
+.bulleted
+- `[shred]`: overwrite file contents
+- `[dd]`: do many things with files, like modifying and duplicating data across devices and partitions, (basic) data recovery and generating files
+- `[du]`: estimate file usage
+- `[stat]`: display status for file or file system
+- `[chwon]`: change owner of an inode
+- `[chgrp]`: change group of an inode
+- `[chmod]`: change file modes
+- `[find]`: search for a file inside a directory (recursively)
+
+
+:slide
+
+#### Everyday text (file) commands
+
+.bulleted
+- `[echo]`: prints a given string to standard output
+- `[cat]`: sequentially prints files to standard output
+- `[less]`: view files with support for scrolling
+- `[head]`: print the first lines (or characters) of a file
+- `[tail]`: print the last lines (or characters) of a file
+
+#### Other useful text (file) commands
+
+.bulleted
+- `[grep]`: searches for matches in a file, using simplified regular expressions. `[egrep]` for extended regex and `[fgrep]` for string match (as-is).
+- `[sed]`: filter and transform text from files, according to regex
+- `[tr]`: translate, map (more than one to one for example) and delete characters
+- `[cut]`: remove parts of text from each line
+- `[strings]`: find embedded text inside binary files
+- `[truncate]`: shrink or extend the size of a file
+- `[wc]`: count words inside file
+- `[diff]`: compare files and show their differences
+
+
+:middle_slide
+
+#### Device commands
+
+.bulleted
+- `[mount]`: bind another file system to a location in the file system
+- `[umount]`: remove binding to a file system
+- `[lsusb]`: lists USB devices
+- `[lspci]`: lists PCI devices
+
+#### System information commands
+
+.bulleted
+- `[date]`: display current date and time
+- `[hostname]`: show (or set) the systems hostname (network name)
+- `[free]`: display free memory on the system
+
+
+:slide
+
+#### User and group management
+
+.bulleted
+- `[useradd]`: creates a new user (with a password)
+- `[userdel]`: remove a user and all of his files
+- `[usermod]`: modify a user account, including his name and groups
+- `[passwd]`: change password of a user. With `[-l]` user could be locked (impossible to log in)
+
+[$br3]
+
+.bulleted
+- `[groupadd]`: create a new group
+- `[groupdel]`: remove a group
+- `[groupmod]`: modify an existing group
+
+[$br3]
+
+.bulleted
+- `[w]`: show who is logged in and what they are doing
+- `[who]`: show who is logged in
+- `[whomai]`: print username
+- `[login]`: establish a new connection to the system
+
+
+:slide
+:bulleted
+- `[/etc]`: system configuration files
+ [$br2]
+
+ :bulleted
+ - `[/etc/group]`: the data for all groups is stored here, in the format
+
+ ```
+GROUPNAME:PASSWORD:GID:USERS...
+
+ - `[/etc/passwd]`: the data for all users is stored here, in the format
+
+ ```
+USERNAME:PASSWORD:UID:GID:USERINFO:HOMEDIR:SHELL
+
+ - `[/etc/shadow]`: stores other user data, especially the password as an encrypted string, in the format
+
+ ```
+USERNAME:PASSWORD:LASTCHANGED:MINBETWEENCHANGES:MAXBETWEENCHANGES:WARNEXPIRE:INACTIVEDAYS:EXPIRE
+
+
+
+
+:slide27
+:bulleted
+- &emsp;
+ :bulleted
+ - `[/etc/fstab]`: read on boot by mount to setup devices in fs
+
+ ```
+# device-spec mount-point fs-type options dump pass
+/dev/sda1 / ext4 defaults 1 1
+UUID=123A-456B /boot vfat noauto,noatime 1 2
+LABEL=Vault /mnt/Vault auto nosuid,nodev,nofail 0 0
+
+ - `[/etc/hosts]`: list of host names (domain names) and their corresponding IP address, when a DNS server doesn't do the job
+
+ ```
+# ipaddress domains
+127.0.0.1 localhost mywebsite.com something.else
+62.44.101.138 my.uni
+
+ - `[/etc/bashrc]`: global defaults and aliases used by the bash shell
+ - `[/etc/motd]`: message of the day (unexecuted text), shown after login but before the shell is ran
+
+
+
+
+:middle_slide35
+:bulleted
+- `[/usr]`: other system resources
+ .bulleted
+ - `[/usr/lib]`: library files
+ - `[/usr/local]`: local, system software
+ - `[/usr/share]`: architecture independent data, like manuals
+
+- `[/var]`: variable data, like logs and cache
+- `[/home]`: home directories of all users
+- `[/lib]`: libraries and kernel modules
+- `[/mnt]`: mounted temporary filesystems
+- `[/root]`: home directory for the root user
+
+
+
+:slide
+
+# 4. Software licensing
+
+.p
+It is important to note that most software in Linux, including the kernel itself, is under a variety of open licenses.
+An open license is a license which allows others to reuse the original work, under some restrictions.
+
+.p
+For software, such a license is applied to the source code from which the original application was made.
+Some commonly used ones, with a (NON-LEGALLY BINDING) summary include:
+
+.bulleted
+- [url https://en.wikipedia.org/wiki/MIT_License MIT]: the author is not responsible for anything that the code does
+- [url https://en.wikipedia.org/wiki/BSD_licenses BSD-3-Clause]: use the same license (copyleft), the author is not responsible for anything that the code does
+- [url https://en.wikipedia.org/wiki/GNU_General_Public_License GNU GPL]: disclose the original project and use the same license ([url https://en.wikipedia.org/wiki/Copyleft copyleft])
+
+.p
+This is important, since pretty much everything can be freely modified by anyone (for the better or worse, but generally better).
+
+
+:slide35
+
+# 5. What makes up a useful OS
+
+[$br1]
+
+.p
+A Linux-based operating system is nothing more than the Linux kernel, combined with an assortment of programs.\n
+Overall, the main elements that make up a useful *[desktop]* operating system (alongside a command-line shell) are:
+
+[$br1]
+
+.numbered
+1. =[Bootloader]=: load the kernel and operating system
+2. =[Init system]=: well managed way to start everything inside the OS
+3. =[Package manager]=: way to manage our binaries
+4. =[Desktop manager]=: graphical shell
+
+
+:slide
+
+## 5.1. Bootloader
+
+.p
+The computer boot process is a relay race.
+
+.p
+In a "standard" BIOS-MBR boot configuration:
+
+```
+BIOS -> Master Boot Record -> Active Parition -> Bootloader ->
+-> Boot menu (optional) -> Kernel -> Everything else
+
+.bulleted
+- [url https://en.wikipedia.org/wiki/BIOS BIOS]: a small chip with code that is ran upon power up
+- [url https://en.wikipedia.org/wiki/Master_boot_record MBR]: small amount of space at the very start of the disk, that contains some (bootstrap) code and partition information. The BIOS hands off execution to the bootstrap code.
+- Active partition: MBR loads and runs code from the beginning of the partition (boot sector), which starts the bootloader
+- [url https://en.wikipedia.org/wiki/Bootloader Bootloader]: the first complex program, which manages kernels, shows a menu, allows for debugging and so on
+
+
+:middle_slide
+
+.p
+The BIOS is baked into the motherboard, the MBR is pretty universal (and it's less than 512 bytes) and the kernel we know and love.
+
+.p
+That leaves us with the need for a bootloader.
+On Linux, the most used one is called [url https://en.wikipedia.org/wiki/GNU_GRUB GRUB].
+
+.p
+It's config is found in `[/etc/default/grub]` (which is then fully generated with `[grub-mkconfig]`) and can be "installed in the partition" with `[grub-install]`.
+
+```
+GRUB_DEFAULT=0
+GRUB_TIMEOUT=5
+GRUB_TIMEOUT_STYLE=menu
+GRUB_CMDLINE_LINUX=""
+GRUB_CMDLINE_LINUX_DEFAULT=""
+GRUB_GFXMODE=640x480
+
+
+:slide27
+
+## 5.2. Init system
+
+.p
+Now we need to load the user stuff, like a network manager, the graphical user interface and so on.\n
+In Minimal Linux Live, this is done by some hard written scripts, which aren't very modular or extensible.
+
+.p
+[url https://en.wikipedia.org/wiki/Init Init systems] use configuration files, called service, to start a program in some way.
+
+:bulleted
+- [url https://en.wikipedia.org/wiki/Systemd systemd], which also aims to also provide easy system configuration
+
+ ```ini
+[Unit]
+Description=Service
+[Service]
+Type=simple
+User=root
+ExecStart=/usr/local/sbin/script.sh
+[Install]
+WantedBy=multi-user.target
+
+- [url https://en.wikipedia.org/wiki/OpenRC openrc], a simple and modern system
+
+
+
+:slide
+
+## 5.3. Package manager
+
+[$br1]
+
+.p
+Programs are just executable files, usually placed in a specific folder, like `[/usr/bin]`.
+
+.bulleted
+- MLL comes with ~100 executables (and ~230 after my script)
+- my Debian server has ~1000 installed packages
+- my current desktop Gentoo setup has ~1500 installed packages
+- my old Fedora setups have reached ~3000 packages on multiple occasions
+
+.p
+Updating all of them means replacing all of the binaries, means tracking where each one came from, installing a new one might require installing multiple others and so on.
+
+.p
+On modern systems, managing binaries is automated by an application called a package manager.
+
+
+:middle_slide35
+
+.p
+Additional benefits of package management automation include:
+
+.bulleted
+- checking for package validity (and tampering)
+- utilising multiple server mirrors
+- automatic dependency management and installation
+- version caveats
+- (indirectly) improved stability because of maintainer compatibility checks
+
+[$br1]
+
+```
+apt install PKG
+apt remove PKG
+apt upgrade
+
+
+:slide
+
+## 5.4. Window systems
+
+.p
+A widow system is your graphical shell: the graphical way to interact with your computer (the kernel).
+It's main components are:
+
+[$br1]
+
+:bulleted
+- =[Window manager]=: the overall system with which you create, remove, resize and work with windows. They are generally separated into two types:
+
+ .bulleted
+ - *[Stacked]*: this is what you know, windows are just rectangles floating about, and can be put one over each other
+ - *[Tiled]*: windows take up a predefined (but changeable) portion of the screen
+
+- =[Compositor]=: adds an unseen window buffer, allowing additional processing, before a window is shown. This powers transparency, animation effects and more.
+
+- =[Session manager]=: graphical application that manages the window managers (outside WMs), think of it as a login window
+
+
+
+:slide27
+
+# 6. War on distros
+
+.p
+A distribution is a complete set of of all applications that you might use.
+
+.p
+Overall, there are 4-5 distributions from which 90% of all other distros are based upon:
+
+.numbered
+1. [url http://www.slackware.com/ Slackware]:
+ as the oldest still maintained distro, it served as inspiration for a lot of other distros.
+ It aims to be as simple and as close to UNIX as possible.
+2. [url https://www.debian.org/ Debian] (and [url https://ubuntu.com/ Ubuntu]):
+ it is the most popular distribution (if we also include Ubuntu).
+ Ubuntu aims to be modern and fancy, while Debian aims to be as stable as possible, which makes it the most popular in server usage.
+3. [url https://www.gentoo.org/ Gentoo]:
+ the distribution which defined non-binary software distribution
+4. [url https://archlinux.org/ Arch Linux]:
+ a very popular and modern distribution with the goal of providing the latest and greatest software.
+
+.p
+We haven't touched too much, but Linux distributions aren't limited to desktop or server computers.
+
+.numbered
+1. [url https://en.wikipedia.org/wiki/Android_%28operating_system%29#AOSP AOSP]: the base of the whole Android operating system
+2. [url https://en.wikipedia.org/wiki/OpenWrt OpenWRT]: a router operating system
+
+
+:slide35
+
+# 7. Demos - virtual machine and setup from zero
+
+[$br2]
+
+.p
+Now for the best part: we'll be installing a Linux distribution on a virtual machine and then directly on a laptop, running Windows 10!
+
+.p
+I've chosen to install [url https://linuxmint.com/ Linux Mint], since it is generally targeted towards newcomers and will feel familiar enough to Windows users.
+
+.p
+Currently there won't be an official recording of the process, you should've been here live!
+
+
+:title_slide35
+
+# Thank you for your time
+
+
+:slide18
+
+# Sources
+
+.p
+All of these contain, at most, small paraphrased sentences in the slides.
+They served as personal educational and reference tools.
+
+.bulleted
+- [url https://en.wikipedia.org/ wikipedia] and [url https://stackexchange.com/ stackexchange] have been used extensively and linked where appropriate.
+- [url https://people.cs.rutgers.edu/~pxk/416/index.html CS416 - Operating Systems Design] by [url https://people.cs.rutgers.edu/~pxk/rutgers/ Paul Krzyzanowski] at [url https://www.cs.rutgers.edu/ Rutgers State University]
+- [url https://web.archive.org/web/20220713165958/https://homepage.cs.uri.edu/~thenry/resources/unix_art/ch02s01.html Origins and History of UNIX, 1969-1995] from [url https://web.archive.org/web/20220611160552/https://homepage.cs.uri.edu/~thenry/resources/unix_art/index.html The Art of Unix Programming] by Eric Steven Raymond
+- [url https://www.youtube.com/watch?v=EY6q5dv_B-o Ken Thompson interviewed by Brian Kernighan at VCF East 2019] by [url https://vcfed.org/ Vintage Computer Federation]
+- [url http://www.cs.uah.edu/~kkeen/CS590/Pseudo%20Terminals.ppt Pseudo Terminals presentation] from [url http://www.cs.uah.edu/~kkeen/CS590/ CS590] by [url http://www.cs.uah.edu/~kkeen/kkeen.html Kevin J. Keen] at [url https://www.uah.edu/ University of Alabama in Huntsville]
+- [url https://teaching.idallen.com/dat2330/04f/notes/links_and_inodes.html Hard links and Unix file system nodes] from [url https://teaching.idallen.com/dat2330/04f/ DAT 2330 Introduction to Operating Systems] by [url http://www.idallen.com/ Ian D. Allen]
+- [url https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/9_VirtualMemory.html Virtual Memory, OS Course Notes] by [url https://www.cs.uic.edu/~jbell/ Dr. John T. Bell] at [url https://www.cs.uic.edu University of Illinois Chicago],\n
+ which is directly based on [url https://archive.org/details/operating-system-concepts-9e Operating System Concepts, 9th Edition] by [url https://codex.cs.yale.edu/avi/ Abraham Silberschatz]
+- [url http://csapp.cs.cmu.edu/3e/home.html Chapter 9 Preview - Virtual Memory] from [url http://csapp.cs.cmu.edu/ Computer Systems: A Programmer's Perspective] by [url http://www.cs.cmu.edu/~bryant Randal E. Bryant] and [url http://www.cs.cmu.edu/~droh David R. O'Hallaron]
+- [url https://www.cse.iitb.ac.in/~mythili/teaching/cs347_autumn2016/notes/07-memory.pdf Memory Management, Lecture Notes] by [url https://www.cse.iitb.ac.in/~mythili/ Mythili Vutukuru]
+- [url http://www.cs.iit.edu/~cs561/cs351/VM/paging%20advantages%20and%20disadvantages.html Paging advantages and disadvantages] by Charles R. Bauer at [url http://www.cs.iit.edu/ Computer Science Departmemnt of Illinois Institute of Technology]
+- [url https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html Bash Reference Manual] by the [url https://www.gnu.org/ GNU project] and [url https://man.openbsd.org/ksh ksh manual] by the [url https://www.openbsd.org/ OpenBSD project]
+- [url https://www.in-ulm.de/~mascheck/bourne/v7/ Manual of the Bourne Shell on Version 7], archived by [url https://www.in-ulm.de/~mascheck/ Sven Mascheck]
+- [url https://www.linuxbase.org/betaspecs/fhs/fhs/ch04.html /usr hierarchy] from [url https://www.linuxbase.org/betaspecs/fhs/fhs/index.html Filesystem Hierarchy Standard] by [url https://www.linuxfoundation.org/ Linux Foundation], Daniel Quinlan, Paul 'Rusty' Russell, Christopher Yeoh
+- [url https://www.pathname.com/fhs/pub/fhs-2.3.pdf Filesystem Hierarchy Standard] by Rusty Russel, Daniel Quinlan and Christopher Yeoh
+- [url https://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/usernames.html#FTN.AEN26405 User & Group Names] from [url https://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/book1.html Linux Standard Base Core Specification] by [url https://en.wikipedia.org/wiki/Free_Standards_Group Free Standards Group]
+- [url https://docstore.mik.ua/orelly/linux/run/ch05_07.htm Managing User Accounts] from [url https://docstore.mik.ua/orelly/linux/run/index.htm Running Linux, Third Edition] by Matt Welsh, Matthias Kalle Dalheimer, and Lar Kaufman
+- [url https://neosmart.net/wiki/mbr-boot-process/ The BIOS/MBR Boot Process] by [url https://wiki.neosmart.net/ NeoSmart's Knowledgebase]
+
+# Licensing
+
+.p
+Images on slides "2.1. shell" and "2.2. UNIX-style file system" are made by me and [url /license.html licensed as content].\n
+The script [url http://syndamia.com/talks/linuxgraphy-by-strabo/mll-set.sh mll-set.sh] is licensed under MIT (though I don't see it as substatial enough to be licensed under anything).
diff --git a/src/slides/linuxgraphy-by-strabo/index.md b/src/slides/linuxgraphy-by-strabo/index.md
deleted file mode 100644
index 5780cfa..0000000
--- a/src/slides/linuxgraphy-by-strabo/index.md
+++ /dev/null
@@ -1,1382 +0,0 @@
-# Linuxgraphy by Strabo
-
-### Custom assets
-
-*Licensing information in the last slide, at the bottom of the page*
-
-- [UNIX layers image](./img/unix-layers.png)
-- [UNIX directory tree](./img/unix-dir-tree.png)
-- [mll-set.sh](./mll-set.sh)
-
-### Presented at
-
-&.bg Unofficial [FMI](https://fmi.uni-sofia.bg/en) Computer Science Discord server &emsp; *04.03.2023 || 14:50 - 17:20*
-: In front of a tiny audience of other uni students. Exact revision [here](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/6feed223ff48fe00cf12fcd63f3f56179c298cae/src/talks/linuxgraphy-by-strabo/index.md).
-
-&.bg Unofficial [FMI](https://fmi.uni-sofia.bg/en) Computer Science Discord server &emsp; *22.01.2023 || 18:00 - 21:00*
-: In front of a tiny audience of other uni students. Exact revision [here](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/6eb7a8fff01c6814253a0e738efb53734d297be9/src/talks/linuxgraphy-by-strabo/index.md).
-
-&.presentation
-
-
-
-&[title
-
-# Linuxgraphy by Strabo
-
-*Made by [Syndamia](https://syndamia.com)*
-
-&.br4
-&{sqrow
-
-&.br1
-
-&(font22
-2000 years ago [Strabo](https://en.wikipedia.org/wiki/Strabo) published [Geography](https://en.wikipedia.org/wiki/Geography), in which he laid out the world as it was known to the Romans and Greeks.
-&.br1
-Today, I'll lay out Linux as it is known to me.
-&)
-
-![](https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/Strabo.jpg/199px-Strabo.jpg)
-
-&.br1
-
-&} &]
-
-
-
-&[slide35
-
-# Contents
-
-&{sqrow
-&{column
-
-1. Historical context
-2. Structure of UNIX-likes
- 1. Shell
- 2. UNIX-style file system
- 2. Kernel
-&.br2
-3. Linux from the inside
- 1. Shells
- 2. Files and directories
- 3. Common configuration files
- 4. System management
-4. Software licensing
-
-&} &{column
-
-5. What makes up a useful OS
- 1. Bootloader
- 1. Init system
- 2. Package manager
- 3. Desktop manager
-6. War on distros
-&.br4
-7. Demos - virtual machine and setup from zero
-
-&} &}
-
-&]
-
-
-
-&[slide
-
-# 1. Historical context
-
-&.br1
-
-#### 1945 - 1955
-
-You directly loaded instructions into memory and let it execute your "code" (processor instructions).
-Nothing else ran on the machine.
-
-This process was labor intensive: a qualified operator loaded your program, dumped the memory contents, remove any external media, reset the machine and load the next job.
-
-#### 1956 - 1959
-
-Computers became faster, but a lot of time was spend on managing jobs.
-
-[resident monitors](https://en.wikipedia.org/wiki/Resident_monitor): very small programs, which always *resided* in memory, and *monitored* what the state of the current job was.
-Jobs were loaded in series ([batches](https://en.wikipedia.org/wiki/Batch_processing)).
-When the current job finished, memory would be dumped and the next one would automatically be loaded and started.
-
-&]
-
-
-
-&[slide
-
-#### 1960s
-
-&.br1
-
-Peripherals (tapes, punch cards, ...) were extremely slow.
-[Multiprogramming](https://en.wikipedia.org/wiki/Computer_multitasking#Multiprogramming): the current job is waiting for a peripheral, another job would be started.
-
-[Travel reservation system](https://en.wikipedia.org/wiki/Sabre_%28travel_reservation_system%29) by American Airlines: where travel agents would search, price and book services.
-A computer system now had to support:
-
-- User accounts with concurrent access
-- Fast response time and ease of use
-- Storage organization, also following the rise of disks
-- Data communication links (often phone lines)
-
-&.br1
-
-More and more business started using computers, thanks to [minicomputers](https://en.wikipedia.org/wiki/Minicomputer), so demand for OS software increased.
-
-&]
-
-
-
-&[slide
-
-#### 1964 - 1969
-
-IBM's [System/360](https://en.wikipedia.org/wiki/IBM_System/360) line of computers, each with expansion capabilities, backwards compatibility, all under one instruction set and operating system.
-
-[Multics](https://en.wikipedia.org/wiki/Multics), an influential operating system that was designed for a General Electric mainframe.
-Some of it's novel ideas include, but are not limited to:
-
-- [Time-sharing](https://en.wikipedia.org/wiki/Time-sharing): sharing resources of a singular machine among many users (via [multiprogramming](https://en.wikipedia.org/wiki/Multiprogramming) and [multi-tasking](https://en.wikipedia.org/wiki/Computer_multitasking))
-- [Single level store](https://en.wikipedia.org/wiki/Single-level_store) (aka [virtual memory](https://en.wikipedia.org/wiki/Virtual_memory)): Processes would write into contiguous memory, but in reality it is scattered and managed by the operating system.
-- [Protection rings](https://en.wikipedia.org/wiki/Protection_ring): Allowing different levels of access to different resources (programs). In general, this also often requires a [CPU protected mode](https://en.wikipedia.org/wiki/Protected_mode).
-- [Hierarchical file system](https://en.wikipedia.org/wiki/Directory_%28computing%29): Arbitrary directories with subdirectories, rather than just having files next to each other or having directories which could only contain files.
-- [Command processor](https://en.wikipedia.org/wiki/Shell_%28computing%29) (that is separated from the OS): More on that later
-
-&]
-
-
-
-&[slide
-
-#### 1969: Death of Multics and birth of UNIX
-
-Ultimately Multics grew too large, becoming unusable and unmaintainable.
-In the beginning, programming was done mostly by [Bell Labs](https://en.wikipedia.org/wiki/Bell_Labs), with [Ken Thompson](https://en.wikipedia.org/wiki/Ken_Thompson) being one of the developers.
-
-&.br1
-&{sqrow
-
-&(font18
-![](https://upload.wikimedia.org/wikipedia/commons/f/f8/Ken-Thompson-2019.png =160x)
-*Ken Thompson image by National Inventors Hall of Fame*
-![](https://upload.wikimedia.org/wikipedia/commons/1/1b/Ken_Thompson_and_Dennis_Ritchie--1973.jpg)
-*Ken Thompson and Dennis Ritchie in 1973*
-&)
-
-&{column
-
-Thompson still had some desire to work on operating systems, after Bell Labs pulled out.
-The tools he made while rewriting [his own video game](https://en.wikipedia.org/wiki/Space_Travel_%28video_game%29) on a PDP-7 lead to a whole operating system: UNIX.
-
-Based, expanded on and improved upon many of Multic's ideas, UNIX became the father of modern OSs.
-
-&}
-
-&} &]
-
-
-
-&[slide
-
-# 2. Structure of UNIX-likes
-
-Ignoring [standards](https://unix.stackexchange.com/questions/14368/difference-between-posix-single-unix-specification-and-open-group-base-specifi/14415) and [specifications](https://unix.stackexchange.com/questions/87686/what-makes-an-operating-system-unix-like), in my opinion, from the point of a user, a UNIX-like OS has the following components:
-
-&.br4
-
-1. **shell**: A programmable replaceable command-line interpreter, with utilities for managing the whole system and support for pipelines and I/O redirection
-2. **UNIX-style file system**: [Filesystem](https://en.wikipedia.org/wiki/Unix_filesystem) as a single rooted tree, objects (nodes) in the file system are [inodes](https://en.wikipedia.org/wiki/Inode) and an inode can be [(at least)](https://en.wikipedia.org/wiki/Unix_file_types) either a regular file, directory or devices. Permissions per users and group.
-3. **kernel**: Program that manages all communication and operations between the hardware and software
-
-&.br4
-
-&(font18 *For now we'll generally just look over some of the common stuff and go into detail later, while in Linux.* &)
-
-&]
-
-
-
-&[slide35
-
-## 2.1. shell
-
-&.br2 &{sqrow
-
-&{column
-The operating system is divided into layers, [like an onion](https://youtu.be/-FtCTW2rVFM?t=57).
-Only the kernel has access to the hardware.
-shells and executables (binaries) have access to the kernel.
-
-shells provide user interfaces, [both](http://en.wikipedia.org/wiki/Shell_%28computing%29) command-line and graphical.
-While on the topic of UNIX, we'll only discuss the former.
-&}
-
-&(centered ![](./img/unix-layers.png) &)
-
-&} &]
-
-
-
-&[slide
-
-### Command-line shells
-
-Command-line shells operate solely with text, often only with ASCII characters.
-Usually connecting to a computer (to the shell) is said to be done with either a "terminal" ("console") or "teleprinter" ("teletype").
-
-&{row
-
-Video displays became widely available in the late 1970s, so before that access was done with a "teleprinter", a typewriter-printer combo.
-
-&(font18
-![](https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/ASR-33_at_CHM.agr.jpg/1280px-ASR-33_at_CHM.agr.jpg =860x)
-*Teletype Model 33 by [Arnold Reinhold](https://commons.wikimedia.org/wiki/User:ArnoldReinhold)*
-&)
-
-
-&.newrow
-
-With the advent of computer displays, teleprinters were replaced with terminals, video display-keyboard combo.
-Thanks to the widely popular [VT100](https://en.wikipedia.org/wiki/VT100), almost all terminals support [ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code).
-
-&(font18
-![](https://upload.wikimedia.org/wikipedia/commons/thumb/9/99/DEC_VT100_terminal.jpg/675px-DEC_VT100_terminal.jpg?20131106192408 =860x)
-*DEC VT100 by [Jason Scott](https://www.flickr.com/people/54568729@N00)*
-&)
-
-&} &]
-
-
-
-&[slide
-
-Today we don't usually use such specialised hardware, but the names persist with slightly different meanings.
-
-[Virtual Terminal](https://en.wikipedia.org/wiki/Virtual_console) (Console, tty): on some modern UNIX-likes (like Linux), the kernel/OS provides special devices, where a console is directly implemented/simulated with the connected computer and display.
-
-- systems that don't provide it usually expose another way to connect a console (now external hardware and/or software is required), like a [serial](https://en.wikipedia.org/wiki/Serial_port) port
-
-[Terminal Emulator](https://en.wikipedia.org/wiki/Terminal_emulator): a special program that emulates a virtual terminal (within another display system)
-
-[Pseudoterminal](https://en.wikipedia.org/wiki/Pseudoterminal) (pty): a program that sits between a terminal and a shell (or other program), and makes them both think they're directly connected
-
-- ssh, a program to remotely connect to a device's shell, establishes a pseudoterminal. Your local terminal thinks it's connected to a local shell and vice versa with the remote shell, however the pty in between handles the true communication.
-
-&]
-
-
-
-&[middle
-
-### Command location and parameters
-
-Most commands are regular programs, which exist somewhere on the system.
-When entering a command name, the shell searches for an executable with that name.
-Searching the whole drive is very inefficient, so the search is limited to the few directories, listed in a variable called "PATH".
-
-You can give a full or relative path, and that will be executed directly.
-
-Each command can be given parameters, separated by spaces, each (by convention) being either text values or options (switches).
-
-Options usually start with a hyphen `-` (like `-c` or `-current-time`) and often support abbreviations (`-a -b -c` to `-abc`).
-Newer conventions also allow start with two hyphens `--` (`--current-time`), though if shown as-is indicate the rest is a string.
-More rarely you might see `--OPTION=VALUE` or just `OPTION=VALUE`.
-
-&]
-
-
-
-&[middle
-
-### Thompson shell
-
-The first UNIX shell is the [Thompson shell](https://en.wikipedia.org/wiki/Thompson_shell).
-The two major features that every other shell supports are:
-
-- I/O redirection: redirection of input and output, allowing insertion of input from a file or storage of output into a file:
-
- ```
- command [args...] < filepath
- command [args...] > filepath
- ```
-
-- pipelines: being able to redirect the output from one command to another without limit
-
- ```
- command1 [args...] | command2 [args...] | ...
- ```
-
-&]
-
-
-
-&[slide
-
-## 2.2. UNIX-style file system
-
-- Rooted singular tree of directories (the root folder of which is called "root", denoted with a "/")
-- Each tree object (node) is an [i(ndex)node](https://en.wikipedia.org/wiki/Inode), containing type, ownership, access, internal data and any other metadata, but **not** name!
-- Directory inodes (files) contain a table with rows of names and inode numbers, mapping a file name to it's contents. Each row is called a [hard link](https://en.wikipedia.org/wiki/Hard_link). Every directory has a hard link to itself, called ".", and a hard link to it's parent, called "..".
-
-![](./img/unix-dir-tree.png)
-
-&]
-
-
-
-&[middle
-
-### Attributes of an inode
-
-- [file type](https://en.wikipedia.org/wiki/Unix_file_types): Each inode represents some sort of file (data), but a "file" can also be a directory or device, so we need to know how to handle it.
- There are 7 main types (but there can exist more, depending on OS):
- &.br1
- + **regular**: just a plain old file
- + **directory**: as explained, a file containing hard links to other files. Each directory is allowed to appear *only once* in a single parent.
- + **symbolic link**: points to any file (or directory). It contains the (relative) path to that object (as a simple string), so a symlink not could even be valid.
- Think of a C++ pointer (pseudocode).
-
- ```
- symlink /bin/mprog = "/usr/local/bin/mprog";
- exec(/bin/mprog); -> Executes /usr/local/bin/mprog
- ```
-
-&]
-
-
-
-&[slide
-
- + **FIFO special**: aka [named pipe](https://en.wikipedia.org/wiki/Named_pipe), a special type of regular file, where at any moment only one process can read from it and one can write to it. It takes the concept of shell pipes to inter-process communication.
-
- ```
- [Process] --write-> [FIFO] x-write-- [Process]
- [ A ] x--read-- [ ] --read--> [ B ]
- ```
-
- + **block special**: a device which is randomly accessible, like a hard drive or cdrom drive.
- Think of a C++ array (pseudocode):
-
- ```
- BlockSpecial[438] = 1 ; var = BlockSpecial[438]
- ```
-
- + **character special**: devices which are accessed via serial streams of input or output, like keyboards, mice, graphics cards and teletypes.
- Think of a C++ stream (pseudocode):
-
- ```
- CharacterSpecial << 1 ; CharacterSpecial >> var
- ```
-
-&]
-
-
-
-&[middle
-
- + **sockets**: file for inter-process communication. Compared to FIFO specials, they can be used by more than two processes, used in both directions and support [file descriptors](https://en.wikipedia.org/wiki/File_descriptor) and packets
-
- ```
- [Process A] <--read&write--> [Socket 1]
- [Process B] <--read&write--> [Socket 1]
- ...
-
- [Process A] --write--> [Socket 1] --read--> [Process B]
- \-read--> [Process C]
- ```
-
-&]
-
-
-
-&[slide
-
-#### Side-step into users and groups
-
-&.br3
-
-A user in UNIX is essentially a small collection of data, most important of it being a **unique ID** (number), a **name** (string), a **group id** (number; files created by the user are in that group) and a **password**.
-
-Groups are also small collections of data, but much simpler, comprised only of a **unique ID** (number), a **name** (string) and a **list of users** that are "in" the group. Their main purpose is to simplify access control.
-
-User with ID 0 is called root, it is the "system administrator", all actions made by the system itself are done as that user.
-Every user has their own "home" folder (under "/home/USERNAME/", except for root, which is "/root/"), in which they store personal files, as well as user-specific configuration files.
-
-&]
-
-
-
-&[slide
-
-- [file permissions](https://en.wikipedia.org/wiki/File_system_permissions): control the freedom of a user to read (navigate for directories), change and execute files
- File permissions are split into three sets: what the **owner** can do, what **group** members can do and what **anyone else** can do.
- Each set contains a mix of three permissions: **r**ead, **w**rite and e**x**ecute, and each set stores some combination of them.
- &.br1
- Each is represented by a bit in the order above (`101` means you *can* read, *cannot* write, *can* execute) and the overall permissions are often shown as a three digit number or character string.
- Example: `111101100` will be shown as `754` or `rwxr-xr--`
-
-- link count: the count of hard links that point to the inode. A file is deleted **only when there are no hard links left to it**. Every directory inode has at least two - one from parent and one from itself ("."), though the latter **isn't** counted. Child and parent directories also **add** to the count.
-
-- User ID of owner, Group ID, file size and timestamps
-
-&]
-
-
-
-&[slide
-
-## 2.3. Kernel
-
-&(font18 &.br1 &)
-
-The kernel has the core functionality of the operating system and bridges the gap between programs and hardware.
-Some important subsystems include scheduling, file, device, process and memory management.
-
-To preserve the [everything is a file](https://en.wikipedia.org/wiki/Everything_is_a_file) methodology, devices and processes can be handled as files (inside `/dev` and `/proc`).
-They (most of the time, in modern kernels) aren't actual files on a hard drive, but "virtual" files, where operations on them are handled in a different manner than normal by the kernel.
-
-&.br2
-
-&(font35 Linux is **not** an operating system, it is a kernel!!! &)
-
-&.br2
-
-Two of the important things a kernel does is manage **processes** and **memory**.
-
-&]
-
-
-
-&[slide35
-
-### 2.3.1 Processes
-
-&.br1
-
-A program is some collection of code and other data, stored in a file (or noncompiled code).
-A process is the program in motion, the program itself *alongside* certain system states.
-
-The system states include (but are not limited to):
-
-- the processor state, including the program counter and register values
-- memory map, indicating what regions of memory are allocated (to the process)
-- [file descriptors](https://en.wikipedia.org/wiki/File_descriptor), unique identifiers for files
-
-
-&]
-
-
-
-&[middle35
-
-On a multitasking (multiprocessing) system, which is any modern desktop system, multiple processes are always running "at once".
-
-In reality, constantly one process is stopped and another is ran, switching between all of them ([context switching](https://en.wikipedia.org/wiki/Context_switch)).
-All "waiting" processes are put in a prioritized queue ([run queue](https://en.wikipedia.org/wiki/Run_queue)).
-
-Stopping is either done by the process itself (more on that later), or by the system when the process has been actively running for too much time.
-
-&]
-
-
-
-&[slide35
-
-#### Process Control Block
-
-All process information is stored in a data structure, called a *process control block* (or process descriptor).
-Not to be confused with a [printed circuit board](https://en.wikipedia.org/wiki/Printed_circuit_board)!
-A PCB's data can be split into three categories:
-
-1. **Process identification** - the ID of the process itself, of it's parent process, of it's owner (user), etc.
-2. **Process state** - as described, the processor state, etc.
- On a context switch, values in registers are put into the stopped PCB and then are loaded from the running PCB.
-3. **Process control information** - process state, memory map, privileges, etc.
-
-A process can be **forked**, meaning a new process is created, with the same underlying code (but not process states and ...).
-
-&]
-
-
-
-&[middle35
-
-#### Process states
-
-- **Created**: This is the initial state given to a new process. In this state, the process awaits a "ready" state.
-- **Ready** (Waiting): A process is put in the run queue and awaits being executed ("running" state).
-- **Running**: When the process's program is being currently executed by the CPU. The process can run in either *kernel mode*, having access to the kernel and user addresses, or *user mode*, having access only to it's own code and data.
-- **Blocked**: When a process cannot continue without external change, usually when waiting for an I/O device.
-- **Terminated**: The process has either completed execution or has been killed. The process itself is called a ["zombie process"](https://en.wikipedia.org/wiki/Zombie_process) (until it is removed).
-
-&]
-
-
-
-&[middle35
-
-#### Exit status
-
-Every process, before being deleted (and after being in a Terminated state) passes a small number, called the [exit status](https://en.wikipedia.org/wiki/Exit_status) (exit code), to it's parent process.
-For all intents and purposes, this number is an 8bit unsigned integer, meaning it's value is between 0 and 255.
-
-Pretty much universally, an exit code of 0 signifies a successful termination, and anything else specifies some sort of error code.
-Different programs specify the meaning of an exit code in different ways, some assign each number to a specific error, other use the bits representing the number as flags.
-
-&]
-
-
-
-&[slide35
-
-### 2.3.2 Memory management
-
-&.br2
-
-In ye olde days, you would save a bit of memory for the operating system and give all of the rest to the current process ([monoprogramming](https://en.wiktionary.org/wiki/monoprogramming)), which we wait until completion.
-
-This doesn't allow for context switching (disks are slow) and a blocked state forces the CPU to wait.
-
-Some bad ideas include: depending on the code of all processes to not use the same addresses, use only [relative addresses](https://en.wikipedia.org/wiki/Position-independent_code) (`-fPIC` option in `gcc`) or use a [table](https://en.wikipedia.org//wiki/Relocation_%28computing%29#Relocation_table) that the kernel fills out with addresses.
-
-&]
-
-
-
-&[slide35
-
-### Virtual memory
-
-&.br2
-
-&{fright
-![](./img/virtual-memory-by-Ehamberg.png)
-&(font18 *Image by [Ehamberg](https://commons.wikimedia.org/wiki/File:Virtual_memory.svg)* &)
-&}
-
-A program (process) works with some (sequential) addresses, and the OS (with the help of [hardware](https://en.wikipedia.org/wiki/Memory_management_unit)) translates/maps the process' addresses (logical/[virtual addresses](https://en.wikipedia.org/wiki/Virtual_address_space)) to real ones (physical addresses).
-
-Simplified memory management for the program, protected address space for each process and improved flexibility.
-
-&]
-
-
-
-&[slide35
-
-#### Segmentation (without paging)
-
-&.br2
-
-Initially, virtual memory was implemented with segmentation, where a process' memory is divided into segments for code, stack, heap, etc.
-Each segment is given a chunk of contiguous memory, which can be resized, and addresses are defined as the base segment (physical) address with an offset.
-
-In the modern day, segmentation isn't used by itself, since resizing segments could require reordering of memory and [external fragmentation](https://en.wikipedia.org/wiki/Fragmentation_%28computing%29#External_fragmentation), where there simply isn't enough contiguous memory, could occur.
-
-
-&]
-
-
-
-&[slide35
-
-#### Paging
-
-&.br3
-
-The virtual and physical memory is divided into fixed-sized chunks of consecutive addresses.
-A virtual memory chunk is called a **page**, while a physical memory chunk is called a (page) **frame**.
-Usually both have the same size of (at least) 4 KiB.
-
-Every process has a [page table](https://en.wikipedia.org/wiki/Page_table), which maps the process' pages to system frames.
-Thus every memory address is translated from it's page location to a frame location.
-
-&]
-
-
-
-&[slide35
-
-Advantages include:
-
-- elimination of [external fragmentation](https://en.wikipedia.org/wiki/Fragmentation_%28computing%29#External_fragmentation)
-- increased flexibility, allowed sharing of memory between processes (useful for shared libraries)
-- finding free memory is fast and easy, just use the first free pages you see
-- frames can be scattered
-- more efficient swapping, moving of memory from RAM to disk and back
-
-Disadvantages include:
-
-- longer memory access, because of the page table
-- [internal fragmentation](https://en.wikipedia.org/wiki/Fragmentation_%28computing%29#Internal_fragmentation), where one or multiple pages might be partially empty, leaving free space that cannot be used
-
-&]
-
-
-
-&[slide
-
-# 3. Linux from the inside
-
-Enough theory, time to have some fun and learn Linux!
-
-We'll be using [Linux Minimal Live](https://ivandavidov.github.io/minimal/#home) (just a bootable ISO) because it's:
-
-- very small, comprised of only the Linux kernel, GNU C library and Busybox
-- made by a fellow Bulgarian ![](/img/bg.svg =30)
-
-We're going to explore and look around the following stuff:
-
-- **Shells**: What a modern shell would often support on a Linux based OS
-- **Files and directories**: Naming conventions and commands to work with them
-- **Common configuration files**: Relevant configuration files, their purpose and syntax
-- **System management**: Other commands with which to modify your system
-
-&]
-
-
-
-&[middle18
-
-#### If you're following at home
-
-Owing to it's size, not everything we need comes out of the box, so I created [a script](./mll-set.sh) which installs what's needed.
-If you want to try it out yourself, after booting up Minimal Linux Live, type out and run:
-
-```
-wget -q http://unsecure.syndamia.com/mll-set.sh && chmod +x mll-set.sh && ./mll-set.sh
-```
-
-You might've noticed that the command above doesn't use the normal [https://syndamia.com/talks/linuxgraphy-by-strabo/mll-set.sh](./mll-set.sh) link.
-That is because, out of the box, MLL doesn't really support secure connections (https), so I've made only that file available without it.
-
-The script, in summary, installs bash, coreutils and shadow "packages" (from [http://s.minos.io/archive/bifrost/x86\_64](http://s.minos.io/archive/bifrost/x86_64)) to /usr/local/bin, creates /etc/passwd, /etc/bashrc and /etc/profile with some values in them and starts bash.
-
-&]
-
-
-
-&[slide
-
-## 3.1. Shells
-
-&.br2
-
-### Variables and data types
-
-Before talking about the different features newer shells support, we'll roughly cover variables and data types (mostly [bash](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameters) specifics).
-
-A variable, also called parameter, is created with the syntax (NO spaces between the =):
-
-```
-name=value
-```
-
-Where `name` is either a combination of letters (upper and lower case), numbers and the underscore character, which cannot begin with a number, or one of select few **positional** and **special** parameters.
-
-&]
-
-
-
-&[slide35
-
-#### Positional and special parameters
-
-[Positional parameters](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Positional-Parameters) are numbers from 1 to N, where each one corresponds to a shell (or function, or script) argument.
-
-Some of the [special parameters](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Special-Parameters) are:
-
-- `0`, corresponding to the shell's or script's name,
-- `@` is all positional parameters, separated by spaces
-- `#` is the number of positional parameters
-- `?` is the last executed (foreground) process
-- `$` is process ID of the current shell.
-
-`value`, without any special surrounding characters (more on that later), is treated as a string (but it mustn't have spaces!), however it may also be omitted, in which case it is the empty string `""`.
-
-&]
-
-
-
-&[slide35
-
-#### Data types
-
-In most shells, there are 3 data types: strings, integers and (one-dimensional) indexed arrays.
-[bash has more](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#index-declare), like references and associative arrays, but those aren't universal.
-
-A value is a **string** when surrounded by single `'` or double `"` quotes,
-an **integer** when it isn't surrounded by anything and composed only of digits (if there are letters, it is a string; it's [quite tricky](https://tldp.org/LDP/abs/html/untyped.html) when a value is interpreted as a string or integer) and
-an **array** when surrounded by braces `()`, where inside elements are strings or integers, separated by spaces.
-An indexed array can also be created by specifying the value at any index:
-
-```
-name[index]=value
-```
-
-&]
-
-
-
-&[slide
-
-#### Mixing types and operations
-
-```
-name=value
-```
-
-| Type |Value with| string operation | integer operation | array operation |
-|-------|----------|---------------------------------------|---------------------------------------|---------------------------------------------|
-|string | |value |0 |value when index is 0, empty string otherwise|
-|integer| |empty string, but sometimes value |value |value when index is 0, empty string otherwise|
-|array | |operation is done on element at index 0|operation is done on element at index 0|value |
-
-&]
-
-
-
-&[slide
-
-#### Parameter expansion
-
-With [parameter expansion](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion), actions are done with the general variable (entity) or on strings and arrays values.
-Operations on integers are done with [arithmetic expansion](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Arithmetic-Expansion).
-
-Parameter expansion is started with the character `$` and either a name or curly braces.
-Retrieving a value is done with the forms `$name`, `${name}` and `${name[index]}` for arrays.
-
-Some parameter expansions in bash:
-
-- `${#parameter}` length of characters
-- `${parameter:offset}` and `${parameter:offset:length}` return substring from index offset
-- `${parameter/pattern/string}` return a string, where every match on pattern is replaced by string
-- `${name[@]}` a (space separated) sequence of indices from 0 to length (for defined values) of array name
-
-&]
-
-
-
-&[slide
-
-#### Arithmetic expansion
-
-Arithmetic expansions allow evaluation of [arithmetic expressions](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Arithmetic).
-They're in the form `$(( expression ))`.
-
-Some useful expressions are:
-
-- `++name`, `name++`, `--name`, `name++` postfix and prefix incrementation and decrementation
-- `+`, `-`, `*`, `/`, `%` normal arithmetic operators, `**` exponentiation
-- `~`, `<<`, `>>`, `&`, `^`, `|` bitwise operators
-- `==`, `!=`, `>`, `>=`, `<`, `<=` logical comparison
-- `!`, `&&`, `||` logical not, and, or
-- `expr ? exprTrue : exprFalse` conditional
-- `=`, `+=`, ..., `<<=`, ... assignment operators
-- `expr1 , expr2` consecutive expressions and `(expr)` bracing
-
-Expressions work with both variable names and integers.
-
-&]
-
-
-
-&[middle
-
-### Bourne shell
-
-Most modern shells support a lot of the more defying features of the [Bourne Shell](https://en.wikipedia.org/wiki/Bourne_shell), which include:
-
-- [Job control](https://en.wikipedia.org/wiki/Job_control_%28Unix%29): Management of currently running groups of processes
- + `&`: A process can be ran in the background with an ampersand (&) at the end of the command:
-
- ```
- command [args...] &
- ```
-
- + `Ctrl+z`: suspend the currently running (foreground) job
- + `bg`: start a suspended job in the background
- + `fg`: resume the last job to be put in the background and make it the current job with which we're interacting
- + `jobs`: list all active (background) jobs
-
-&]
-
-
-
-&[middle
-
-- &emsp;
- + Every job is identified with a **Job ID** (number), which you can use by prepending a percentage sign. Example, to resume the job with JID 4:
-
- ```
- fg %4
- ```
- + For managing everything, usually there is a *job table*.
- Upon shell termination, the shell tells all jobs in that table to terminate and waits for them.
- `disown`: remove a job from the job table
- + `kill`: send a signal to the process or job. Then that process will have to handle it accordingly.
- Common ones are `-KILL` to immediately stop the process, `-QUIT` to quit it, `-ABRT` to cancel the current action, `-TERM` shut down (orderly), `-STOP` shut down (forcefully)
-
-&]
-
-
-
-&[middle27
-
-- [heredoc](https://en.wikipedia.org/wiki/Here_document): File literal, meaning it is a user "string" which is interpreted as a file
- + start with `<< NAME`, where NAME can be anything you want, it is used to mark the beginning and end of a heredoc. `<<` is also a redirection symbol
- + on every new line write out your text, all characters will be preserved
- + to end it, write out `NAME` on the beginning of a new empty line. Example:
-
- ```
- cat << MYFILE
- This is
- some
- text
- MYFILE
- ```
-
-- control operators: Control what command is executed, depending on [exit status](https://en.wikipedia.org/wiki/Exit_status)
- + `expr1 && expr2`: Run expr2, only if expr1 exited successfully
- + `expr1 || expr2`: Run expr2 if expr1 exited unsuccessfully
- + `expr1 ; expr2`: Run expr2 after expr1 (sequential execution)
-
-&]
-
-
-&[middle27
-
-- [redirection](https://en.wikipedia.org/wiki/Redirection_%28computing%29): Outside of having `<` and `>` for I/O redirection, often there is also
- + `>>`: Acts like `>`, putting text into a file, but rather than overwriting everything, it appends it
- + `<<`: As explained, for heredocs
- + `<<<`: To the right is a string ([herestring](https://en.wikipedia.org/wiki/Here_document#Here_strings)), and it is interpreted as a file
-
- ```
- cat <<< "Hello World!"
- ```
-
- + **Standard input**, **standard output** and **standard error** are all **files** with which the shell works.
- Typing text in the shell puts it into stdin, command output are put into stdout (and shown to the user) and errors are put into stderr (also shown to the user).
- Each one of them is numbered from 0 to 2, and you can specify redirection by appending or prepending it to the redirection symbol.
- * `N>outputfile`: redirects the output from standard stream N into outputfile
- * `N>&M`: redirects the output from standard stream N into standard stream M
- * `N<inputfile`: redirects input file contents to standard stream N
- * `N<&M`: redirects standard stream M to standard stream N
-
-&]
-
-
-
-&[middle27
-
-- [built-in test command](https://en.wikipedia.org/wiki/Test_%28Unix%29): With `test` you can do conditional expressions. You can also often use brackets `[ args... ]` instead of `test args...`
- + Some of the available file checks
- * `-e FILENAME`: FILENAME exists
- * `-d FILENAME`: if FILENAME is a directory
- * `-h FILENAME`: if FILENAME is a symbolic link
- * `-w FILENAME`: you can write in FILENAME
- + Some of the available string checks
- * `-n STR`: string STR has nonzero length
- * `-z STR`: string STR has length zero
- * `STR1 = STR2` and `STR1 != STR2`: self explanatory
- + Some of the available number checks
- * `INT1 -eq INT2`: equal integers
- * `INT1 -gt INT2`: INT1 > INT2
- * `INT1 -gt INT2`: INT1 >= INT2
- + Operators: `!` - negation, `-a` - binary AND, `-o` - binary OR, parentheses for grouping (escaped with `\`)
-
-
-&]
-
-
-
-&[slide
-
-- [scripting support](https://en.wikipedia.org/wiki/Shell_script): Running commands from top to bottom of a file
- + `#`: Everything between a # and the end of the line denotes a comment
- + `#!`: If on the first line of the file, is treated as a [shebang](https://en.wikipedia.org/wiki/Shebang_%28Unix%29), which specifies what interpreter to be used for the script
-
-- compound commands: Structures for flow control
- In all examples, `test-command` is any command (or combination with control operators), and logic is based on exit code.
-
- + conditional
-
- ```
- if test-command ; then commands-if-true
- elif test-command ; then commands-if-true
- else commands-if-true
- fi
- ```
-
- elif statements can appear multiple times, both elif and else are optional
-
-&]
-
-
-
-&[slide
-
-- &emsp;
- &.br1
-
- ```
- case word in (pattern | ...) commands-if-true ;; ... esac
- ```
-
- Where the beginning brace can be ommited.
- Patterns are according to [bash's pattern matching](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Pattern-Matching)
-
- + loops
-
- ```
- while test-command; do commands-if-true; done
- ```
-
- ```
- for name in words...; do commands-if-true; done
- ```
- If `in words...` is ommited, positional arguments are used
-
-&]
-
-
-
-&[middle35
-
-## 3.2. Files and directories
-
-- `/dev`: devices
-- `/proc`: process information
-
-&.br3
-
-- `/bin`: main command programs (binaries), used by users
-- `/sbin`: command programs, used for the system operation
-- `/usr`: other system resources
- + `/usr/bin`: all other user command binaries
-
-&]
-
-
-
-&[slide
-
-#### Everyday file system commands
-
-- `mkdir`: create directories
-- `rm`: remove a (hardlink to) file or directory
-- `mv`: move file (or directory) to another directory
-- `cp`: copy a file
-- `ln`: create hard (or soft, with `-s`) links to files (inodes)
-- `ls`: list directory contents
-
-#### Other useful file system commands
-
-- `shred`: overwrite file contents
-- `dd`: do many things with files, like modifying and duplicating data across devices and partitions, (basic) data recovery and generating files
-- `du`: estimate file usage
-- `stat`: display status for file or file system
-- `chwon`: change owner of an inode
-- `chgrp`: change group of an inode
-- `chmod`: change file modes
-- `find`: search for a file inside a directory (recursively)
-
-&]
-
-
-
-&[slide
-
-#### Everyday text (file) commands
-
-- `echo`: prints a given string to standard output
-- `cat`: sequentially prints files to standard output
-- `less`: view files with support for scrolling
-- `head`: print the first lines (or characters) of a file
-- `tail`: print the last lines (or characters) of a file
-
-#### Other useful text (file) commands
-
-- `grep`: searches for matches in a file, using simplified regular expressions. `egrep` for extended regex and `fgrep` for string match (as-is).
-- `sed`: filter and transform text from files, according to regex
-- `tr`: translate, map (more than one to one for example) and delete characters
-- `cut`: remove parts of text from each line
-- `strings`: find embedded text inside binary files
-- `truncate`: shrink or extend the size of a file
-- `wc`: count words inside file
-- `diff`: compare files and show their differences
-
-&]
-
-
-
-&[middle
-
-#### Device commands
-
-- `mount`: bind another file system to a location in the file system
-- `umount`: remove binding to a file system
-- `lsusb`: lists USB devices
-- `lspci`: lists PCI devices
-
-#### System information commands
-
-- `date`: display current date and time
-- `hostname`: show (or set) the systems hostname (network name)
-- `free`: display free memory on the system
-
-&]
-
-
-
-&[slide
-
-#### User and group management
-
-- `useradd`: creates a new user (with a password)
-- `userdel`: remove a user and all of his files
-- `usermod`: modify a user account, including his name and groups
-- `passwd`: change password of a user. With `-l` user could be locked (impossible to log in)
-
-&.br3
-
-- `groupadd`: create a new group
-- `groupdel`: remove a group
-- `groupmod`: modify an existing group
-
-&.br3
-
-- `w`: show who is logged in and what they are doing
-- `who`: show who is logged in
-- `whomai`: print username
-- `login`: establish a new connection to the system
-
-&]
-
-
-
-&[slide
-
-- `/etc`: system configuration files
- &.br2
-
- + `/etc/group`: the data for all groups is stored here, in the format
-
- ```
- GROUPNAME:PASSWORD:GID:USERS...
- ```
-
- + `/etc/passwd`: the data for all users is stored here, in the format
-
- ```
- USERNAME:PASSWORD:UID:GID:USERINFO:HOMEDIR:SHELL
- ```
-
- + `/etc/shadow`: stores other user data, especially the password as an encrypted string, in the format
-
- ```
- USERNAME:PASSWORD:LASTCHANGED:MINBETWEENCHANGES:MAXBETWEENCHANGES:WARNEXPIRE:INACTIVEDAYS:EXPIRE
- ```
-
-&]
-
-
-
-&[slide27
-
-- &emsp;
-
- + `/etc/fstab`: read on boot by mount to setup devices in fs
-
- ```
- # device-spec mount-point fs-type options dump pass
- /dev/sda1 / ext4 defaults 1 1
- UUID=123A-456B /boot vfat noauto,noatime 1 2
- LABEL=Vault /mnt/Vault auto nosuid,nodev,nofail 0 0
- ```
-
- + `/etc/hosts`: list of host names (domain names) and their corresponding IP address, when a DNS server doesn't do the job
-
- ```
- # ipaddress domains
- 127.0.0.1 localhost mywebsite.com something.else
- 62.44.101.138 my.uni
- ```
-
- + `/etc/bashrc`: global defaults and aliases used by the bash shell
- + `/etc/motd`: message of the day (unexecuted text), shown after login but before the shell is ran
-
-&]
-
-
-
-&[middle35
-
-- `/usr`: other system resources
- + `/usr/lib`: library files
- + `/usr/local`: local, system software
- + `/usr/share`: architecture independent data, like manuals
-- `/var`: variable data, like logs and cache
-- `/home`: home directories of all users
-- `/lib`: libraries and kernel modules
-- `/mnt`: mounted temporary filesystems
-- `/root`: home directory for the root user
-
-&]
-
-
-
-&[slide
-
-# 4. Software licensing
-
-It is important to note that most software in Linux, including the kernel itself, is under a variety of open licenses.
-An open license is a license which allows others to reuse the original work, under some restrictions.
-
-For software, such a license is applied to the source code from which the original application was made.
-Some commonly used ones, with a (NON-LEGALLY BINDING) summary include:
-
-- [MIT](https://en.wikipedia.org/wiki/MIT_License): the author is not responsible for anything that the code does
-- [BSD-3-Clause](https://en.wikipedia.org/wiki/BSD_licenses): use the same license (copyleft), the author is not responsible for anything that the code does
-- [GNU GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License): disclose the original project and use the same license ([copyleft](https://en.wikipedia.org/wiki/Copyleft))
-
-This is important, since pretty much everything can be freely modified by anyone (for the better or worse, but generally better).
-
-&]
-
-
-
-&[slide35
-
-# 5. What makes up a useful OS
-
-A Linux-based operating system is nothing more than the Linux kernel, combined with an assortment of programs.
-Overall, the main elements that make up a useful *desktop* operating system (alongside a command-line shell) are:
-
-&.br1
-
-1. **Bootloader**: load the kernel and operating system
-2. **Init system**: well managed way to start everything inside the OS
-3. **Package manager**: way to manage our binaries
-4. **Desktop manager**: graphical shell
-
-&]
-
-
-
-&[slide
-
-## 5.1. Bootloader
-
-The computer boot process is a relay race.
-
-In a "standard" BIOS-MBR boot configuration:
-
-```
-BIOS -> Master Boot Record -> Active Parition -> Bootloader ->
--> Boot menu (optional) -> Kernel -> Everything else
-```
-
-- [BIOS](https://en.wikipedia.org/wiki/BIOS): a small chip with code that is ran upon power up
-- [MBR](https://en.wikipedia.org/wiki/Master_boot_record): small amount of space at the very start of the disk, that contains some (bootstrap) code and partition information. The BIOS hands off execution to the bootstrap code.
-- Active partition: MBR loads and runs code from the beginning of the partition (boot sector), which starts the bootloader
-- [Bootloader](https://en.wikipedia.org/wiki/Bootloader): the first complex program, which manages kernels, shows a menu, allows for debugging and so on
-
-&]
-
-
-
-&[middle
-
-The BIOS is baked into the motherboard, the MBR is pretty universal (and it's less than 512 bytes) and the kernel we know and love.
-
-That leaves us with the need for a bootloader.
-On Linux, the most used one is called [GRUB](https://en.wikipedia.org/wiki/GNU_GRUB).
-
-It's config is found in `/etc/default/grub` (which is then fully generated with `grub-mkconfig`) and can be "installed in the partition" with `grub-install`.
-
-```
-GRUB_DEFAULT=0
-GRUB_TIMEOUT=5
-GRUB_TIMEOUT_STYLE=menu
-GRUB_CMDLINE_LINUX=""
-GRUB_CMDLINE_LINUX_DEFAULT=""
-GRUB_GFXMODE=640x480
-```
-
-&]
-
-
-
-&[slide27
-
-## 5.2. Init system
-
-Now we need to load the user stuff, like a network manager, the graphical user interface and so on.
-In Minimal Linux Live, this is done by some hard written scripts, which aren't very modular or extensible.
-
-[Init systems](https://en.wikipedia.org/wiki/Init) use configuration files, called service, to start a program in some way.
-
-- [systemd](https://en.wikipedia.org/wiki/Systemd), which also aims to also provide easy system configuration
-- [openrc](https://en.wikipedia.org/wiki/OpenRC), a simple and modern system
-
-```
-[Unit]
-Description=Service
-[Service]
-Type=simple
-User=root
-ExecStart=/usr/local/sbin/script.sh
-[Install]
-WantedBy=multi-user.target
-```
-
-&]
-
-
-
-&[slide
-
-## 5.3. Package manager
-
-&.br1
-
-Programs are just executable files, usually placed in a specific folder, like `/usr/bin`.
-
-- MLL comes with ~100 executables (and ~230 after my script)
-- my Debian server has ~1000 installed packages
-- my current desktop Gentoo setup has ~1500 installed packages
-- my old Fedora setups have reached ~3000 packages on multiple occasions
-
-Updating all of them means replacing all of the binaries, means tracking where each one came from, installing a new one might require installing multiple others and so on.
-
-On modern systems, managing binaries is automated by an application called a package manager.
-
-&]
-
-
-
-&[middle35
-
-Additional benefits of package management automation include:
-
-- checking for package validity (and tampering)
-- utilising multiple server mirrors
-- automatic dependency management and installation
-- version caveats
-- (indirectly) improved stability because of maintainer compatibility checks
-
-&.br1
-
-```
-apt install PKG
-apt remove PKG
-apt upgrade
-```
-
-&]
-
-
-
-&[slide
-
-## 5.4. Window systems
-
-A widow system is your graphical shell: the graphical way to interact with your computer (the kernel).
-It's main components are:
-
-&.br1
-
-- **Window manager**: the overall system with which you create, remove, resize and work with windows. They are generally separated into two types:
- + *Stacked*: this is what you know, windows are just rectangles floating about, and can be put one over each other
- + *Tiled*: windows take up a predefined (but changeable) portion of the screen
-- **Compositor**: adds an unseen window buffer, allowing additional processing, before a window is shown. This powers transparency, animation effects and more.
-- **Session manager**: graphical application that manages the window managers (outside WMs), think of it as a login window
-
-&]
-
-
-
-&[slide27
-
-# 6. War on distros
-
-A distribution is a complete set of of all applications that you might use.
-
-Overall, there are 4-5 distributions from which 90% of all other distros are based upon:
-
-1. [Slackware](http://www.slackware.com/): as the oldest still maintained distro, it served as inspiration for a lot of other distros. It aims to be as simple and as close to UNIX as possible.
-2. [Debian](https://www.debian.org/) (and [Ubuntu](https://ubuntu.com/)): it is the most popular distribution (if we also include Ubuntu). Ubuntu aims to be modern and fancy, while Debian aims to be as stable as possible, which makes it the most popular in server usage.
-3. [Gentoo](https://www.gentoo.org/): the distribution which defined non-binary software distribution
-4. [Arch Linux](https://archlinux.org/): a very popular and modern distribution with the goal of providing the latest and greatest software.
-
-We haven't touched too much, but Linux distributions aren't limited to desktop or server computers.
-
-1. [AOSP](https://en.wikipedia.org/wiki/Android_%28operating_system%29#AOSP): the base of the whole Android operating system
-2. [OpenWRT](https://en.wikipedia.org/wiki/OpenWrt): a router operating system
-
-&]
-
-
-
-&[slide35
-
-# 7. Demos - virtual machine and setup from zero
-
-&.br2
-
-Now for the best part: we'll be installing a Linux distribution on a virtual machine and then directly on a laptop, running Windows 10!
-
-I've chosen to install [Linux Mint](https://linuxmint.com/), since it is generally targeted towards newcomers and will feel familiar enough to Windows users.
-
-Currently there won't be an official recording of the process, you should've been here live!
-
-&]
-
-
-
-&[title35
-
-# Thank you for your time
-
-&]
-
-
-
-&[slide18
-
-# Sources
-
-All of these contain, at most, small paraphrased sentences in the slides.
-They served as personal educational and reference tools.
-
-- [wikipedia](https://en.wikipedia.org/) and [stackexchange](https://stackexchange.com/) have been used extensively and linked where appropriate.
-- [CS416 - Operating Systems Design](https://people.cs.rutgers.edu/~pxk/416/index.html) by [Paul Krzyzanowski](https://people.cs.rutgers.edu/~pxk/rutgers/) at [Rutgers State University](https://www.cs.rutgers.edu/)
-- [Origins and History of UNIX, 1969-1995](https://web.archive.org/web/20220713165958/https://homepage.cs.uri.edu/~thenry/resources/unix_art/ch02s01.html) from [The Art of Unix Programming](https://web.archive.org/web/20220611160552/https://homepage.cs.uri.edu/~thenry/resources/unix_art/index.html) by Eric Steven Raymond
-- [Ken Thompson interviewed by Brian Kernighan at VCF East 2019](https://www.youtube.com/watch?v=EY6q5dv_B-o) by [Vintage Computer Federation](https://vcfed.org/)
-- [Pseudo Terminals presentation](http://www.cs.uah.edu/~kkeen/CS590/Pseudo%20Terminals.ppt) from [CS590](http://www.cs.uah.edu/~kkeen/CS590/) by [Kevin J. Keen](http://www.cs.uah.edu/~kkeen/kkeen.html) at [University of Alabama in Huntsville](https://www.uah.edu/)
-- [Hard links and Unix file system nodes](https://teaching.idallen.com/dat2330/04f/notes/links_and_inodes.html) from [DAT 2330 Introduction to Operating Systems](https://teaching.idallen.com/dat2330/04f/) by [Ian D. Allen](http://www.idallen.com/)
-- [Virtual Memory, OS Course Notes](https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/9_VirtualMemory.html) by [Dr. John T. Bell](https://www.cs.uic.edu/~jbell/) at [University of Illinois Chicago](https://www.cs.uic.edu),
- which is directly based on [Operating System Concepts, 9th Edition](https://archive.org/details/operating-system-concepts-9e) by [Abraham Silberschatz](https://codex.cs.yale.edu/avi/)
-- [Chapter 9 Preview - Virtual Memory](http://csapp.cs.cmu.edu/3e/home.html) from [Computer Systems: A Programmer's Perspective](http://csapp.cs.cmu.edu/) by [Randal E. Bryant](http://www.cs.cmu.edu/~bryant) and [David R. O'Hallaron](http://www.cs.cmu.edu/~droh)
-- [Memory Management, Lecture Notes](https://www.cse.iitb.ac.in/~mythili/teaching/cs347_autumn2016/notes/07-memory.pdf) by [Mythili Vutukuru](https://www.cse.iitb.ac.in/~mythili/)
-- [Paging advantages and disadvantages](http://www.cs.iit.edu/~cs561/cs351/VM/paging%20advantages%20and%20disadvantages.html) by Charles R. Bauer at [Computer Science Departmemnt of Illinois Institute of Technology](http://www.cs.iit.edu/)
-- [Bash Reference Manual](https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html) by the [GNU project](https://www.gnu.org/) and [ksh manual](https://man.openbsd.org/ksh) by the [OpenBSD project](https://www.openbsd.org/)
-- [Manual of the Bourne Shell on Version 7](https://www.in-ulm.de/~mascheck/bourne/v7/), archived by [Sven Mascheck](https://www.in-ulm.de/~mascheck/)
-- [/usr hierarchy](https://www.linuxbase.org/betaspecs/fhs/fhs/ch04.html) from [Filesystem Hierarchy Standard](https://www.linuxbase.org/betaspecs/fhs/fhs/index.html) by [Linux Foundation](https://www.linuxfoundation.org/), Daniel Quinlan, Paul 'Rusty' Russell, Christopher Yeoh
-- [Filesystem Hierarchy Standard](https://www.pathname.com/fhs/pub/fhs-2.3.pdf) by Rusty Russel, Daniel Quinlan and Christopher Yeoh
-- [User & Group Names](https://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/usernames.html#FTN.AEN26405) from [Linux Standard Base Core Specification](https://refspecs.linuxbase.org/LSB_3.1.1/LSB-Core-generic/LSB-Core-generic/book1.html) by [Free Standards Group](https://en.wikipedia.org/wiki/Free_Standards_Group)
-- [Managing User Accounts](https://docstore.mik.ua/orelly/linux/run/ch05_07.htm) from [Running Linux, Third Edition](https://docstore.mik.ua/orelly/linux/run/index.htm) by Matt Welsh, Matthias Kalle Dalheimer, and Lar Kaufman
-- [The BIOS/MBR Boot Process](https://neosmart.net/wiki/mbr-boot-process/) by [NeoSmart's Knowledgebase](https://wiki.neosmart.net/)
-
-# Licensing
-
-Images on slides "2.1. shell" and "2.2. UNIX-style file system" are made by me and [licensed as content](/license.html).
-The script [mll-set.sh](http://syndamia.com/talks/linuxgraphy-by-strabo/mll-set.sh) is licensed under MIT (though I don't see it as substatial enough to be licensed under anything).
-
-&]
diff --git a/src/styles.css b/src/styles.css
index 8721bbc..bfc9c3b 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -95,6 +95,13 @@ body, td, th { font-size: 18px; font-family: 'Tabler', sans-serif; }
nav, article { background-color: var(--bg-color); }
+ /* Lists with line-separated items (ORDERED_LIST, UNORDERED_LIST) */
+li > div:only-child,
+li > div:only-child > img {
+ display: block;
+ margin: 1em 0em;
+}
+
/*## Wrapper ##*/
#content-wrapper {
@@ -328,6 +335,12 @@ a:hover, a strong:hover { color: var(--a-hover-color); }
sup a, dt a { border: none; }
a * { color: var(--fg-color); }
+code > a, code > a:hover {
+ color: var(--fg-color);
+ text-decoration: none;
+ border: none;
+}
+
/*### Wrapper > Article > i, em, strong ###*/
i, em { color: var(--em-color); }
diff --git a/src/teaching.du b/src/teaching.du
new file mode 100644
index 0000000..dc12de2
--- /dev/null
+++ b/src/teaching.du
@@ -0,0 +1,12 @@
+# Teaching
+
+This is a list of all the subjects I've taught professionally.
+
+\n
+
+:defs
+; [$bg] 2023-2024 &emsp; [url /teaching/oop-2023 З520 Обектно-ориентрано програмиране - практикум, КН, 8 група]
+: Хоноруван преподавател във [url https://www.fmi.uni-sofia.bg/ ФМИ] на специалност [url https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki Компютърни науки]
+
+; [$bg] 2023-2024 &emsp; [url /teaching/upp-2023 3107 Увод в програмирането - практикум, КН, 8 група]
+: Хоноруван преподавател във [url https://www.fmi.uni-sofia.bg/ ФМИ] на специалност [url https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki Компютърни науки]
diff --git a/src/teaching.md b/src/teaching.md
deleted file mode 100644
index c36de4d..0000000
--- a/src/teaching.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Teaching
-
-This is a list of all the subjects I've taught professionally.
-
-<br>
-
-&.bg 2023-2024 &emsp; [З520 Обектно-ориентрано програмиране - практикум, КН, 8 група](/teaching/oop-2023)
-: Хоноруван преподавател във [ФМИ](https://www.fmi.uni-sofia.bg/) на специалност [Компютърни науки](https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki)
-
-&.bg 2023-2024 &emsp; [3107 Увод в програмирането - практикум, КН, 8 група](/teaching/upp-2023)
-: Хоноруван преподавател във [ФМИ](https://www.fmi.uni-sofia.bg/) на специалност [Компютърни науки](https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki)
diff --git a/src/teaching/index.du b/src/teaching/index.du
new file mode 100644
index 0000000..dc12de2
--- /dev/null
+++ b/src/teaching/index.du
@@ -0,0 +1,12 @@
+# Teaching
+
+This is a list of all the subjects I've taught professionally.
+
+\n
+
+:defs
+; [$bg] 2023-2024 &emsp; [url /teaching/oop-2023 З520 Обектно-ориентрано програмиране - практикум, КН, 8 група]
+: Хоноруван преподавател във [url https://www.fmi.uni-sofia.bg/ ФМИ] на специалност [url https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki Компютърни науки]
+
+; [$bg] 2023-2024 &emsp; [url /teaching/upp-2023 3107 Увод в програмирането - практикум, КН, 8 група]
+: Хоноруван преподавател във [url https://www.fmi.uni-sofia.bg/ ФМИ] на специалност [url https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki Компютърни науки]
diff --git a/src/teaching/index.md b/src/teaching/index.md
deleted file mode 100644
index c36de4d..0000000
--- a/src/teaching/index.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Teaching
-
-This is a list of all the subjects I've taught professionally.
-
-<br>
-
-&.bg 2023-2024 &emsp; [З520 Обектно-ориентрано програмиране - практикум, КН, 8 група](/teaching/oop-2023)
-: Хоноруван преподавател във [ФМИ](https://www.fmi.uni-sofia.bg/) на специалност [Компютърни науки](https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki)
-
-&.bg 2023-2024 &emsp; [3107 Увод в програмирането - практикум, КН, 8 група](/teaching/upp-2023)
-: Хоноруван преподавател във [ФМИ](https://www.fmi.uni-sofia.bg/) на специалност [Компютърни науки](https://www.fmi.uni-sofia.bg/bg/kompyutrni-nauki)
diff --git a/src/teaching/oop-2023/index.du b/src/teaching/oop-2023/index.du
new file mode 100644
index 0000000..20e5282
--- /dev/null
+++ b/src/teaching/oop-2023/index.du
@@ -0,0 +1,64 @@
+# Обектно-ориентирано програмиране - практикум, Компютърни науки, 8 група
+
+Материали на проведените през 2023/2024 практикуми по Обектно-ориентирано програмиране на Компютърни науки (2 поток), 8 група.
+
+=[Зала:]= ФМИ 120 ||
+=[Време:]= 13:15 - 15:00 ||
+=[Ден:]= Четвъртък
+\n
+=[Директни връзки:]=
+[url ../upp-2023/week1/welcome.html?a#section-4 Контакт с мен] |
+[url https://github.com/Syndamia/oop-2023-solutions Решения на задачи] |
+[url https://github.com/Aleksis99/Object-Oriented-Programming_FMI_2023-2024 Материали от семинари] |
+[url https://learn.fmi.uni-sofia.bg/course/view.php?id=10041 Курс в мудъл]
+
+:table
+|=&#8470;=||=Дата=||=Материали=|
+
+|:1 :||:22.02.2024:|
+|:[url ./week1/organization.html?a Организационно] \|\| [url ./week1/good-software.html?a Основни добри софтуерни практики] \|\| [url ./week1/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week01 Решения] \|\| [url https://classroom.github.com/a/UPJOzHty GitHub classroom]:|
+
+|:2 :||:29.02.2024:|
+|:[url ./week2/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week02 Решения] \|\| [url https://classroom.github.com/a/3qPsfyyI GitHub classroom]:|
+
+|:3 :||:07.03.2024:|
+|:[url ./week3/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week03 Решения] \|\| [url https://classroom.github.com/a/KPMqXsFp GitHub classroom]:|
+
+|:4 :||:14.03.2024:|
+|:[url ./week4/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week04 Решения] \|\| [url https://classroom.github.com/a/qa_FfWeG GitHub classroom]:|
+
+|:5 :||:21.03.2024:|
+|:[url ./week5/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week05 Решения] \|\| [url https://classroom.github.com/a/42ZZ56Mg GitHub classroom]:|
+
+|:6 :||:28.03.2024:|
+|:[url ./week6/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week06 Решения] \|\| [url https://classroom.github.com/a/rzSTn5pu GitHub classroom]:|
+
+|:7 :||:04.04.2024:|
+|:[url ./week7/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week07 Решения] \|\| [url https://classroom.github.com/a/vvZENbkX GitHub classroom]:|
+
+|:8 :||:11.04.2024:|
+|:[url ./week8/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week08 Решения] \|\| [url https://classroom.github.com/a/7d0MBjcK GitHub classroom]:|
+
+|:9 :||:18.04.2024:|
+|:[url ./week9/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week09 Решения] \|\| [url https://classroom.github.com/a/wlL1oUg2 GitHub classroom]:|
+
+|:10:||:25.04.2024:|
+|:[url ./week10/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week10 Решения] \|\| [url https://classroom.github.com/a/PbkITWhF GitHub classroom]:|
+
+|:11:||:09.05.2024:|
+|:[url ./week11/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week11 Решения] \|\| [url https://classroom.github.com/a/oYQehcnN GitHub classroom] =[Това упражнение е от 11:15 до 13:15]=:|
+
+|:12:||:09.05.2024:|
+|:[url ./week12/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week12 Решения] \|\| [url https://classroom.github.com/a/o7hNz1pr GitHub classroom]:|
+
+|:13:||:16.05.2024:|
+|:[url ./week13/ Задачи] \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week13 Решения] \|\| [url https://classroom.github.com/a/GvV1wrC1 GitHub classroom]:|
+
+|:14:||:23.05.2024:|
+|:[url ./week14/ Задачи] <!-- \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week12 Решения] --> \|\| [url https://classroom.github.com/a/K0XomKEP GitHub classroom]:|
+
+|:15:||:30.05.2024:|
+|:[url ./week15/ Задачи] <!-- \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week12 Решения] --> \|\| [url https://classroom.github.com/a/z2QadyEE GitHub classroom] =[Това упражнение е от 11:15 до 13:15]=:|
+
+|:16:||:06.06.2024:|
+|:[url ./week16/ Задачи] <!-- \|\| [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week12 Решения] --> \|\| [url https://classroom.github.com/a/BWjw2dUC GitHub classroom]:|
diff --git a/src/teaching/oop-2023/index.md b/src/teaching/oop-2023/index.md
deleted file mode 100644
index 63acb0f..0000000
--- a/src/teaching/oop-2023/index.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# Обектно-ориентирано програмиране - практикум, Компютърни науки, 8 група
-
-Материали на проведените през 2023/2024 практикуми по Обектно-ориентирано програмиране на Компютърни науки (2 поток), 8 група.
-
-**Зала:** ФМИ 120 ||
-**Време:** 13:15 - 15:00 ||
-**Ден:** Четвъртък
-<br>
-**Директни връзки:**
-[Контакт с мен](../upp-2023/week1/welcome.html?a#section-4) |
-[Решения на задачи](https://github.com/Syndamia/oop-2023-solutions) |
-[Материали от семинари](https://github.com/Aleksis99/Object-Oriented-Programming_FMI_2023-2024) |
-[Курс в мудъл](https://learn.fmi.uni-sofia.bg/course/view.php?id=10041)
-
-|&#8470;|Дата|Материали|
-|-------|----|---------|
-|1 |22.02.2024|[Организационно](./week1/organization.html?a) \|\| [Основни добри софтуерни практики](./week1/good-software.html?a) \|\| [Задачи](./week1/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week01) \|\| [GitHub classroom](https://classroom.github.com/a/UPJOzHty)|
-|2 |29.02.2024|[Задачи](./week2/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week02) \|\| [GitHub classroom](https://classroom.github.com/a/3qPsfyyI)|
-|3 |07.03.2024|[Задачи](./week3/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week03) \|\| [GitHub classroom](https://classroom.github.com/a/KPMqXsFp)|
-|4 |14.03.2024|[Задачи](./week4/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week04) \|\| [GitHub classroom](https://classroom.github.com/a/qa_FfWeG)|
-|5 |21.03.2024|[Задачи](./week5/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week05) \|\| [GitHub classroom](https://classroom.github.com/a/42ZZ56Mg)|
-|6 |28.03.2024|[Задачи](./week6/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week06) \|\| [GitHub classroom](https://classroom.github.com/a/rzSTn5pu)|
-|7 |04.04.2024|[Задачи](./week7/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week07) \|\| [GitHub classroom](https://classroom.github.com/a/vvZENbkX)|
-|8 |11.04.2024|[Задачи](./week8/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week08) \|\| [GitHub classroom](https://classroom.github.com/a/7d0MBjcK)|
-|9 |18.04.2024|[Задачи](./week9/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week09) \|\| [GitHub classroom](https://classroom.github.com/a/wlL1oUg2)|
-|10|25.04.2024|[Задачи](./week10/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week10) \|\| [GitHub classroom](https://classroom.github.com/a/PbkITWhF)|
-|11|09.05.2024|[Задачи](./week11/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week11) \|\| [GitHub classroom](https://classroom.github.com/a/oYQehcnN) **Това упражнение е от 11:15 до 13:15**|
-|12|09.05.2024|[Задачи](./week12/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week12) \|\| [GitHub classroom](https://classroom.github.com/a/o7hNz1pr)|
-|13|16.05.2024|[Задачи](./week13/) \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week13) \|\| [GitHub classroom](https://classroom.github.com/a/GvV1wrC1)|
-|14|23.05.2024|[Задачи](./week14/) <!-- \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week12) --> \|\| [GitHub classroom](https://classroom.github.com/a/K0XomKEP)|
-|15|30.05.2024|[Задачи](./week15/) <!-- \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week12) --> \|\| [GitHub classroom](https://classroom.github.com/a/z2QadyEE) **Това упражнение е от 11:15 до 13:15**|
-|16|06.06.2024|[Задачи](./week16/) <!-- \|\| [Решения](https://github.com/Syndamia/oop-2023-solutions/tree/main/week12) --> \|\| [GitHub classroom](https://classroom.github.com/a/BWjw2dUC)|
diff --git a/src/teaching/oop-2023/week1/good-software.md b/src/teaching/oop-2023/week1/good-software.du
index 79a51b0..94bf593 100644
--- a/src/teaching/oop-2023/week1/good-software.md
+++ b/src/teaching/oop-2023/week1/good-software.du
@@ -1,54 +1,48 @@
# Основни добри софтуерни практики - ООП, Седмица 1, 22.02.2024
+\n
+
Миналия семестър не ни стигна времето да обсъдим домашното по-сериозно.
Главния проблем, който забелязах, беше колко грозно и нагласено бяха написани решенията.
Като въведение в ООП, ще поговорим по тази тема.
-&.presentation
-
-&[title
-
-# Основни идеи<br>при добро писане на код
+[$presentation-controller]
-&]
+:title_slide
+# Основни идеи\n
+ при добро писане на код
-&[slide35
+:slide35
## Какво прави програмиста с чужд код?
-&.br4
+[$br4]
+.numbered
1. Чете
2. Разучава как се ползва/какво прави
3. Използва го/Модифицира го
-Добър код прави тези задачи лесни!
-
-&]
-
+.p Добър код прави тези задачи лесни!
-&[slide35
+:slide35
## Подобряване на четене
-&.br4
+[$br4]
+.unordered
- Лично вярвам, че четимост е по-важна от конвенции
- Човек вижда най-лесно "контрастни" шаблони
-
```
. . 0.00.0 010010 815213
000000 000000 738438
. . .0000. 100001 122481
.... 0....0 011110 511119
-```
-
-&]
-
Както виждате, в примера има усмихнато личице, "закодирано" по различни начини.
@@ -58,14 +52,11 @@
При код, ще илюстрирам идеята си с един пример, но няма да задълбавам, следващата секция е много по-важна.
Пък и тази тема е малко религиозна и ще чувате различни мнения според човека който питате.
+:middle_slide
+Труден за четене код *[(забелязвате ли грешките?)]*:
-&[middle
-
-Труден за четене код *(забелязвате ли грешките?)*:
-
-&(font22
-
+.font22
```
int a, b;
std::cout << "Enter coordinates" << std::endl;
@@ -84,10 +75,6 @@ if (board[a][b][i] == ' ') {
return false;
}
}
-```
-
-&) &]
-
Нарочно съм премахнал оцветяването, то драстично помага, но тук повече се интересуваме от "формата" на код.
@@ -95,15 +82,12 @@ if (board[a][b][i] == ' ') {
Вмъкнал съм три грешки: едно нещо липсва, има една печатна и една логическа грешка.
Разбира се, ако се зачетете дума по дума сигурно ще ги откриете, но сега да сравним.
+:middle_slide
+По-лесен за четене код *[(а сега виждат ли се по-лесно?)]*:
-&[middle
-
-По-лесен за четене код *(а сега виждат ли се по-лесно?)*:
-
-&(font18
-
-```
+:font18
+:code
std::cout << "Enter coordinates" << std::endl;
int a, b;
@@ -132,48 +116,43 @@ for (int i = 0; i < layers; i++)
return false;
}
}
-```
-&) &]
-Би трябвало да е малко по-лесно, в последния `if` имаме "e**n**ptyRow", което е печатната грешка, `!=` което трябва да бъде `==` и липсва въвеждането на `b` след първия `if`.
+Би трябвало да е малко по-лесно, в последния `[if]` имаме "e=[n]=ptyRow", което е печатната грешка, `[!=]` което трябва да бъде `[==]` и липсва въвеждането на `[b]` след първия `[if]`.
Примерът не е перфектен, но илюстрира какво се опитвам да кажа: формата на код е от огромно значение, обръщайте ѝ внимание.
-&[slide
+:slide
## Абстракцията - улеснява изучаване И употреба/модификация
-&.br1
+[$br1]
+.bulleted
- Разделяме обработване на стойностите от директната имплементацията
- Създаваме нови "машинни инструкции"
-&.br1
-
-- `doX()` е по-лошо от `do(X)`
- - можем да преизползваме `do()` за неща, различни от `X`
- - един път разбрано, всяка употреба на `do()` също е разбрана; този стил кара `do()` да бъде по-обща функция, което я прави по-лесна за разбиране
- - модификация на `do(X)` се свежда до заменяне на `do()` с `doOther()` или до заменяне на `X` с `Y`; променяме "инструкцията" или променяме данната
-
-&]
+[$br1]
+.bulleted
+- `[doX()]` е по-лошо от `[do(X)]`
+ .unordered
+ - можем да преизползваме `[do()]` за неща, различни от `[X]`
+ - един път разбрано, всяка употреба на `[do()]` също е разбрана; този стил кара `[do()]` да бъде по-обща функция, което я прави по-лесна за разбиране
+ - модификация на `[do(X)]` се свежда до заменяне на `[do()]` с `[doOther()]` или до заменяне на `[X]` с `[Y]`; променяме "инструкцията" или променяме данната
Нека сега разгледаме няколко примера, първият е много груб и елементарен, но служи за добро начало:
-
-
-&[middle
-
+:middle_slide
```cpp
Лошо - doX() │ Добро - do(X)
- │
+ │
int fib5() │ int fib(int n)
{ │ {
int prev = 0, curr = 1; │ int prev = 0, curr = 1;
@@ -185,24 +164,18 @@ int fib5() │ int fib(int n)
} │ }
return curr; │ return curr;
} │ }
-```
-
-&]
-
Би трябвало да е супер очевидно, никой няма да пише отделна функция на Фибоначи за всяко число.
-Нека сега да разгледаме няколко "реални" примера, свързани с домашното (за припомняне, условието се намира [тук](https://learn.fmi.uni-sofia.bg/mod/assign/view.php?id=296069)).
+Нека сега да разгледаме няколко "реални" примера, свързани с домашното (за припомняне, условието се намира [url https://learn.fmi.uni-sofia.bg/mod/assign/view.php?id=296069 тук]).
Самите решения няма винаги да са добре форматирани, това е направено с цел да се поберат добре в слайда.
Първия е върху функция, която приема координатите на плочка, премахва я от дъската (ако съществува) и я слага в края на празния ред.
+:slide
-
-&[slide
-
-Лошо - `doX()` в тялото на функцията
+Лошо - `[doX()]` в тялото на функцията
```cpp
void tryTakeTile(char** board, int rows, int cols,
@@ -224,27 +197,22 @@ void tryTakeTile(char** board, int rows, int cols,
board[x][y] = ' ';
}
}
-```
-
-&]
-
Повечето предадени работи са имплементирали функционалността по точно този начин.
Замислете се обаче, какво става ако сменим типа данна, тоест ако дъската е триизмерна?
-Тогава трябва да добавим още една `int` променлива, още едно условие в `if`, трябва да я добавим при трите индексирания на `board`.
+Тогава трябва да добавим още една `[int]` променлива, още едно условие в `[if]`, трябва да я добавим при трите индексирания на `[board]`.
-Какво става ако променим самата структура от данни за `emptyRow` (за сега сте учили само масиви, но скоро ще видите, че има и други начини да съхраняваш редица информация), тогава ще трябва да пренапишем целия цикъл.
+Какво става ако променим самата структура от данни за `[emptyRow]` (за сега сте учили само масиви, но скоро ще видите, че има и други начини да съхраняваш редица информация), тогава ще трябва да пренапишем целия цикъл.
Тоест, ако променим нещо, трябва да пренапишем значителни части от самия код, и като разширим това върху 10-20 функции, изведнъж малка промяна става голяма.
Нека сега да пренапишем функцията, използвайки колкото се може повече абстракция.
+:middle_slide
-&[middle
+Добро - `[do(X)]`
-Добро - `do(X)`
-
-```cpp
+:code_cpp
bool tryReadCoordinates(int& x, int& y) {
std::cin >> x >> y;
if (!availablePosition(board, rows, cols, x, y)) {
@@ -262,26 +230,21 @@ void tryTakeTile(char** board, int rows, int cols,
board[x][y] = ' ';
}
}
-```
-
-&]
-Искаме трето измерение на `board`?
-Няма проблем, написали сме нова `tryReadCoordinates`, която приема три променливи, и в `tryTakeTile` добавяме една декларация и обновяваме двете индексирания на `board`.
-Ако `emptyRow` стане друг тип данна, просто променяме функцията да бъде `appendToOtherDataType` и сме готови.
+Искаме трето измерение на `[board]`?
+Няма проблем, написали сме нова `[tryReadCoordinates]`, която приема три променливи, и в `[tryTakeTile]` добавяме една декларация и обновяваме двете индексирания на `[board]`.
+Ако `[emptyRow]` стане друг тип данна, просто променяме функцията да бъде `[appendToOtherDataType]` и сме готови.
И ако тази промяна трябва да се направи в много функции, даже бихме могли да употребяваме функционалност на самия текстов редактор да търси и заменя срещания на един низ с друг.
Нека сега да увеличим сложността още малко, да разгледаме функция за генерирането на дъската.
Отново, повечето предадени решения изглеждаха подобни на примера.
+:slide
-
-&[slide
-
-Лошо - всички цикли са `doX()`
+Лошо - всички цикли са `[doX()]`
```cpp
void generateLayer(char** layer, int rows, int cols,
@@ -302,10 +265,6 @@ void generateLayer(char** layer, int rows, int cols,
}
}
}
-```
-
-&]
-
Стария проблем, някакви цикли, ако искаме да променям някоя данна или как нещо работи, трябва да пренапишем половината функция.
@@ -313,17 +272,15 @@ void generateLayer(char** layer, int rows, int cols,
Този сегмент е по-интересен за променяне от преди, понеже за да го направим хубаво трябва да променим самата ни логика.
Запълването със шпации е ясно, обаче случайното поставяне на плочки не е.
-Ако имаме функция `placeRandomЕлемент` която само поставя една плочка в слоя, пак ще имаме вложени цикли, трябва да има начин да останем с един цикъл.
-Ако направим `placeRandomElementNTimes`, тогава пък абстрахираната функция става твърде специфична и вече имаме `doX()` при самата нея.
+Ако имаме функция `[placeRandomЕлемент]` която само поставя една плочка в слоя, пак ще имаме вложени цикли, трябва да има начин да останем с един цикъл.
+Ако направим `[placeRandomElementNTimes]`, тогава пък абстрахираната функция става твърде специфична и вече имаме `[doX()]` при самата нея.
Чрез функционално програмиране този проблем може да се разреши лесно, обаче вие ще го учите следващия семестър.
С достатъчно размишления, може да стигнем до следния вариант: вместо всяка плочка да я поставяме на случайна позиция, защо не поставим всички плочки една след друга и не разбъркаме слоя?
+:middle_slide
-
-&[middle
-
-Добро - `do(X)`
+Добро - `[do(X)]`
```cpp
void generateLayer(char** layer, int rows, int cols,
@@ -338,12 +295,8 @@ void generateLayer(char** layer, int rows, int cols,
}
shuffleMatrix(layer, rows, cols);
}
-```
-
-**Бонус:** работи по-коректно от преди
-
-&]
+=[Бонус:]= работи по-коректно от преди
В предходния вариант, ако примерно цялата е пълна освен една клетка, и трябва да поставим една финална плочка, тогава трябва да чакаме докато случайните стойности се напаснат точно с координатите на тази една клетка.
@@ -351,16 +304,14 @@ void generateLayer(char** layer, int rows, int cols,
Даже, този проблем става все по-тегав с времето: с всяка запълнена клетка, шанса случайните стойности да ударят на заети координати се увеличава.
Докато тук, нямаме този проблем, отнема някакво консистентно предопределено време да разбъркаме матрицата.
-Как имплементираме `shuffleMatrix` си има и своите тънкости, но най-елементарния начин е просто да направим сортираш алгоритъм, при който вместо да сравним две стойности, използваме случайна стойност, която определя дали ще разменим плочките.
+Как имплементираме `[shuffleMatrix]` си има и своите тънкости, но най-елементарния начин е просто да направим сортираш алгоритъм, при който вместо да сравним две стойности, използваме случайна стойност, която определя дали ще разменим плочките.
Друго хубаво нещо на решения с абстракция, е един лек лавинен ефект, където веднъж като почнем да мислим за абстракции, намираме къде да ги ползваме навсякъде.
Да разгледаме същата функция, обаче при D подточка.
+:middle_slide
-
-&[middle
-
-Решения със слоеве правят същото. Лошо - `doX()` при циклите:
+Решения със слоеве правят същото. Лошо - `[doX()]` при циклите:
```cpp
void generate(char*** board, int rows, int cols, int layers,
@@ -372,21 +323,15 @@ void generate(char*** board, int rows, int cols, int layers,
} while(layer[x][y][layer] != ' ');
...
}
-```
-
-&]
+Без абстракция отново ще пренапишем голяма част от `[generate]` функцията, за да се побере на слайда съм оставил само "най-сложната" промяна - случайните стойности.
+Пак, имаше решения на подточката, без преизползване на `[generate]` за един слой.
+Айде да разгледаме решението, заедно с абстрахираната `[generate]`.
-Без абстракция отново ще пренапишем голяма част от `generate` функцията, за да се побере на слайда съм оставил само "най-сложната" промяна - случайните стойности.
-Пак, имаше решения на подточката, без преизползване на `generate` за един слой.
-Айде да разгледаме решението, заедно с абстрахираната `generate`.
+:slide
-
-
-&[slide
-
-Добро - `do(X)`
+Добро - `[do(X)]`
```cpp
void generateLayer(char** layer, int rows, int cols,
@@ -407,42 +352,32 @@ void generate(char*** board, int rows, int cols, int layers,
tiles, tileCounts, tilesSize);
}
}
-```
-
-&]
-
Супер елементарно, има-няма 5-6 реда код промяна, при генериране за всеки слой, просто извикваме функцията за генериране върху един слой, за всеки слой.
А в самата функция само премахваме броя вмъкнати плочки от сумата на даден тип.
-Наблюдателните са забелязали, че в "ръчното" решение слоевете са третия индекс, тоест имаме `board[x][y][layer]`, докато в това решение е първия, тоест `board[layer][x][y]`.
+Наблюдателните са забелязали, че в "ръчното" решение слоевете са третия индекс, тоест имаме `[board[x][y][layer]]`, докато в това решение е първия, тоест `[board[layer][x][y]]`.
Разликата е значителна, но от гледна точка на код, особено когато използваме абстракция, промяната е лесна.
Иначе, в момента се намираме в много добра позиция, без абстракция как правим рестартирането на играта?
По условие броя и типовете плочки трябва да се запазят, но позиции не.
Истината е, че става малко тромаво: цикълът за намираме на позиции се преизползва, и броя плочки трябва да се запази.
-Обаче, сега това става с едно `shuffleMatrix`, не е нужно нищо специално да правим!
-
+Обаче, сега това става с едно `[shuffleMatrix]`, не е нужно нищо специално да правим!
-
-&[middle35
+:middle_slide35
### Абстракцията - подобрява и коментари
+.unordered
- Целта на коментарите е да направи разбиране и модификация на код по-лесни.
-- В повечето случаи, коментарът трябва да ни дава *нова* информация или да *свърже* парчета информация
-
-&]
-
+- В повечето случаи, коментарът трябва да ни дава *[нова]* информация или да *[свърже]* парчета информация
Да разгледаме следния пример.
-
-
-&[middle
+:middle_slide
Лошо:
@@ -453,7 +388,6 @@ for (int i = 0; i < rows; i++) {
matrix[i][j] = '\0';
}
}
-```
Добро:
@@ -465,55 +399,43 @@ for (int i = 0; i < rows; i++) {
matrix[i][j] = '\0';
}
}
-```
-
-
-&]
-
-При добрия вариант, получаваме нова информация, че това запълване се случва понеже ще подаваме към някаква си `functionX`, и че евентуално може да има други функции, при които празни клетки може да не се обозначават с `'\0'`.
+При добрия вариант, получаваме нова информация, че това запълване се случва понеже ще подаваме към някаква си `[functionX]`, и че евентуално може да има други функции, при които празни клетки може да не се обозначават с `['\0']`.
В лошия можем да стигнем до същото заключение като погледнем самия код.
-<!--
-<br>
+:comment
Всичко това е много хубаво, обаче цитирайки Дийкстра, малки изолирани примери не са достатъчни:
+:middle_slide
+.quote For practical reasons, the demonstration programs must be small, many times smaller than the "life-size programs" I have in mind. My basic problem is that precisely this difference in scale is one of the major sources of our difficulties in programming!
-&[middle
-
-> For practical reasons, the demonstration programs must be small, many times smaller than the "life-size programs" I have in mind. My basic problem is that precisely this difference in scale is one of the major sources of our difficulties in programming!
+&mdash; Edsger W. Dijkstra, [url https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF Notes on Structured Programming, On our inability to do much]
-&mdash; Edsger W. Dijkstra, [Notes on Structured Programming, On our inability to do much](https://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF)
-
-&.br1
+[$br1]
Решение на цялото домашно, с описаните методи TODO
-&]
-
-
Окуражавам ви да разгледате решенията, да ги сравните с вашите и поне да придобиете някаква интуиция за нещата.
Така да мислиш не е лесно, отнема време и усилия.
--->
-Умението да разрешиш един проблем *не те* прави добър програмист, да го разрешиш по четим, разширяем, лесен, ефикасен, ... начин *те* прави добър програмист.
+Умението да разрешиш един проблем *[не те]* прави добър програмист, да го разрешиш по четим, разширяем, лесен, ефикасен, ... начин *[те]* прави добър програмист.
-&[slide35
+:slide35
## Изводи
-&.br4
+[$br4]
+.unordered
- Форматирайте/подравнявайте си кода, искате лесно четене
- Вдигайте абстракция
+ .unordered
- Обширни функции > код за конкретни стойности
- Преизползване на възможно най-много код
- Коментари които дават или разширяват знание
-
-&]
diff --git a/src/teaching/oop-2023/week1/index.md b/src/teaching/oop-2023/week1/index.du
index df05b2e..dc3346b 100644
--- a/src/teaching/oop-2023/week1/index.md
+++ b/src/teaching/oop-2023/week1/index.du
@@ -1,81 +1,103 @@
# Задачи - ООП, Седмица 1, 22.02.2024
-GitHub classroom: [classroom.github.com/a/UPJOzHty](https://classroom.github.com/a/UPJOzHty)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/UPJOzHty classroom.github.com/a/UPJOzHty]
## Задача 1
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise1.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise1.cpp Решение]
Имплементирайте низ чрез структура.
В структурата трябва да запазвате указател към низа и неговата дължина.
-Имплементирайте функция `concatString`, която приема две структури от този тип и връща низ, пак в същата структура, който е конкатенация (слепване) на първите два низа.
+Имплементирайте функция `[concatString]`, която приема две структури от този тип и връща низ, пак в същата структура, който е конкатенация (слепване) на първите два низа.
-&:question Има ли значение дали типовете на аргументите, или на върнатата стойност, са референции или указатели (или нито едното)?
+.question Има ли значение дали типовете на аргументите, или на върнатата стойност, са референции или указатели (или нито едното)?
В самия код тествайте функциите (не е нужен потребителски вход).
## Задача 2
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise2.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise2.cpp Решение]
Имплементирайте структура за динамично-заделен масив от целочислени числа.
Тя трябва да запазва указател към масива, размера на масива и бройката на елементи в масива.
Заделянето на динамична памет е бавна операция, затова винаги ще заделяме повече клетки, отколкото са ни нужни.
-Имплементирайте функция `resize`, която удвоява размера на масива (нека първоначалния размер на масива е 2), на подадена стойност от тип вашата структура.
+Имплементирайте функция `[resize]`, която удвоява размера на масива (нека първоначалния размер на масива е 2), на подадена стойност от тип вашата структура.
-Имплементирайте функция `addToEnd`, която приема (инстанция на) структурата ви и вмъква елемент в първата незаета позиция.
+Имплементирайте функция `[addToEnd]`, която приема (инстанция на) структурата ви и вмъква елемент в първата незаета позиция.
В самия код тествайте функциите (не е нужен потребителски вход).
## Задача 3
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise3.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise3.cpp Решение]
Разглеждате "пакети" (логове) информация от редица датчици.
Един пакет запазва времето, когато информацията е била отчетена от датчиците, и стойностите на всички датчици: температура, атмосферно налягане, влажност и надморска височина.
Всички типове данни са целочислени.
От входа получавате N, броя пакети, които трябва да запазите, и след това 5N на брой целочислени стойности.
-Накрая получавате буква: `t`, `p`, `h`, `e`, всяка съответства на някоя отделна стойност от датчиците.
+Накрая получавате буква: `[t]`, `[p]`, `[h]`, `[e]`, всяка съответства на някоя отделна стойност от датчиците.
Трябва да изкарате на екрана всичките стойности от пакетите, подредени в нарастващ ред на времето, като всички след първата са разликите им спрямо първата.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|6<br>56 45 64 -8 98<br>14 40 -15 -18 -1<br>22 89 72 62 4<br>85 44 60 17 13<br>75 18 -12 48 21<br>27 10 94 -5 16<br>p|-15 87 109 79 3 75|
+.table
+|=Вход=||=Изход=|
+|:6\n
+ 56 45 64 -8 98\n
+ 14 40 -15 -18 -1\n
+ 22 89 72 62 4\n
+ 85 44 60 17 13\n
+ 75 18 -12 48 21\n
+ 27 10 94 -5 16\n
+ p:|
+|:-15 87 109 79 3 75:|
## Задача 4
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise4.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise4.cpp Решение]
+
+'footnote sabre Защото една от първите индустрии, които са се нуждаели от компютърни системи, била [url https://en.wikipedia.org/wiki/Sabre_%28travel_reservation_system%29#History авиационната индустрия].
-Направете структура за съхранение на полети[^sabre].
+Направете структура за съхранение на полети[$sabre].
Трябва да запазите имената на началния и крайния град като низове (допускаме, че няма шпации в имената на градовете), часът на излитане и на кацане в целочислен формат (като на циферблат на дигитален часовник, без разделителното двоеточие) и цената на полета в тип с плаваща запетая (в долари).
### а) въвеждане
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise4.cpp#L15-L36)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise4.cpp#L15-L36 Решение]
От входа получавате N, това определя броя полети, които трябва да се добавят в системата.
Всеки полет е редица от 5 стойности, в реда в който са дефинирани.
-*Напомням, че това е нагласено да ползвате `std::cin` вместо ръчно да обработвате целия ред.*
+*[Напомням, че това е нагласено да ползвате `[std::cin]` вместо ръчно да обработвате целия ред.]*
Изкарайте началните и крайните градове, както и цената на полетите, подредени в нарастващ ред на час на излитане.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|5<br>Berlin Paris 1105 1255 140<br>Sofia Paris 0915 1115 140<br>Paris NewYork 1225 1610 500<br>Sofia NewYork 0610 1345 800<br>Sofia Berlin 1020 1130 200|Sofia NewYork 800<br>Sofia Paris 140<br>Sofia Berlin 200<br>Berlin Paris 140<br>Paris NewYork 500|
+.table
+|=Вход=||=Изход=|
+|:5\n
+ Berlin Paris 1105 1255 140\n
+ Sofia Paris 0915 1115 140\n
+ Paris NewYork 1225 1610 500\n
+ Sofia NewYork 0610 1345 800\n
+ Sofia Berlin 1020 1130 200:|
+|:Sofia NewYork 800\n
+ Sofia Paris 140\n
+ Sofia Berlin 200\n
+ Berlin Paris 140\n
+ Paris NewYork 500:|
### б) търсене
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise4.cpp#L38-L247)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise4.cpp#L38-L247 Решение]
След като се въведат всички полети, получавате от входа два низа - имена на градове.
Трябва да изкарате най-евтиния, и след него най-бързия, вариант за пътуване от първия град към втория.
@@ -83,18 +105,29 @@ GitHub classroom: [classroom.github.com/a/UPJOzHty](https://classroom.github.com
Прикачване между полети е позволено, така че под "вариант" трябва да изкарате всичките полети, които са решение.
За един полет е нужно да изкарате само началния град, крайния град, час на излитане и цена, като градовете трябва да са подредени в нарастващ ред на часа на излитане.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|5<br>Berlin Paris 1105 1255 140<br>Sofia Paris 0915 1115 140<br>Paris NewYork 1225 1610 500<br>Sofia NewYork 0610 1245 800<br>Sofia Berlin 1020 1130 200<br>Sofia NewYork|Cheapest:<br>Sofia Paris 0915 140<br>Paris NewYork 1225 500<br>Quickest:<br>Sofia NewYork 0610 800|
+.table
+|=Вход=||=Изход=|
+|:5\n
+ Berlin Paris 1105 1255 140\n
+ Sofia Paris 0915 1115 140\n
+ Paris NewYork 1225 1610 500\n
+ Sofia NewYork 0610 1245 800\n
+ Sofia Berlin 1020 1130 200\n
+ Sofia NewYork:|
+|:Cheapest:\n
+ Sofia Paris 0915 140\n
+ Paris NewYork 1225 500\n
+ Quickest:\n
+ Sofia NewYork 0610 800:|
## Задача 5
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise5.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week01/Exercise5.cpp Решение]
-Имате система за потребители, всеки потребител си има име и приятели (един приятел е **указател към потребител**).
+Имате система за потребители, всеки потребител си има име и приятели (един приятел е =[указател към потребител]=).
В началото се въвежда N, това е броят потребители в системата.
За един потребител, първо се въвежда на нов ред името му, след това броя на неговите приятели и накрая, на отделни редове, имената на всички тези приятели.
@@ -102,10 +135,26 @@ GitHub classroom: [classroom.github.com/a/UPJOzHty](https://classroom.github.com
Накрая получавате едно име, това е началния потребител.
Трябва да намерите, започвайки от него, с колко други потребителя има някаква приятелска връзка (директна, приятел на приятел, приятел на приятел на приятел, ...).
-**Пример:**
-
-|Вход|Изход|
-|----|-----|
-|5<br>Георги<br>2<br>Асен Гьонов<br>Майстора<br>Асен Гьонов<br>2<br>Георги<br>др. Божидаров<br>Майстора<br>1<br>Георги<br>др. Божидаров<br>1<br>Асен Гьонов<br>Павел<br>0<br>Майстора|3|
+=[Пример:]=
-[^sabre]: Защото една от първите индустрии, които са се нуждаели от компютърни системи, била [авиационната индустрия](https://en.wikipedia.org/wiki/Sabre_%28travel_reservation_system%29#History).
+.table
+|=Вход=||=Изход=|
+|:5\n
+ Георги\n
+ 2\n
+ Асен Гьонов\n
+ Майстора\n
+ Асен Гьонов\n
+ 2\n
+ Георги\n
+ др. Божидаров\n
+ Майстора\n
+ 1\n
+ Георги\n
+ др. Божидаров\n
+ 1\n
+ Асен Гьонов\n
+ Павел\n
+ 0\n
+ Майстора:|
+|:3:|
diff --git a/src/teaching/oop-2023/week1/organization.md b/src/teaching/oop-2023/week1/organization.du
index 92fdcc8..40abea9 100644
--- a/src/teaching/oop-2023/week1/organization.md
+++ b/src/teaching/oop-2023/week1/organization.du
@@ -1,61 +1,54 @@
# Организация - ООП, Седмица 1, 22.02.2024
-&.presentation
+\n
-&[title35
+[$presentation-controller]
-# Добре дошли в ООП
-
-&]
+:title_slide35
+# Добре дошли в ООП
За разлика от Увод в програмиране, по ООП практикума е малко по-специален.
+:middle_slide35
-
-&[middle35
-
+:unordered
- ООП практикум е избираема, която няма смисъл да не запишете
+ .unordered
- Само плюсове за вас
-- Оценката е според контролни/изпити по ООП
-&]
+- Оценката е според контролни/изпити по ООП
Така ви помагаме с избираемите: по учебен план трябва да имате поне 2 практикума, сравнително безплатно получавате единия.
Относно оценяване:
+:middle_slide35
-
-&[middle35
-
+.unordered
- Освобождаване от изпит според работата ви по време на практикум
- Няма намаляване на оценка
-- Оценявам общите ви умения<br>
- Важното е да умеете да сте програмисти: коректност, брой и трудност на решени задачи се зачитат по-малко отколкото успех да напишете прилично-изглеждаща програма (дори с малко мой тласък)
-
-&]
-
+- Оценявам общите ви умения
+ .p Важното е да умеете да сте програмисти: коректност, брой и трудност на решени задачи се зачитат по-малко отколкото успех да напишете прилично-изглеждаща програма (дори с малко мой тласък)
Все пак не може да ви даваме безплатни оценки, затова:
+:middle_slide35
+:unordered
+- Зачитат се =[единствено нещата, качени в GitHub classroom, качени в срок]=
+ .unordered
+ - До =[15]= минути след края на часа
-&[middle35
-
-- Зачитат се **единствено нещата, качени в GitHub classroom, качени в срок**
- - До **15** минути след края на часа
- Както преди, не е нужно да присъствате, за да качвате решения
- Ако случайно някой не знае как се ползва:
-&(centered [syndamia.com/upp-2023/week1/setup.html?a](../upp-2023/week1/setup.html?a) &)
-
-&]
+.centered [url ../upp-2023/week1/setup.html?a syndamia.com/upp-2023/week1/setup.html?a]
Който по време на УП е използвал GitHub classroom не би трябвало да прави нещо, продължавате си по старо му, със същите акаунти.
-Разбира се, за всякакви проблеми се [свържете с мен](../upp-2023/week1/welcome.html?a#section-4).
+Разбира се, за всякакви проблеми се [url ../upp-2023/week1/welcome.html?a#section-4 свържете с мен].
diff --git a/src/teaching/oop-2023/week10/index.du b/src/teaching/oop-2023/week10/index.du
new file mode 100644
index 0000000..dfff7fc
--- /dev/null
+++ b/src/teaching/oop-2023/week10/index.du
@@ -0,0 +1,150 @@
+# Задачи - ООП, Седмица 10, 25.04.2024
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/PbkITWhF classroom.github.com/a/PbkITWhF]
+
+## Преговорни
+
+.warn Моля, не отделяйте на преговорните задачи повече от 30мин
+
+### Задача 1 - Шаблони
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise01 Решение]
+
+Реализирайте шаблонен клас `[Array]`, който запазва динамично-заделен и оразмеряем масив от елементи с подаден тип.
+Имплементирайте голяма четворка.
+
+### Задача 2 - Оператори
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise02 Решение]
+
+За предходния шаблонен клас имплементирайте оператори:
+
+.unordered
+- [], който връща референция към елемента на подадения индекс
+- == и !=, които сравняват поелементно
+- +, += които конкатенират (слепват) два масива
+
+### Задача 3 - Грешки
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise03 Решение]
+
+Имплементирайте функция, която приема име на текстов файл и изкарва на екрана първия ред от него.
+Ако файлът не може да бъде отворен, хвърлете грешка - низ.
+Ако във файлът няма други редове (няма знакът `['\\n']`), тогава хвърлете грешка число - размерът на файла.
+
+В главната функция, приемете името на файла от потребителския вход и извикайте функцията.
+Ако файлът не може да бъде отворен, тогава изкарайте хвърлената грешка на терминала и приключете програмата (успешно).
+Ако няма други редове в него, тогава изкарайте съобщението "In X characters, there is no newline!", където X е хвърленото число, и пробвайте да приемете пак име на файла от потребителския вход.
+
+## Лесни
+
+### Задача 4
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise04 Решение]
+
+Реализирайте клас `[Time24]`, който запазва час и минути (в 24-часов формат) в две отделни целичислени член-данни.
+Имплементирайте член-функция `[Print24]`, която изкарва часа на екрана в 24-часов формат.
+Нека конструкторът му приема две целочислени променливи, една за часа и втора за минутите.
+
+Реализирайте негов наследник `[Time12]`, който имплементира метод `[Print12]`, принтиращ часа в 12-часов формат.
+Имплементирайте и негов конструктор, който приема две целочислени променливи (една за часа и една за минутите), заедно с булева променлива описваща дали часа е следобеден или не.
+
+### Задача 5
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise05 Решение]
+
+Реализирайте клас `[FN]`, който запазва факултетен номер като неотрицателно цяло число от 5 цифри.
+Реализирайте негов наследник `[ModernFN]`, който запазва и начален (префиксен) низ, състоящ се от цифра, две букви и още две цифри.
+
+Имплементирайте конструктори, като този на `[FN]` приема число, докато този на `[ModernFN]` приема низ, състоящ се от целия факултетен номер (и трябва да конвертирате последните 5 цифри към число).
+Имплементирайте метод `[PrintOldFN]` на класа `[FN]` и метод `[PrintNewFN]` на класа `[ModernFN]`, които изкарват целия факултетен номер на съответния клас.
+
+### Задача 6
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise06 Решение]
+
+Реализирайте клас `[Grade]`, който запазва оценка (от 2 до 6) като неотрицателна целочислена член-данна.
+Реализирайте и негов наследник `[GradeWithName]`, който запазва и името на оценката като низ с произволна дължина.
+
+Конструктора на `[Grade]` приема само числовата стойност, докато този на наследника приема и името на оценката.
+Имплементирайте голяма петица на `[GradeWithName]`.
+
+### Задача 7
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise07 Решение]
+
+Реализирайте клас `[String]`, който запазва низ с произволна дължина.
+Имплементирайте голяма петица и член-функция `[At]`, която приема индекс и връща референция към буквата на този индекс (при невалиден индекс хвърляте грешка).
+
+Реализирайте негов наследник `[FileString]`, който запазва и името на текстов файл като низ с произволна дължина.
+Ако е нужно, имплементирайте голяма петица.
+
+Самия низ в `[FileString]` е първия низ (начало първата буква и край `['\\n']`) от файла с подадено име.
+
+Имплементирайте метод `[ChangeAt]`, който приема индекс и нова буква, променя буквата на дадения индекс с подадената и обновява файла със запазеното име.
+
+### Задача 8
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise08 Решение]
+
+Реализирайте клас `[User]`, който запава име и парола като два низа с произволна дължина.
+Реализирайте негов наследник `[Moderator]`, който запазва и подпис, който също е низ с произволна дължина.
+Реализирайте наследник `[Administrator]` на `[Moderator]`, който запазва и оразмеряващ се масив от цели числа.
+
+Идеята е, че всяко действие от модератор или администратор се "подписва" публично (за да се знае, че той го е направил, дори да си смени името), а за администратор допълнително пазим масив от идентификатори на форуми, които администрира.
+
+За всеки клас имплементирайте голяма петица и гетъри и сетъри за името и паролата, когато е нужно.
+За `[Moderator]` имплементирайте гетър за подписа, но без сетър.
+За `[Administrator]` имплементирайте методи за добавяне и премахване на идентификатор на форум.
+
+### Задача 9
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise09 Решение]
+
+Реализирайте клас `[CommunicationPacket]`, който запазва начален и краен адрес като две неотрицателни цели числа, заедно с трето число за размера на данните.
+В този клас никога няма данни, затова размера винаги е нула.
+
+Реализирайте негови наследници `[StringPacket]` и `[IntPacket]`, където първия запазва и низ с произволна дължина (и дължината му е размера на данните) докато втория запазва и едно цяло число (и размера на `[int]` е размера на данните).
+
+Размерът не се подава на конструктори, а се изчислява в конструктори.
+Имплементирайте голяма петица и конструктори с нужните параметри.
+
+### Задача 10
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise10 Решение]
+
+Реализирайте клас `[String]`, който запазва низ с произволна дължина, и имплементира оператори ==, !=, + (който връща нов низ с конкатенацията на двата низа).
+
+Реализирайте негов наследник `[ModifiableString]`, който имплементира оператор[] &#20;(връщащ референция към буквата на дадения индекс) и оператор+=.
+
+Реализирайте наследник на `[ModifiableString]`, `[ShowableString]`, който имплементира оператори << и >>.
+Реализирайте наследник на `[ModifiableString]`, `[SaveableString]`, който имплементира методи write и read, приемащи име на двоичен файл и записващи или четещи низа от този файл.
+
+За всички класове имплементирайте голяма петица, когато е нужно.
+
+## Трудни
+
+### Задача 11
+
+Реализирайте шаблонен клас `[Array]`, който запазва оразмеряем масив с елементи от подаден тип.
+Имплементирайте оператор== и оператор!=, заедно с метод `[isEmpty]`.
+Концептуално идеята е, че този масив не може да се променя след като му се въведат стойностите от конструктора.
+
+Реализирайте негов наследник `[PrintableArray]`, който имплементира оператори << и >>.
+Реализирайте наследник `[SaveableArray]` на `[Array]`, който имплементира методи write и read, приемащи име на файл и булева стойност дали е двоичен или не, и съответно прочитат или запазват елементите от този масив във файла.
+
+Реализирайте трети наследник, `[ModifiableArray]`, на `[Array]`, в който са имплементирани член-функции:
+
+.unordered
+- `[push]`, която приема елемент и го вмъква в (десния) края на масива
+- `[pop]`, който премахва елемент от (десния) края на масива
+- `[last]`, който връща последния елемент от масива
+
+Може да се налага масива да се оразмерява.
+Като подсказка, имплементирайте си метод, наличен за класа и наследници, който вмъква елемент на произволен индекс.
+
+Реализирайте наследник `[IndexableArray]` на `[ModifiableArray]`, който имплементира оператор[].
+Ако индекса е след края, тогава "вмъквате" елементи по подразбиране между края и подадения индекс, и връщате елемента от сега новия край.
+Реализирайте наследник `[FrontableArray]` на `[ModifiableArray]`, който имплементира методи `[pushf]` и `[popf]`, които работят като `[push]` и `[pop]`, но с елемента в началото на масива (първия елемент).
diff --git a/src/teaching/oop-2023/week10/index.md b/src/teaching/oop-2023/week10/index.md
deleted file mode 100644
index 06d9a7b..0000000
--- a/src/teaching/oop-2023/week10/index.md
+++ /dev/null
@@ -1,146 +0,0 @@
-# Задачи - ООП, Седмица 10, 25.04.2024
-
-GitHub classroom: [classroom.github.com/a/PbkITWhF](https://classroom.github.com/a/PbkITWhF)
-
-## Преговорни
-
-&:warn Моля, не отделяйте на преговорните задачи повече от 30мин
-
-### Задача 1 - Шаблони
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise01)
-
-Реализирайте шаблонен клас `Array`, който запазва динамично-заделен и оразмеряем масив от елементи с подаден тип.
-Имплементирайте голяма четворка.
-
-### Задача 2 - Оператори
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise02)
-
-За предходния шаблонен клас имплементирайте оператори:
-
-- [], който връща референция към елемента на подадения индекс
-- == и !=, които сравняват поелементно
-- +, += които конкатенират (слепват) два масива
-
-### Задача 3 - Грешки
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise03)
-
-Имплементирайте функция, която приема име на текстов файл и изкарва на екрана първия ред от него.
-Ако файлът не може да бъде отворен, хвърлете грешка - низ.
-Ако във файлът няма други редове (няма знакът `'\n'`), тогава хвърлете грешка число - размерът на файла.
-
-В главната функция, приемете името на файла от потребителския вход и извикайте функцията.
-Ако файлът не може да бъде отворен, тогава изкарайте хвърлената грешка на терминала и приключете програмата (успешно).
-Ако няма други редове в него, тогава изкарайте съобщението "In X characters, there is no newline!", където X е хвърленото число, и пробвайте да приемете пак име на файла от потребителския вход.
-
-## Лесни
-
-### Задача 4
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise04)
-
-Реализирайте клас `Time24`, който запазва час и минути (в 24-часов формат) в две отделни целичислени член-данни.
-Имплементирайте член-функция `Print24`, която изкарва часа на екрана в 24-часов формат.
-Нека конструкторът му приема две целочислени променливи, една за часа и втора за минутите.
-
-Реализирайте негов наследник `Time12`, който имплементира метод `Print12`, принтиращ часа в 12-часов формат.
-Имплементирайте и негов конструктор, който приема две целочислени променливи (една за часа и една за минутите), заедно с булева променлива описваща дали часа е следобеден или не.
-
-### Задача 5
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise05)
-
-Реализирайте клас `FN`, който запазва факултетен номер като неотрицателно цяло число от 5 цифри.
-Реализирайте негов наследник `ModernFN`, който запазва и начален (префиксен) низ, състоящ се от цифра, две букви и още две цифри.
-
-Имплементирайте конструктори, като този на `FN` приема число, докато този на `ModernFN` приема низ, състоящ се от целия факултетен номер (и трябва да конвертирате последните 5 цифри към число).
-Имплементирайте метод `PrintOldFN` на класа `FN` и метод `PrintNewFN` на класа `ModernFN`, които изкарват целия факултетен номер на съответния клас.
-
-### Задача 6
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise06)
-
-Реализирайте клас `Grade`, който запазва оценка (от 2 до 6) като неотрицателна целочислена член-данна.
-Реализирайте и негов наследник `GradeWithName`, който запазва и името на оценката като низ с произволна дължина.
-
-Конструктора на `Grade` приема само числовата стойност, докато този на наследника приема и името на оценката.
-Имплементирайте голяма петица на `GradeWithName`.
-
-### Задача 7
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise07)
-
-Реализирайте клас `String`, който запазва низ с произволна дължина.
-Имплементирайте голяма петица и член-функция `At`, която приема индекс и връща референция към буквата на този индекс (при невалиден индекс хвърляте грешка).
-
-Реализирайте негов наследник `FileString`, който запазва и името на текстов файл като низ с произволна дължина.
-Ако е нужно, имплементирайте голяма петица.
-
-Самия низ в `FileString` е първия низ (начало първата буква и край `'\n'`) от файла с подадено име.
-
-Имплементирайте метод `ChangeAt`, който приема индекс и нова буква, променя буквата на дадения индекс с подадената и обновява файла със запазеното име.
-
-### Задача 8
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise08)
-
-Реализирайте клас `User`, който запава име и парола като два низа с произволна дължина.
-Реализирайте негов наследник `Moderator`, който запазва и подпис, който също е низ с произволна дължина.
-Реализирайте наследник `Administrator` на `Moderator`, който запазва и оразмеряващ се масив от цели числа.
-
-Идеята е, че всяко действие от модератор или администратор се "подписва" публично (за да се знае, че той го е направил, дори да си смени името), а за администратор допълнително пазим масив от идентификатори на форуми, които администрира.
-
-За всеки клас имплементирайте голяма петица и гетъри и сетъри за името и паролата, когато е нужно.
-За `Moderator` имплементирайте гетър за подписа, но без сетър.
-За `Administrator` имплементирайте методи за добавяне и премахване на идентификатор на форум.
-
-### Задача 9
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise09)
-
-Реализирайте клас `CommunicationPacket`, който запазва начален и краен адрес като две неотрицателни цели числа, заедно с трето число за размера на данните.
-В този клас никога няма данни, затова размера винаги е нула.
-
-Реализирайте негови наследници `StringPacket` и `IntPacket`, където първия запазва и низ с произволна дължина (и дължината му е размера на данните) докато втория запазва и едно цяло число (и размера на `int` е размера на данните).
-
-Размерът не се подава на конструктори, а се изчислява в конструктори.
-Имплементирайте голяма петица и конструктори с нужните параметри.
-
-### Задача 10
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week10/Exercise10)
-
-Реализирайте клас `String`, който запазва низ с произволна дължина, и имплементира оператори ==, !=, + (който връща нов низ с конкатенацията на двата низа).
-
-Реализирайте негов наследник `ModifiableString`, който имплементира оператор[] &#20;(връщащ референция към буквата на дадения индекс) и оператор+=.
-
-Реализирайте наследник на `ModifiableString`, `ShowableString`, който имплементира оператори << и >>.
-Реализирайте наследник на `ModifiableString`, `SaveableString`, който имплементира методи write и read, приемащи име на двоичен файл и записващи или четещи низа от този файл.
-
-За всички класове имплементирайте голяма петица, когато е нужно.
-
-## Трудни
-
-### Задача 11
-
-Реализирайте шаблонен клас `Array`, който запазва оразмеряем масив с елементи от подаден тип.
-Имплементирайте оператор== и оператор!=, заедно с метод `isEmpty`.
-Концептуално идеята е, че този масив не може да се променя след като му се въведат стойностите от конструктора.
-
-Реализирайте негов наследник `PrintableArray`, който имплементира оператори << и >>.
-Реализирайте наследник `SaveableArray` на `Array`, който имплементира методи write и read, приемащи име на файл и булева стойност дали е двоичен или не, и съответно прочитат или запазват елементите от този масив във файла.
-
-Реализирайте трети наследник, `ModifiableArray`, на `Array`, в който са имплементирани член-функции:
-
-- `push`, която приема елемент и го вмъква в (десния) края на масива
-- `pop`, който премахва елемент от (десния) края на масива
-- `last`, който връща последния елемент от масива
-
-Може да се налага масива да се оразмерява.
-Като подсказка, имплементирайте си метод, наличен за класа и наследници, който вмъква елемент на произволен индекс.
-
-Реализирайте наследник `IndexableArray` на `ModifiableArray`, който имплементира оператор[].
-Ако индекса е след края, тогава "вмъквате" елементи по подразбиране между края и подадения индекс, и връщате елемента от сега новия край.
-Реализирайте наследник `FrontableArray` на `ModifiableArray`, който имплементира методи `pushf` и `popf`, които работят като `push` и `pop`, но с елемента в началото на масива (първия елемент).
diff --git a/src/teaching/oop-2023/week11/index.du b/src/teaching/oop-2023/week11/index.du
new file mode 100644
index 0000000..5fd580b
--- /dev/null
+++ b/src/teaching/oop-2023/week11/index.du
@@ -0,0 +1,210 @@
+# Задачи - ООП, Седмица 11, 09.05.2024
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/oYQehcnN classroom.github.com/a/oYQehcnN]
+
+## Преговорни
+
+.warn Моля, не отделяйте на преговорните задачи повече от 30мин
+
+.important Всеки бащин клас, във всички случаи, трябва да има виртуален деструктор (`[virtual ~ClassName();]`).
+
+### Задача 1 - Шаблони и оператори
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise01 Решение]
+
+Реализирайте шаблонен клас множество, който запазва фиксиран брой елементи от подаден тип.
+Реализирайте голяма петица и оператори:
+.bulleted
+- `[+]`, `[+=]` които действат като обединение
+- `[*]`, `[*=]` които действат като сечение
+- `[-]`, `[-=]` които действат като допълнение
+
+### Задача 2 - Наследяване
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise02 Решение]
+
+Реализирайте клас `[Employee]`, съхраняващ име на човек, позиция и департамент като низове със съответно дължина 512, 128 и 64, заедно със заплата като число с плаваща запетая.
+
+Реализирайте негов наследник `[Manager]`, който допълнително пази масив с фиксиран размер от Employee.
+
+Реализирайте наследника на `[Employee]`, `[Developer]`, който допълнително пази брой проекти върху който работи.
+
+Наследниците не могат да достъпят заплатата, но трябва да могат да достъпят другите данни на `[Employee]`.
+
+## Лесни
+
+### Задача 3
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise03 Решение]
+
+.comment Динамично свързване, Inherit 3
+
+Реализирайте клас `[Electronics]`, който съдържа модел (низ с максимална дължина от 255 знака), `[needsVolts]` и `[needsAmps]` (стойности с плаваща запетая).
+
+Имплементирайте негови наследници:
+.bulleted
+- `[Laptop]`, който допълнително съхранява размер на екрана като число с плаваща запетая
+- `[WashingMachine]`, който допълнително запазва максимално тегло на прането, като цяло неотрицателно число
+- `[Camera]`, която допълнително запазва резолюция като число с плаваща запетая (в мегапиксели)
+
+За всеки клас реализирайте член-функция `[Print]`, която изкарва всички данни на екрана.
+
+&:question Чрез статично или динамично свързване сте имплементирали `[Print]`? Каква е разликата?
+
+### Задача 4
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise04 Решение]
+
+.comment Dynamic linking, Inherit 2
+
+Реализирайте клас `[String]`, който запазва динамично-заделен масив.
+
+Имплементирайте негов наследник `[Name]`, който допълнително запазва число: номер на името (първо име, бащино име (второ име), фамилия (трето име)).
+
+Имплементирайте втори наследник на `[String]`, `[Street]`, който запазва и число: номер на улицата.
+
+Във всеки клас имплементирайте голяма петица, член-функция `[Length]`, като:
+.bulleted
+- в `[String]` връща дължината на низа,
+- в `[Name]` връща дължината на името умножена по номера си и
+- в `[Street]` връща дължината на името на улицата плюс броя цифри в номера на улицата.
+
+Самият низ в `[String]` =[не]= може да се достъпва от наследниците.
+
+### Задача 5
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise05 Решение]
+
+.comment Templates 1 type
+
+Реализирайте шаблонен клас `[Counted]`, който запазва елемент от подаден тип и неговата бройка (цяло неотрицателно число).
+Имплементирайте оператори `[++]`, `[--]`, `[+=]`, `[-=]`, които променят бройката, както и гетъри за елемента и бройката.
+
+### Задача 6
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise06 Решение]
+
+.comment Templates 2 types
+
+Реализирайте шаблонен клас `[TwoArray]`, който запазва два динамично-заделени масива с подадени типове.
+Масивите не могат да се оразмеряват и имат еднаква дължина.
+
+Имплементирайте:
+.bulleted
+- голяма петица,
+- оператор `[[]]`, който по подаден индекс връща елемент от първия масив, и
+- оператор `[()]`, който по подаден индекс връща елемент от втория масив.
+
+### Задача 7
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise07 Решение]
+
+.comment Abstract class
+
+Реализирайте абстрактен клас `[DynamicArray]`, който задължава наследниците да имплементират оператор `[[]]` и оператор `[+=]`.
+
+Реализирайте негови наследници:
+
+:unordered
+- `[Numbers]`, който "имплементира" динамично-заделен масив от цели числа, като
+
+ .bulleted
+ - оператор `[[]]` връща първия елемент, по-малък от подадения индекс. Ако няма такъв, връщате първия елемент.
+ - оператор `[+=]` вмъква елементите в началото на масива
+
+- `[String]`, който "имплементира" динамично-заделен масив от букви, като
+
+ .bulleted
+ - оператор `[[]]` връща индекс на брой (първата, втората, ...) главна буква в низа. Ако няма такава, тогава връща последната буква.
+ - оператор `[+=]` вмъква елементите в края на масива
+
+
+Имплементирайте голяма петица.
+
+.question Къде ще имплементирате динамичния масив и голямата петица?
+
+.question Можем ли да използваме оператор `[+=]` в полиморфна йерархия?
+
+### Задача 8
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise08 Решение]
+
+.comment Abstract class
+
+Имплементирайте абстрактен клас `[Message]`, който съдържа динамично-заделен низ (текстово съобщение, което се показва на екрана) и задължава наследниците да имплементират:
+.unordered
+- метод `[size]`, който връща общия размер на всички данни в байтове.
+
+Реализирайте негов наследник `[Link]` (хипервръзка), който запазва и втори динамично-заделен низ, запазващ адресът към който линкът сочи.
+
+Реализирайте втори негов наследник `[Location]`, чието текстово съдържание е адрес, и който допълнително запазва две стойности с плаваща запетая: една за географска ширина и втора за географска дължина.
+
+За всички класове реализирайте член-функция `[Length]`, която връща размера на =[текстовото съобщение]= и оператор `[<<]`.
+
+.question Има ли разлика между оператор `[<<]` на трите класа?
+
+### Задача 9
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise09 Решение]
+
+Реализирайте абстрактен шаблонен клас `[MixedArray]`, който съхранява алтерниращи елементи от два типа.
+Тоест, на индекс 0 имаме елемент от първия тип, на индекс 1 от втория, на индекс 2 от първи и так. нат.
+
+Елементите не е нужно да могат да се конвертират помежду си (тоест не може да използвате полиморфен контейнер), затова се достъпват с член функция `[At]`, приемаща индекс и референции към указатели към всеки тип.
+При подаден индекс, на единия указател се записва адресът на съответната стойност, а на другия `[nullptr]`.
+
+Също имплементира голяма петица и задължава наследниците да имплементират оператори `[+=]`, върщащи указател.
+
+Реализирайте негов наследник `[DirectConcat]`, който реализира `[+=]` като директно слепване (конкатениране).
+
+Реализирайте втори негов наследник, `[MixedConcat]`, който реализир `[+=]` като алтернира елемент от първия масив с елемент от втория.
+
+## Трудни
+
+### Задача 10
+
+Реализирайте система за документ с форматиран текст.
+В нея всеки елемент от документа е от тип Node, като за един Node трябва да имате:
+.bulleted
+- id, автоматично-избрано число, с което отличава Node
+- operator<<
+- operator[]
+
+Реализирайте следните типове Node:
+.bulleted
+- paragraph, това е най-обикновен низ
+- anchor, това е хипервръзка (линк), която съхранява видимо съдържание и уеб адрес
+- emplaced link, това е хипервръзка при която видимото съдържание съвпада с уеб адреса
+- заглавие, което е като хипервръзка, но уеб адресът започва с '#' и останалото съвпада със текстовото съдържание, като всяка буква е малка и вместо шпации има тирета
+- bulletpoint list, който съхранява редица Node-ове и ги изкарва на екрана, всяко на нов ред, започващи с '-'
+- table, която съхранява таблица с Node-ове
+
+Имплементирайте клас Document, който запазва масив от Node-ове и за който са имплементирани:
+.bulleted
+- методи save и load, които запазват и четат цялото съдържание на документа в =[текстов]= файл с произволен формат.
+
+### Задача 11
+
+Ще реализирате система за изпълнение на крайни автомати (от Теоретични Компютърни науки, ЕАИ).
+
+За тази цел е нужен абстрактен шаблонен клас State, чиито тип определя азбуката, който съхранява динамично-заделен масив от преходи (Transition) и задължава protected имплементация на член-функцията equal, която приема два елемента от азбуката и връща дали са равни.
+Имплементирайте голяма петица и оператор +=, който вмъква нов преход в състоянието.
+
+Реализирайте абстрактен шаблонен клас Transition, чиито тип определя азбуката, и който съхранява елемент от този тип (стойността, която ако е равна на подадената ще изпълним прехода) и указател към следващо състояние.
+Класът задължава имплементацията на оператор [], който по подаден елемент от азбуката или връща указателя към следващото състояние, или връща nullptr.
+
+Реализирайте наследник на State, ArrayState, който (допускате че) приема указател на динамичо-заделен масив.
+
+Реализирайте наследник на Transition, PrintedTransition, който при всяко извикване на оператор [] също изкарва съобщение на екрана.
+
+Реализирайте клас FiniteStateMachine, който съхранява динамичен масив от състояния.
+За него имплементирайте голяма петица и конструктор, приемащ име на текстов файл в CSV формат, в който са запазени:
+.bulleted
+- на първия ред обща информация във формата "Transitions,StartStateName", след това
+- състояния и преходи във формата "StateName,OnValue,TransitionTo", после
+- финални състояния във формата "FinalStateName1,FinalStateName2,...", и накрая
+- входни букви от азбуката "Letter1,Letter2,...".
+
+Имплементирайте метод Run, който изпълнява автомата и връща булева стойност: дали приема входните букви или не.
diff --git a/src/teaching/oop-2023/week11/index.md b/src/teaching/oop-2023/week11/index.md
deleted file mode 100644
index 8ac676b..0000000
--- a/src/teaching/oop-2023/week11/index.md
+++ /dev/null
@@ -1,201 +0,0 @@
-# Задачи - ООП, Седмица 11, 09.05.2024
-
-GitHub classroom: [classroom.github.com/a/oYQehcnN](https://classroom.github.com/a/oYQehcnN)
-
-## Преговорни
-
-&:warn Моля, не отделяйте на преговорните задачи повече от 30мин
-
-&:important Всеки бащин клас, във всички случаи, трябва да има виртуален деструктор (`virtual ~ClassName();`).
-
-### Задача 1 - Шаблони и оператори
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise01)
-
-Реализирайте шаблонен клас множество, който запазва фиксиран брой елементи от подаден тип.
-Реализирайте голяма петица и оператори:
-
-- `+`, `+=` които действат като обединение
-- `*`, `*=` които действат като сечение
-- `-`, `-=` които действат като допълнение
-
-### Задача 2 - Наследяване
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise02)
-
-Реализирайте клас `Employee`, съхраняващ име на човек, позиция и департамент като низове със съответно дължина 512, 128 и 64, заедно със заплата като число с плаваща запетая.
-
-Реализирайте негов наследник `Manager`, който допълнително пази масив с фиксиран размер от Employee.
-
-Реализирайте наследника на `Employee`, `Developer`, който допълнително пази брой проекти върху който работи.
-
-Наследниците не могат да достъпят заплатата, но трябва да могат да достъпят другите данни на `Employee`.
-
-## Лесни
-
-### Задача 3
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise03)
-
-<!-- Динамично свързване, Inherit 3 -->
-
-Реализирайте клас `Electronics`, който съдържа модел (низ с максимална дължина от 255 знака), `needsVolts` и `needsAmps` (стойности с плаваща запетая).
-
-Имплементирайте негови наследници:
-
-- `Laptop`, който допълнително съхранява размер на екрана като число с плаваща запетая
-- `WashingMachine`, който допълнително запазва максимално тегло на прането, като цяло неотрицателно число
-- `Camera`, която допълнително запазва резолюция като число с плаваща запетая (в мегапиксели)
-
-За всеки клас реализирайте член-функция `Print`, която изкарва всички данни на екрана.
-
-&:question Чрез статично или динамично свързване сте имплементирали `Print`? Каква е разликата?
-
-### Задача 4
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise04)
-
-<!-- Dynamic linking, Inherit 2 -->
-
-Реализирайте клас `String`, който запазва динамично-заделен масив.
-
-Имплементирайте негов наследник `Name`, който допълнително запазва число: номер на името (първо име, бащино име (второ име), фамилия (трето име)).
-
-Имплементирайте втори наследник на `String`, `Street`, който запазва и число: номер на улицата.
-
-Във всеки клас имплементирайте голяма петица, член-функция `Length`, като:
-
-- в `String` връща дължината на низа,
-- в `Name` връща дължината на името умножена по номера си и
-- в `Street` връща дължината на името на улицата плюс броя цифри в номера на улицата.
-
-Самият низ в `String` **не** може да се достъпва от наследниците.
-
-### Задача 5
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise05)
-
-<!-- Templates 1 type -->
-
-Реализирайте шаблонен клас `Counted`, който запазва елемент от подаден тип и неговата бройка (цяло неотрицателно число).
-Имплементирайте оператори `++`, `--`, `+=`, `-=`, които променят бройката, както и гетъри за елемента и бройката.
-
-### Задача 6
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise06)
-
-<!-- Templates 2 types -->
-
-Реализирайте шаблонен клас `TwoArray`, който запазва два динамично-заделени масива с подадени типове.
-Масивите не могат да се оразмеряват и имат еднаква дължина.
-
-Имплементирайте:
-
-- голяма петица,
-- оператор `[]`, който по подаден индекс връща елемент от първия масив, и
-- оператор `()`, който по подаден индекс връща елемент от втория масив.
-
-### Задача 7
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise07)
-
-<!-- Abstract class -->
-
-Реализирайте абстрактен клас `DynamicArray`, който задължава наследниците да имплементират оператор `[]` и оператор `+=`.
-
-Реализирайте негови наследници:
-
-- `Numbers`, който "имплементира" динамично-заделен масив от цели числа, като
- + оператор `[]` връща първия елемент, по-малък от подадения индекс. Ако няма такъв, връщате първия елемент.
- + оператор `+=` вмъква елементите в началото на масива
-- `String`, който "имплементира" динамично-заделен масив от букви, като
- + оператор `[]` връща индекс на брой (първата, втората, ...) главна буква в низа. Ако няма такава, тогава връща последната буква.
- + оператор `+=` вмъква елементите в края на масива
-
-Имплементирайте голяма петица.
-
-&:question Къде ще имплементирате динамичния масив и голямата петица?
-
-&:question Можем ли да използваме оператор `+=` в полиморфна йерархия?
-
-### Задача 8
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise08)
-
-<!-- Abstract class -->
-
-Имплементирайте абстрактен клас `Message`, който съдържа динамично-заделен низ (текстово съобщение, което се показва на екрана) и задължава наследниците да имплементират:
-
-- метод `size`, който връща общия размер на всички данни в байтове.
-
-Реализирайте негов наследник `Link` (хипервръзка), който запазва и втори динамично-заделен низ, запазващ адресът към който линкът сочи.
-
-Реализирайте втори негов наследник `Location`, чието текстово съдържание е адрес, и който допълнително запазва две стойности с плаваща запетая: една за географска ширина и втора за географска дължина.
-
-За всички класове реализирайте член-функция `Length`, която връща размера на **текстовото съобщение** и оператор `<<`.
-
-&:question Има ли разлика между оператор `<<` на трите класа?
-
-### Задача 9
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week11/Exercise09)
-
-Реализирайте абстрактен шаблонен клас `MixedArray`, който съхранява алтерниращи елементи от два типа.
-Тоест, на индекс 0 имаме елемент от първия тип, на индекс 1 от втория, на индекс 2 от първи и так. нат.
-
-Елементите не е нужно да могат да се конвертират помежду си (тоест не може да използвате полиморфен контейнер), затова се достъпват с член функция `At`, приемаща индекс и референции към указатели към всеки тип.
-При подаден индекс, на единия указател се записва адресът на съответната стойност, а на другия `nullptr`.
-
-Също имплементира голяма петица и задължава наследниците да имплементират оператори `+=`, върщащи указател.
-
-Реализирайте негов наследник `DirectConcat`, който реализира `+=` като директно слепване (конкатениране).
-
-Реализирайте втори негов наследник, `MixedConcat`, който реализир `+=` като алтернира елемент от първия масив с елемент от втория.
-
-## Трудни
-
-### Задача 10
-
-Реализирайте система за документ с форматиран текст.
-В нея всеки елемент от документа е от тип Node, като за един Node трябва да имате:
-
-- id, автоматично-избрано число, с което отличава Node
-- operator<<
-- operator[]
-
-Реализирайте следните типове Node:
-
-- paragraph, това е най-обикновен низ
-- anchor, това е хипервръзка (линк), която съхранява видимо съдържание и уеб адрес
-- emplaced link, това е хипервръзка при която видимото съдържание съвпада с уеб адреса
-- заглавие, което е като хипервръзка, но уеб адресът започва с '#' и останалото съвпада със текстовото съдържание, като всяка буква е малка и вместо шпации има тирета
-- bulletpoint list, който съхранява редица Node-ове и ги изкарва на екрана, всяко на нов ред, започващи с '-'
-- table, която съхранява таблица с Node-ове
-
-Имплементирайте клас Document, който запазва масив от Node-ове и за който са имплементирани:
-
-- методи save и load, които запазват и четат цялото съдържание на документа в **текстов** файл с произволен формат.
-
-### Задача 11
-
-Ще реализирате система за изпълнение на крайни автомати (от Теоретични Компютърни науки, ЕАИ).
-
-За тази цел е нужен абстрактен шаблонен клас State, чиито тип определя азбуката, който съхранява динамично-заделен масив от преходи (Transition) и задължава protected имплементация на член-функцията equal, която приема два елемента от азбуката и връща дали са равни.
-Имплементирайте голяма петица и оператор +=, който вмъква нов преход в състоянието.
-
-Реализирайте абстрактен шаблонен клас Transition, чиито тип определя азбуката, и който съхранява елемент от този тип (стойността, която ако е равна на подадената ще изпълним прехода) и указател към следващо състояние.
-Класът задължава имплементацията на оператор [], който по подаден елемент от азбуката или връща указателя към следващото състояние, или връща nullptr.
-
-Реализирайте наследник на State, ArrayState, който (допускате че) приема указател на динамичо-заделен масив.
-
-Реализирайте наследник на Transition, PrintedTransition, който при всяко извикване на оператор [] също изкарва съобщение на екрана.
-
-Реализирайте клас FiniteStateMachine, който съхранява динамичен масив от състояния.
-За него имплементирайте голяма петица и конструктор, приемащ име на текстов файл в CSV формат, в който са запазени:
-
-- на първия ред обща информация във формата "Transitions,StartStateName", след това
-- състояния и преходи във формата "StateName,OnValue,TransitionTo", после
-- финални състояния във формата "FinalStateName1,FinalStateName2,...", и накрая
-- входни букви от азбуката "Letter1,Letter2,...".
-
-Имплементирайте метод Run, който изпълнява автомата и връща булева стойност: дали приема входните букви или не.
diff --git a/src/teaching/oop-2023/week12/index.du b/src/teaching/oop-2023/week12/index.du
new file mode 100644
index 0000000..b0384e5
--- /dev/null
+++ b/src/teaching/oop-2023/week12/index.du
@@ -0,0 +1,97 @@
+# Задачи - ООП, Седмица 12, 09.05.2024
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/o7hNz1pr classroom.github.com/a/o7hNz1pr]
+
+### Задача 1
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week12/Exercise1 Решение]
+
+.comment Multiple inheritance
+
+Реализирайте клас `[Publication]`, който пази:
+
+.bulleted
+- низ от максимална дължина 1023, съхраняващ автори и
+- втори низ с максимална дължина от 255, съхраняващ име на (научно) списание.
+
+Реализирайте клас `[TextDocument]`, който пази неоразмеряем низ с текстово съдържание и неговия размер.
+
+Реализирайте наследник на двата класа `[ScientificPaper]`, който допълнително пази и низ от максимално 511 знака, съдържащ име на научна дисциплина.
+За всички класове реазлизирайте оператор <<.
+
+### Задача 2
+
+*[Не говорим за нея, условието беше толкова сбъркано, че се наложи да я сваля]*
+
+### Задача 3
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week12/Exercise3 Решение]
+
+Реализирайте абстрактен клас `[MobileDevice]`, който запазва:
+.bulleted
+- телефонен номер като цяло неотрицателно число и
+- масив с максимална дължина от 511 знака за текстово съобщение.
+
+Допълнително нека:
+.bulleted
+- класът да задължава имплементацията на метод `[Show]`,
+- да има член-функция `[CanAccept]`, която по подадено "хиперсъобщение" връща дали неговия номер съвпада с този на класа.\n
+ Под "хиперсъобщение" имаме предвид низ, който започва с телефонния номер, след това има шпация и след това е самото съобщение.
+- да има член-функция `[Accept]`, която по подадено "хиперсъобщение" запазва текстовото съобщение.
+ Ако номерът не съответства тогава хвърля грешка.
+
+Реализирайте негов наследник `[Telephone]`, за който `[Show]` изкарва съобщението на екрана.
+
+'footnote pager От времето без мобилни телефони, хората са си купували пейджъри, които ти пращат нотификация ако някой ти звънне и не вдигнеш. Пейджърите са "заключени" за определени региони, тоест някой ти се обажда, не вдигаш, и всички телекомуникционни кули в региона изпращат съобщение "на теб ти звънна този", и пейджъра като засече сигнала ти писука. Мисля че също можеш да пращаш кратки съобщения. Не е било хич сигурна система, все още се ползва от болници в някои държави.
+
+Реализирайте втори негов наследник `[Pager]` [$pager], който съхранява име на файл (като динамично-заделен низ) и `[Show]` изкарва съобщението в съответния файл.
+Разбира се, имплементирайте голяма петица.
+
+Реализирайте клас `[TelecommunicationCompany]`, който съхранява динамично-заделен и оразмеряем масив от (указатели към) `[MobileDevice]`.
+Имплементирайте всичко от голяма петица.
+
+### Задача 4
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week12/Exercise4 Решение]
+
+.comment Multiple inheritance with mixed class types, polymorphic container, and copying
+
+Реализирайте клас `[Employee]`, който запазва:
+.bulleted
+- заплата като число с плаваща запетая и
+- производителост също като число с плаваща запетая.
+
+Производителността е множител на заплатата, тоест ако има производителност 0.5 значи работи като човек на който му плащат с половината заплата.
+
+Реализирайте абстрактен клас `[Person]`, който запазва:
+.bulleted
+- име като низ с произволна дължина и
+- възраст като цяло неотрицателно число
+
+Допълнително задължава реализацията на член-функция `[Workload]`, връщаща стойност с плаваща запетая.
+Разбира се имплементирайте голяма петица.
+
+Реализирайте наследник на двата класа на име `[Developer]`, който допълнително запазва:
+.bulleted
+- цяло неотрицателно число - брой проекти в които участва, и
+- второ което е брой проекти на които ще се пуска нова версия.
+
+Реализирайте оператори `[++]` и `[--]`, като префиксните променят броя проекти на които ще се пуска нова версия, докато постфиксните променя броя проекти в които участва.\n
+За него `[Workload]` се определя като 1.1 по всеки проект и допълнително по 2.3 за всеки проект на който ще се пуска нова версия.
+
+Реализирайте наследник на двата класа на име `[Manager]`, който допълнително запазва динамично-заделен и оразмеряем масив от `[Person]`, които менижира.
+
+Имплементирайте голяма петица и:
+.bulleted
+- оператори `[==]` и `[!=]`, сравняващи хора по име
+- член-функция `[StartManaging]`, която приема `[Person]` и го запазва, и
+- член-функция `[StopManaging]`, която приема `[Person]` и го премахва от масива ако съществува в него.
+
+`[Workload]` се определя като 0.6 на човек който менижира.
+
+Финално реализирайте клас `[Company]`, който запазва масив от 128 указателя `[Person]` в компанията.
+Имплементирайте негова член-функция:
+.bulleted
+- `[PaymentDifference]`, която връща с колко платената заплата на всички служители се отличава с тази според тяхната производителност
diff --git a/src/teaching/oop-2023/week12/index.md b/src/teaching/oop-2023/week12/index.md
deleted file mode 100644
index b492678..0000000
--- a/src/teaching/oop-2023/week12/index.md
+++ /dev/null
@@ -1,94 +0,0 @@
-# Задачи - ООП, Седмица 12, 09.05.2024
-
-GitHub classroom: [classroom.github.com/a/o7hNz1pr](https://classroom.github.com/a/o7hNz1pr)
-
-### Задача 1
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week12/Exercise1)
-
-<!-- Multiple inheritance -->
-
-Реализирайте клас `Publication`, който пази:
-
-- низ от максимална дължина 1023, съхраняващ автори и
-- втори низ с максимална дължина от 255, съхраняващ име на (научно) списание.
-
-Реализирайте клас `TextDocument`, който пази неоразмеряем низ с текстово съдържание и неговия размер.
-
-Реализирайте наследник на двата класа `ScientificPaper`, който допълнително пази и низ от максимално 511 знака, съдържащ име на научна дисциплина.
-За всички класове реазлизирайте оператор <<.
-
-### Задача 2
-
-*Не говорим за нея, условието беше толкова сбъркано, че се наложи да я сваля*
-
-### Задача 3
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week12/Exercise3)
-
-Реализирайте абстрактен клас `MobileDevice`, който запазва:
-
-- телефонен номер като цяло неотрицателно число и
-- масив с максимална дължина от 511 знака за текстово съобщение.
-
-Допълнително нека:
-
-- класът да задължава имплементацията на метод `Show`,
-- да има член-функция `CanAccept`, която по подадено "хиперсъобщение" връща дали неговия номер съвпада с този на класа.
- Под "хиперсъобщение" имаме предвид низ, който започва с телефонния номер, след това има шпация и след това е самото съобщение.
-- да има член-функция `Accept`, която по подадено "хиперсъобщение" запазва текстовото съобщение.
- Ако номерът не съответства тогава хвърля грешка.
-
-Реализирайте негов наследник `Telephone`, за който `Show` изкарва съобщението на екрана.
-
-Реализирайте втори негов наследник `Pager`[^pager], който съхранява име на файл (като динамично-заделен низ) и `Show` изкарва съобщението в съответния файл.
-Разбира се, имплементирайте голяма петица.
-
-Реализирайте клас `TelecommunicationCompany`, който съхранява динамично-заделен и оразмеряем масив от (указатели към) `MobileDevice`.
-Имплементирайте всичко от голяма петица.
-
-### Задача 4
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week12/Exercise4)
-
-<!-- Multiple inheritance with mixed class types, polymorphic container, and copying -->
-
-Реализирайте клас `Employee`, който запазва:
-
-- заплата като число с плаваща запетая и
-- производителост също като число с плаваща запетая.
-
-Производителността е множител на заплатата, тоест ако има производителност 0.5 значи работи като човек на който му плащат с половината заплата.
-
-Реализирайте абстрактен клас `Person`, който запазва:
-
-- име като низ с произволна дължина и
-- възраст като цяло неотрицателно число
-
-Допълнително задължава реализацията на член-функция `Workload`, връщаща стойност с плаваща запетая.
-Разбира се имплементирайте голяма петица.
-
-Реализирайте наследник на двата класа на име `Developer`, който допълнително запазва:
-
-- цяло неотрицателно число - брой проекти в които участва, и
-- второ което е брой проекти на които ще се пуска нова версия.
-
-Реализирайте оператори `++` и `--`, като префиксните променят броя проекти на които ще се пуска нова версия, докато постфиксните променя броя проекти в които участва.
-За него `Workload` се определя като 1.1 по всеки проект и допълнително по 2.3 за всеки проект на който ще се пуска нова версия.
-
-Реализирайте наследник на двата класа на име `Manager`, който допълнително запазва динамично-заделен и оразмеряем масив от `Person`, които менижира.
-
-Имплементирайте голяма петица и:
-
-- оператори `==` и `!=`, сравняващи хора по име
-- член-функция `StartManaging`, която приема `Person` и го запазва, и
-- член-функция `StopManaging`, която приема `Person` и го премахва от масива ако съществува в него.
-
-`Workload` се определя като 0.6 на човек който менижира.
-
-Финално реализирайте клас `Company`, който запазва масив от 128 указателя `Person` в компанията.
-Имплементирайте негова член-функция:
-
-- `PaymentDifference`, която връща с колко платената заплата на всички служители се отличава с тази според тяхната производителност
-
-[^pager]: От времето без мобилни телефони, хората са си купували пейджъри, които ти пращат нотификация ако някой ти звънне и не вдигнеш. Пейджърите са "заключени" за определени региони, тоест някой ти се обажда, не вдигаш, и всички телекомуникционни кули в региона изпращат съобщение "на теб ти звънна този", и пейджъра като засече сигнала ти писука. Мисля че също можеш да пращаш кратки съобщения. Не е било хич сигурна система, все още се ползва от болници в някои държави.
diff --git a/src/teaching/oop-2023/week13/index.du b/src/teaching/oop-2023/week13/index.du
new file mode 100644
index 0000000..936f34b
--- /dev/null
+++ b/src/teaching/oop-2023/week13/index.du
@@ -0,0 +1,141 @@
+# Задачи - ООП, Седмица 13, 16.05.2024
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/GvV1wrC1 classroom.github.com/a/GvV1wrC1]
+
+.warn Навсякъде, където е нужно, реализирайте голяма петица.
+
+## Преговорни
+
+### Задача 1 - Множествено наследяване
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week13/Exercise1 Решение]
+
+Реализирайте клас `[String]`, който запазва динамичен низ с фиксиран размер.
+
+Реализирайте клас `[IndexArray]`, който запазва динамичен масив с фиксиран размер от цели числа - индекси.
+
+.warn =[Не]= правете общ родител, който имплементира динамичен масив!
+
+Реализирайте наследник на двата класа, `[WordsString]`, при който индексите определят началото на всяка дума от запазения низ.
+Индексите се дефинират при конструктора.
+
+## Лесни
+
+### Задача 2
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week13/Exercise2 Решение]
+
+.comment Диамант
+
+Реализирайте шаблонен клас `[Container]`, който съхранява масив с фиксиран размер от елементи с подаден тип.
+=[Не]= трябва да реализирате нищо повече от задължителните компоненти (голяма петица).
+
+Реализирайте негов наследник `[Indexable]`, който реализира оператор[].
+
+Реализирайте втори негов наследник `[Resizeable]`, който реализира член-функция `[InsertAt]`, приемаща елемент и индекс, и която вмъква елемента на даден индекс.
+Разбира се, може да се наложи оразмеряване на масива.
+
+Реализирайте наследник `[Vector]` на `[Indexable]` и `[Resizeable]`, който реализира оператор[] и член-функции:
+.bulleted
+- `[pop_back]`, премахваща последния елемент
+- `[pop_front]`, премахваща първия елемент
+- `[push_back]`, приемаща елемент който се вкарва в края на масив
+- `[push_front]`, приемаща елемент който се вкарва в началото на масив
+
+.important Не забравяйте за диамантния проблем!
+
+### Задача 3
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week13/Exercise3 Решение]
+
+.comment Диамант
+
+Реализирайте клас `[User]`, който запазва потребителско име и парола като низове с произволна дължина, заедно с булев флаг `[banned]`, определящ дали акаунтът може да прави действия.
+Потребителско име не може да съдържа шпации.
+
+Реализирайте клас `[Thread]`, който запазва масив с произволна дължина, от низове с произволна дължина.
+Имплементирайте член-функция:
+
+.bulleted
+- `[PostMessage]`, която приема потребител и негово съобщение и добавя съобщението с потребителското име като един низ.
+ Ако потребителя е `[banned]`, тогава хвърлете грешка.
+
+Реализирайте наследник `[ThreadModerator]` на `[User]`, който може да променя `[Thread]` обекти, без да се нуждае от публични член-функции в `[Thread]`.
+Имплементирайте методи:
+.bulleted
+- `[RemoveMessage]`, който приема `[Thread]` и индекс на съобщение и премахва съответното съобщение
+- `[RemoveByUser]`, който приема `[Thread]` и потребител, и премахва всички съобщения, направени от дадения потребител
+
+Реализирайте наследник `[UserModerator]` на `[User]`, който може да променя `[User]` обекти, без да се нуждае от публични член-функции в `[User]`.
+Имплементирайте методите:
+.bulleted
+- `[BanUser]`, който приема потребител и вдига `[banned]` флага
+- `[UnbanUser]`, който приема потребител и сваля `[banned]` флага
+
+Реализирайте наследник `[Administrator]` на `[ThreadModerator]` и `[UserModerator]`, който може да прави всичко, което и родителите могат.
+
+.important Не забравяйте за диамантния проблем!
+
+## Трудни
+
+### Задача 4
+
+Реализирайте абстрактен клас `[ShopLocation]`, който съхранява член-данни:
+.bulleted
+- адрес като низ с максимална дължина от 511 знака.
+ Всеки адрес съдържа произволни символи и задължително завършва на число, определящо неговия район.
+- време на отваряне и време на затваряне
+
+Имплементирате методи:
+.bulleted
+- `[IsOpen]`, който връща по подаден час дали локацията е отворена
+- `[InCenter]`, който връща дали локацията се намира в центъра на града.
+ Всички адреси с регион, по-малък от 11, се намират в центъра.
+
+Реализирайте шаблонен клас `[Inventory]`, който съхранява =[фиксиран]= брой елементи и техните неотрицателни бройки (количества).
+Имплементирайте член-функции:
+.bulleted
+- оператор[], който връща елемент на дадения индекс
+- оператор(), който връща бройка на елемент на дадения индекс
+- `[Stock]`, приемащ индекс на елемент и бройка (положителна/отрицателна) с която бройката на дадения елемент се променя.
+ Бройката може да бъде най-малко 0.
+- `[List]`, който връща всички елементи и техните индекси
+
+Реализирайте абстрактен шаблонен наследник `[DeliverableInventory]` на `[Inventory]`, който е инвентар с максимум 2048 елемента и допълнително задължава имплементацията на:
+.bulleted
+- `[ShippingDelay]`, който приема адрес и връща времето в което ще може да се достави обекта
+
+Реализирайте наследник на `[DeliverableInventory]`, склад `[Warehouse]`, който допълнително запазва разстояние от града в километри и имплементира `[ShippingDelay]` по следната логика:
+.bulleted
+- доставки в центъра отнемат един ден + регионът в който се доставя
+- доставки извън центъра отнемат толкова време, колкото е нужно да се стигне до града ако пътува с 80 километра в час + времето което ще отнеме да се измине номер на региона на брой километри при скорост от 20 километра в час
+
+Доставка не може да се случи преди 9 сутринта и след 18 вечерта.
+Ако попадне в този диапазон, тогава се отлага за най-скорошния следващ възможен час.
+
+Реализирайте шаблонен наследник магазин `[Shop]` на `[ShopLocation]` и `[Inventory]`, който е инвентар с максимум 256 елемента, запазващ:
+.bulleted
+- =[оразмеряем]= масив от низове с произволен размер, всеки низ който е "отчет на продажба"
+- общо бройка продажби
+
+и който имплементира методи:
+.bulleted
+- `[SellItems]`, който приема масив от идентификатори на обекти, намалява бройката на всеки от тях и създава нов отчет.
+ Отчета е в произволен формат, но трябва да съдържа идентификаторите и бройките на всеки обект.
+ Ако за някой обект няма достатъчно бройки или изобщо не се пази, хвърлете грешка.
+
+Реализирайте шаблонен клас `[WebStore]`, който запазва оразмеряеми масиви от `[Shop]` и `[Warehouse]`.
+Имплементирайте:
+.bulleted
+- оператор<<, който изкарва всички уникални (unique) обекти от всички магазини и складове, с индекс до тях
+- `[GetEstimate]`, който приема индекс на уникален обект от всички магазини и складове, сегашно време и адрес, и изкарва на екрана всички магазини които са отворени в дадения час и кое е най-скорошното време в което може обектът да се достави от склад.
+ Ако няма отворени магазини, ако няма магазин с наличност и так. нат. изкарайте съответно съобщение.
+
+Последно реализирайте клас `[Book]`, който запазва заглавие на книга и име на автор като низове с максимална дължина от 127 знака.
+Имплементирайте оператор<<, който изкарва съответната книга в произволен формат.
+
+В главната функция реализирайте `[WebStore]` от книги, заедно с набор от книги, магазини и складове по ваш избор.
+Нека в началото на програмата да приемате от потребителя сегашното време и адрес, след това изкарайте на екрана всички ункални книги с индекси.
+Накрая потребителя може да въведе индекс на книга и да получи информация кои отворени сега магазини имат съответната книга и кога най-скоро може да бъде доставена от склад.
diff --git a/src/teaching/oop-2023/week13/index.md b/src/teaching/oop-2023/week13/index.md
deleted file mode 100644
index 5d2ad35..0000000
--- a/src/teaching/oop-2023/week13/index.md
+++ /dev/null
@@ -1,138 +0,0 @@
-# Задачи - ООП, Седмица 13, 16.05.2024
-
-GitHub classroom: [classroom.github.com/a/GvV1wrC1](https://classroom.github.com/a/GvV1wrC1)
-
-&:warn Навсякъде, където е нужно, реализирайте голяма петица.
-
-## Преговорни
-
-### Задача 1 - Множествено наследяване
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week13/Exercise1)
-
-Реализирайте клас `String`, който запазва динамичен низ с фиксиран размер.
-
-Реализирайте клас `IndexArray`, който запазва динамичен масив с фиксиран размер от цели числа - индекси.
-
-&:warn **Не** правете общ родител, който имплементира динамичен масив!
-
-Реализирайте наследник на двата класа, `WordsString`, при който индексите определят началото на всяка дума от запазения низ.
-Индексите се дефинират при конструктора.
-
-## Лесни
-
-### Задача 2
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week13/Exercise2)
-
-<!-- Диамант -->
-
-Реализирайте шаблонен клас `Container`, който съхранява масив с фиксиран размер от елементи с подаден тип.
-**Не** трябва да реализирате нищо повече от задължителните компоненти (голяма петица).
-
-Реализирайте негов наследник `Indexable`, който реализира оператор[].
-
-Реализирайте втори негов наследник `Resizeable`, който реализира член-функция `InsertAt`, приемаща елемент и индекс, и която вмъква елемента на даден индекс.
-Разбира се, може да се наложи оразмеряване на масива.
-
-Реализирайте наследник `Vector` на `Indexable` и `Resizeable`, който реализира оператор[] и член-функции:
-
-- `pop_back`, премахваща последния елемент
-- `pop_front`, премахваща първия елемент
-- `push_back`, приемаща елемент който се вкарва в края на масив
-- `push_front`, приемаща елемент който се вкарва в началото на масив
-
-&:important Не забравяйте за диамантния проблем!
-
-### Задача 3
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week13/Exercise3)
-
-<!-- Диамант -->
-
-Реализирайте клас `User`, който запазва потребителско име и парола като низове с произволна дължина, заедно с булев флаг `banned`, определящ дали акаунтът може да прави действия.
-Потребителско име не може да съдържа шпации.
-
-Реализирайте клас `Thread`, който запазва масив с произволна дължина, от низове с произволна дължина.
-Имплементирайте член-функция:
-
-- `PostMessage`, която приема потребител и негово съобщение и добавя съобщението с потребителското име като един низ.
- Ако потребителя е `banned`, тогава хвърлете грешка.
-
-Реализирайте наследник `ThreadModerator` на `User`, който може да променя `Thread` обекти, без да се нуждае от публични член-функции в `Thread`.
-Имплементирайте методи:
-
-- `RemoveMessage`, който приема `Thread` и индекс на съобщение и премахва съответното съобщение
-- `RemoveByUser`, който приема `Thread` и потребител, и премахва всички съобщения, направени от дадения потребител
-
-Реализирайте наследник `UserModerator` на `User`, който може да променя `User` обекти, без да се нуждае от публични член-функции в `User`.
-Имплементирайте методите:
-
-- `BanUser`, който приема потребител и вдига `banned` флага
-- `UnbanUser`, който приема потребител и сваля `banned` флага
-
-Реализирайте наследник `Administrator` на `ThreadModerator` и `UserModerator`, който може да прави всичко, което и родителите могат.
-
-&:important Не забравяйте за диамантния проблем!
-
-## Трудни
-
-### Задача 4
-
-Реализирайте абстрактен клас `ShopLocation`, който съхранява член-данни:
-
-- адрес като низ с максимална дължина от 511 знака.
- Всеки адрес съдържа произволни символи и задължително завършва на число, определящо неговия район.
-- време на отваряне и време на затваряне
-
-Имплементирате методи:
-
-- `IsOpen`, който връща по подаден час дали локацията е отворена
-- `InCenter`, който връща дали локацията се намира в центъра на града.
- Всички адреси с регион, по-малък от 11, се намират в центъра.
-
-Реализирайте шаблонен клас `Inventory`, който съхранява **фиксиран** брой елементи и техните неотрицателни бройки (количества).
-Имплементирайте член-функции:
-
-- оператор[], който връща елемент на дадения индекс
-- оператор(), който връща бройка на елемент на дадения индекс
-- `Stock`, приемащ индекс на елемент и бройка (положителна/отрицателна) с която бройката на дадения елемент се променя.
- Бройката може да бъде най-малко 0.
-- `List`, който връща всички елементи и техните индекси
-
-Реализирайте абстрактен шаблонен наследник `DeliverableInventory` на `Inventory`, който е инвентар с максимум 2048 елемента и допълнително задължава имплементацията на:
-
-- `ShippingDelay`, който приема адрес и връща времето в което ще може да се достави обекта
-
-Реализирайте наследник на `DeliverableInventory`, склад `Warehouse`, който допълнително запазва разстояние от града в километри и имплементира `ShippingDelay` по следната логика:
-
-- доставки в центъра отнемат един ден + регионът в който се доставя
-- доставки извън центъра отнемат толкова време, колкото е нужно да се стигне до града ако пътува с 80 километра в час + времето което ще отнеме да се измине номер на региона на брой километри при скорост от 20 километра в час
-
-Доставка не може да се случи преди 9 сутринта и след 18 вечерта.
-Ако попадне в този диапазон, тогава се отлага за най-скорошния следващ възможен час.
-
-Реализирайте шаблонен наследник магазин `Shop` на `ShopLocation` и `Inventory`, който е инвентар с максимум 256 елемента, запазващ:
-
-- **оразмеряем** масив от низове с произволен размер, всеки низ който е "отчет на продажба"
-- общо бройка продажби
-
-и който имплементира методи:
-
-- `SellItems`, който приема масив от идентификатори на обекти, намалява бройката на всеки от тях и създава нов отчет.
- Отчета е в произволен формат, но трябва да съдържа идентификаторите и бройките на всеки обект.
- Ако за някой обект няма достатъчно бройки или изобщо не се пази, хвърлете грешка.
-
-Реализирайте шаблонен клас `WebStore`, който запазва оразмеряеми масиви от `Shop` и `Warehouse`.
-Имплементирайте:
-
-- оператор<<, който изкарва всички уникални (unique) обекти от всички магазини и складове, с индекс до тях
-- `GetEstimate`, който приема индекс на уникален обект от всички магазини и складове, сегашно време и адрес, и изкарва на екрана всички магазини които са отворени в дадения час и кое е най-скорошното време в което може обектът да се достави от склад.
- Ако няма отворени магазини, ако няма магазин с наличност и так. нат. изкарайте съответно съобщение.
-
-Последно реализирайте клас `Book`, който запазва заглавие на книга и име на автор като низове с максимална дължина от 127 знака.
-Имплементирайте оператор<<, който изкарва съответната книга в произволен формат.
-
-В главната функция реализирайте `WebStore` от книги, заедно с набор от книги, магазини и складове по ваш избор.
-Нека в началото на програмата да приемате от потребителя сегашното време и адрес, след това изкарайте на екрана всички ункални книги с индекси.
-Накрая потребителя може да въведе индекс на книга и да получи информация кои отворени сега магазини имат съответната книга и кога най-скоро може да бъде доставена от склад.
diff --git a/src/teaching/oop-2023/week14/index.md b/src/teaching/oop-2023/week14/index.du
index 917c11b..761edd5 100644
--- a/src/teaching/oop-2023/week14/index.md
+++ b/src/teaching/oop-2023/week14/index.du
@@ -1,6 +1,8 @@
# Задачи - ООП, Седмица 14, 23.05.2024
-GitHub classroom: [classroom.github.com/a/K0XomKEP](https://classroom.github.com/a/K0XomKEP)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/K0XomKEP classroom.github.com/a/K0XomKEP]
## Задача
@@ -13,36 +15,36 @@ GitHub classroom: [classroom.github.com/a/K0XomKEP](https://classroom.github.com
Преди да стигнем до потребителите, ще се нуждаем от някои други компоненти.
Реализирайте предмет, като в един предмет се пазят:
-
+.bulleted
- име
- тип (задължителен/избираем)
- брой ECTS кредити, които носи
- код, комбинация от главна буква и 3-цифрено число
Реализирайте семестър, като в един семестър се пазят:
-
+.bulleted
- учебната година
- тип (зимен/летен)
- учебния план (низ във формата "СПЕЦИАЛННОСТ(УЧЕБЕН КУРС)")
- предмети; разбира се един предмет може да се споделя от няколко семестъра
Реализирайте специалност, която пази:
-
+.bulleted
- свое име
- катедра към която е свързана
- всички семестри, в които е (била) активна
- предмети, съответстващи на всеки тип семестър
и имплементира метод:
-
-- `NewSemester`, който приема учебна година и тип, и връща нов обект от семестър с попълнени данни
+.bulleted
+- `[NewSemester]`, който приема учебна година и тип, и връща нов обект от семестър с попълнени данни
Имаме потребители, като всеки си има роля, определяща неговите способности в системата.
Ролята може да бъде студент, преподавател или администратор, като при конкретизиране в условието на някои от тях трябва да се извършат съответните проверки.
Ваш избор е какво да бъде ролята.
За един потребител със сигурност се пазят:
-
+.bulleted
- име
- факултетен номер (от модерния стил)
- потребителско име, което се определя като първата буква от първото име, конкатенирана с фамилията.
@@ -51,12 +53,10 @@ GitHub classroom: [classroom.github.com/a/K0XomKEP](https://classroom.github.com
- година на учебния план
- име на сегашна специалност
-<br>
-
+.bulleted
- данни за контакт, като една данна съдържа тип и описание (произволни низове)
-<br>
-
+.bulleted
- семестри, в които е (бил) включен
- изпити, които са комбинация от предмети, преподаватели и оценки (която е възможно да не е въведена)
@@ -64,7 +64,7 @@ GitHub classroom: [classroom.github.com/a/K0XomKEP](https://classroom.github.com
Имплементирайте съответни член-функции, които да правят тези действия.
Имплементирйате и методи, приемащи потребителско име, които:
-
+.bulleted
- за един потребител изкарва всички негови лични данни, заедно с кратко описание на семестрите в които е включен
- за един студент изкарва всички изпити, заедно със семестрите към които са свързани и сума на всички успешно получени кредити за дадения семестър (кредитите се броят само когато има оценка, която не е двойка)
- един преподавател може да създаде нов предмет
diff --git a/src/teaching/oop-2023/week15/index.md b/src/teaching/oop-2023/week15/index.du
index 6719bf0..7bf678f 100644
--- a/src/teaching/oop-2023/week15/index.md
+++ b/src/teaching/oop-2023/week15/index.du
@@ -1,6 +1,8 @@
# Задачи - ООП, Седмица 15, 30.05.2024
-GitHub classroom: [classroom.github.com/a/z2QadyEE](https://classroom.github.com/a/z2QadyEE)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/z2QadyEE classroom.github.com/a/z2QadyEE]
## Задача
@@ -11,13 +13,13 @@ GitHub classroom: [classroom.github.com/a/z2QadyEE](https://classroom.github.com
Реализирайте система за чат.
В нея имаме съобщения, като едно съобщение може да бъде:
-
+.bulleted
- текст, като низ
- локация, като съвкупност от държава, град, област (число), улица и номер на улица
- линк (хипервръзка) като текст и (уеб) адрес
- време: дата и час
-Всеки тип трябва да имплементира `Print` член-функция, която изкарва текстово съдържание на съобщението.
+Всеки тип трябва да имплементира `[Print]` член-функция, която изкарва текстово съдържание на съобщението.
За текстово съобщение това е самия текст, за локация това е низ във формата "[ДЪРЖАВА] ГРАД(ОБЛАСТ) УЛИЦА NoНОМЕР НА УЛИЦА", за линк е самия текст и за време е "ЧАС:МИНУТИ ДЕН.МЕСЕЦ.ГОДИНА".
Реализирайте потребители, като за всеки потребител имаме потребителско име и парола.
diff --git a/src/teaching/oop-2023/week16/index.md b/src/teaching/oop-2023/week16/index.du
index f95271d..da0c1d6 100644
--- a/src/teaching/oop-2023/week16/index.md
+++ b/src/teaching/oop-2023/week16/index.du
@@ -1,6 +1,8 @@
# Задачи - ООП, Седмица 16, 06.06.2024
-GitHub classroom: [classroom.github.com/a/BWjw2dUC](https://classroom.github.com/a/BWjw2dUC)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/BWjw2dUC classroom.github.com/a/BWjw2dUC]
## Задача
@@ -11,7 +13,7 @@ GitHub classroom: [classroom.github.com/a/BWjw2dUC](https://classroom.github.com
Разбира се, отдолу няма истински файлове които се запазват в харддиск (примерно), просто ОС превежда всички тези операции върху файлове със съответни действия към устройството.
Реализирайте подобна система.
-Първо трябва ни обща схема за файлове, за всеки файл имаме `Read` и `Write` методи, и пазим името на файла.
+Първо трябва ни обща схема за файлове, за всеки файл имаме `[Read]` и `[Write]` методи, и пазим името на файла.
За всяко устройство само по себе си знаем, че трябва да използваме определен драйвър (по име) и че то има малко информация за себе си: марка като низ и модел като цяло число.
По-конкретно разглежаме два основни типа устройства: индексируемо и поточно (streamable).
@@ -27,4 +29,3 @@ GitHub classroom: [classroom.github.com/a/BWjw2dUC](https://classroom.github.com
Имаме и конкретен тип поточно устройство: мрежов адаптер.
Разбира се, той е и мрежов интерфейс, като идеята е, че по файловия интерфейс се предават статистични и информативни данни, но не и пакети.
-
diff --git a/src/teaching/oop-2023/week2/index.md b/src/teaching/oop-2023/week2/index.du
index f8f27d9..6302ac0 100644
--- a/src/teaching/oop-2023/week2/index.md
+++ b/src/teaching/oop-2023/week2/index.du
@@ -1,17 +1,19 @@
# Задачи - ООП, Седмица 2, 29.02.2024
-GitHub classroom: [classroom.github.com/a/3qPsfyyI](https://classroom.github.com/a/3qPsfyyI)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/3qPsfyyI classroom.github.com/a/3qPsfyyI]
## Задача 0 - Преговорна
-&::solution-link [Решения](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp Решения]
-Ще работим върху N-мерен [морски шах](https://en.wikipedia.org/wiki/Tic-tac-toe), тоест ще имаме дъска за морски шах, която може да е по-голяма от 3 на 3 (примерно 5 на 5, 7 на 7 и т.н.).
+Ще работим върху N-мерен [url https://en.wikipedia.org/wiki/Tic-tac-toe морски шах], тоест ще имаме дъска за морски шах, която може да е по-голяма от 3 на 3 (примерно 5 на 5, 7 на 7 и т.н.).
Няма да се занимаваме с проверки дали (и кой) е спечелил след даден ход, интересуваме се само от запазването на данни.
Основната логика е следната, като във всяка подточка правила по имплементацията са зададени.
-&:warn Не почвайте веднага да имплементирайте, погледнете подточките!
+.warn Не почвайте веднага да имплементирайте, погледнете подточките!
В началото от входа се въвеждат два реда, всеки съответстващ на имената на даден играч (в тези имена може да има шпации).
Първият играч винаги играе като X, вторият винаги като O.
@@ -21,61 +23,61 @@ GitHub classroom: [classroom.github.com/a/3qPsfyyI](https://classroom.github.com
За всеки играч трябва съответно да изкарате общия брой X-ове или броя O-та в цялата дъска, както и дължината на най-дългата последователност от Х-ове или О-та в един реда на дъската (примерно за първия играч, търсим реда с най-много последователни X-ове, и изкарваме тяхната бройка).
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|Emil Petkov<br>BoburaBG<br>5<br>X X O O O<br>O X O X X<br>O X X X O<br>O X X X X<br>O X O O O<br>|Emil Petkov: Total - 13, Longest - 4<br>BoburaBG: Total - 12, Longest - 3|
+.table
+|=Вход=||=Изход=|
+|:Emil Petkov\nBoburaBG\n5\nX X O O O\nO X O X X\nO X X X O\nO X X X X\nO X O O O\n:||:Emil Petkov: Total - 13, Longest - 4\nBoburaBG: Total - 12, Longest - 3:|
### а) без структури
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L3-L83)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L3-L83 Решение]
-&:important Решете подточката **без** структури, тоест без знания по ООП
+.important Решете подточката =[без]= структури, тоест без знания по ООП
-Имплементирайте **функция** `boardCounts`, която приема дъската и връща по някакъв начин нужните бройки: общ брой X-ове, общ брой O-та, брой X-ове в най-дългата последователност от X-ове в ред, брой O-та в най-дългата последователност от O-та в ред.
+Имплементирайте =[функция]= `[boardCounts]`, която приема дъската и връща по някакъв начин нужните бройки: общ брой X-ове, общ брой O-та, брой X-ове в най-дългата последователност от X-ове в ред, брой O-та в най-дългата последователност от O-та в ред.
-След това имплементирайте фукция `printResult`, която приема имената на двата играча, както и бройките, върнати от `boardCounts`, и изкарва на екрана съобщенията във формата от примера.
+След това имплементирайте фукция `[printResult]`, която приема имената на двата играча, както и бройките, върнати от `[boardCounts]`, и изкарва на екрана съобщенията във формата от примера.
### б) структура за board
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L85-L166)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L85-L166 Решение]
"Слепете" в една съвкупност (структура) указателя към самата дъска за морски шах, както и нейния размер N.
-Нека името на структурата да бъде `GameBoard`.
+Нека името на структурата да бъде `[GameBoard]`.
-Обновете `boardCounts`, така че вместо да приема дъската и размера ѝ чрез две променливи, да ги приема чрез една променлива от тип `GameBoard`.
+Обновете `[boardCounts]`, така че вместо да приема дъската и размера ѝ чрез две променливи, да ги приема чрез една променлива от тип `[GameBoard]`.
### в) структура за числата
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L168-L255)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L168-L255 Решение]
-"Слепете" в една съвкупност (структура) на име `BoardCounts` четирите променливи, които `boardCounts` връща.
+"Слепете" в една съвкупност (структура) на име `[BoardCounts]` четирите променливи, които `[boardCounts]` връща.
-Обновете `boardCounts` да връща една стойност от тип `BoardCounts`, вместо да връща четирите бройки като отделни числа.
-Обновете `printResult` да приема стойност от тип `BoardCounts`, вместо да приема четирите бройки като отделни числа.
+Обновете `[boardCounts]` да връща една стойност от тип `[BoardCounts]`, вместо да връща четирите бройки като отделни числа.
+Обновете `[printResult]` да приема стойност от тип `[BoardCounts]`, вместо да приема четирите бройки като отделни числа.
### г) структура за цялата игра
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L257-L300)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise0.cpp#L257-L300 Решение]
-Сега "слепете" предходните две структури, заедно с имената на нашите играчи, в една голяма обща структура за цялата игра на име `Game`.
-Тоест, всичките ни данни: дъската, бройките и имената на играчите, да се намират в `Game`.
+Сега "слепете" предходните две структури, заедно с имената на нашите играчи, в една голяма обща структура за цялата игра на име `[Game]`.
+Тоест, всичките ни данни: дъската, бройките и имената на играчите, да се намират в `[Game]`.
-&:important Искам да *композирате*, тоест искам да използвате `GameBoard` и `BoardCounts` структурите в `Game` структурата.
+.important Искам да *[композирате]*, тоест искам да използвате `[GameBoard]` и `[BoardCounts]` структурите в `[Game]` структурата.
-Обновете `boardCounts` и `printResult`, така че да използват тази структура.
+Обновете `[boardCounts]` и `[printResult]`, така че да използват тази структура.
## Задача 1 - Основи от материала
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise1.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise1.cpp Решение]
Работите върху система за инвентар на книжарница.
-&:warn Не е задължително, но е препоръчително да си направите и една структура `String` с конструктор и деструктор
-
-Създайте структура `Book` със скрити (private) данни за:
+.warn Не е задължително, но е препоръчително да си направите и една структура `[String]` с конструктор и деструктор
+Създайте структура `[Book]` със скрити (private) данни за:
+.bulleted
- заглавие, като един низ
- автори, като масив от низове
- година на публикация, като целочислено число
@@ -83,66 +85,66 @@ GitHub classroom: [classroom.github.com/a/3qPsfyyI](https://classroom.github.com
За всяка от тях създайте съответните публични селектор (get-ър) и мутатор (set-ър) член-функции (методи).
Set-ърите трябва да записват стойности в данните, само когато съответните проверки са изпълнени:
-
+.bulleted
- заглавието не може да бъде празния низ
- трябва да има поне един автор, името на даден автор не може да бъде празния низ
- годината на публикация не може да надвишава 2024, не може да е по-малка от -2100 (2100 п.н.е.) и не може да бъде нула
- цената не може да е отрицателна
-Всеки от мутаторите трябва да връща булева стойност, `true` ако проверките са изпълнени (и запазването на данни е извършено) и `false` ако съответната проверка не е изпълнена (и няма промяна в данните).
+Всеки от мутаторите трябва да връща булева стойност, `[true]` ако проверките са изпълнени (и запазването на данни е извършено) и `[false]` ако съответната проверка не е изпълнена (и няма промяна в данните).
Създайте съответните конструктори и деструктори.
-След това направете структура `Library`, която държи масив от книги и бройката за всяка книга (отново като скрити данни).
+След това направете структура `[Library]`, която държи масив от книги и бройката за всяка книга (отново като скрити данни).
Най-лесния вариант е да имате втори масив, като за всеки индекс в масива с книги, на същия индекс в масива за бройки се намира съответната бройка.
-Можете и да го направите чрез структура `Pair` и да имате един масив.
+Можете и да го направите чрез структура `[Pair]` и да имате един масив.
-Като публични методи на `Library` имплементирайте `AddBook`, която вмъква нова книга в масива, и `RemoveBook` която съответно "премахва" книга по заглавие и година.
-Допълнително направете член-функция `StockBook`, която приема заглавие на книга, годината ѝ, и цяло число с което наличната бройка се увеличава.
-Аналогично направете и `SellBook`.
+Като публични методи на `[Library]` имплементирайте `[AddBook]`, която вмъква нова книга в масива, и `[RemoveBook]` която съответно "премахва" книга по заглавие и година.
+Допълнително направете член-функция `[StockBook]`, която приема заглавие на книга, годината ѝ, и цяло число с което наличната бройка се увеличава.
+Аналогично направете и `[SellBook]`.
За всики тези методи трябва да имате съответните проверки:
+.bulleted
+- ако напълно идентична книга вече съществува, `[AddBook]` не трябва да я добавя на ново
+- `[RemoveBook]` не трябва да "гърми" ако книгата не съществува
+- бройката на добавени/продадени книги, подадени на `[SellBook]` и `[StockBook]`, трябва да бъдат положителни, както и книгите да съществуват
-- ако напълно идентична книга вече съществува, `AddBook` не трябва да я добавя на ново
-- `RemoveBook` не трябва да "гърми" ако книгата не съществува
-- бройката на добавени/продадени книги, подадени на `SellBook` и `StockBook`, трябва да бъдат положителни, както и книгите да съществуват
-
-Аналогично като при `Book`, тези функции трябва да връщат булева стойност, дали проверките са изпълнени.
+Аналогично като при `[Book]`, тези функции трябва да връщат булева стойност, дали проверките са изпълнени.
Не забравяйте за конструктор и деструктор!
-&:question Можете ли да си улесните работата, ако използвате скрити член-функции?
+.question Можете ли да си улесните работата, ако използвате скрити член-функции?
-Не е нужно да правите потребителски вход/изход, но тествайте ръчно кода си в `main`.
+Не е нужно да правите потребителски вход/изход, но тествайте ръчно кода си в `[main]`.
## Задача 2
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise2.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise2.cpp Решение]
Работите върху система за Excel-ски таблици.
Една клетка може да съдържа някаква числена стойност, или проста формула която определя тази стойност.
-Създайте структура `Cell`, която запазва (скрито) целочислена стойност, знак, който определя опреацията във формулата, и два указателя на `Cell` към двете страни на оператора.
-Оператора (знака) може да бъде `+`, `-`, `*` или `/`.
+Създайте структура `[Cell]`, която запазва (скрито) целочислена стойност, знак, който определя опреацията във формулата, и два указателя на `[Cell]` към двете страни на оператора.
+Оператора (знака) може да бъде `[+]`, `[-]`, `[*]` или `[/]`.
Идеята е, че ако клетката само запазва стойност, тогава оператора ще бъде нещо празно (терминираща нула например).
Обаче ако се определя от формула, тогава оператора и указателите също ще са попълнени, а запазената стойност ще действа като кеш, тоест вместо всеки път да преизчисляваме стойността когато я искаме, преизчислили сме я веднъж и я запазваме.
-За тази цел имплементирайте публична член-функция `evaluate`, ако не е запазена формула, тя не прави нищо, ако е, прави съответното изчисление и запазва резултата.
-Разбира се, направете и мутатори `setValue` и `setFormula`, със съответните проверки.
+За тази цел имплементирайте публична член-функция `[evaluate]`, ако не е запазена формула, тя не прави нищо, ако е, прави съответното изчисление и запазва резултата.
+Разбира се, направете и мутатори `[setValue]` и `[setFormula]`, със съответните проверки.
Не забравяйте за конструктор и деструктор.
-Сега направете структура `Table`, която пази (скрито) двумерен масив от клетки.
-Имплементирайте селектор `getCell`, който връща указател на клетка по координати и мутатор `setCell`, който приема клетка и координати в масива.
+Сега направете структура `[Table]`, която пази (скрито) двумерен масив от клетки.
+Имплементирайте селектор `[getCell]`, който връща указател на клетка по координати и мутатор `[setCell]`, който приема клетка и координати в масива.
-&:question Какъв ще е типа на подадената клетка и стойностите в масива?
+.question Какъв ще е типа на подадената клетка и стойностите в масива?
-Направете метод `updateCell`, чрез която стойностите на клетка по координати могат да бъдат променени, и след това всички клетки в таблицата се преизчисляват.
+Направете метод `[updateCell]`, чрез която стойностите на клетка по координати могат да бъдат променени, и след това всички клетки в таблицата се преизчисляват.
-Последно, имплементирайте и член-функция `printTable`, която изкарва на екрана цялата таблица, като клетката на индекси 0,0 се намира в горния ляв ъгъл, всички клетки са разделени с `|`.
+Последно, имплементирайте и член-функция `[printTable]`, която изкарва на екрана цялата таблица, като клетката на индекси 0,0 се намира в горния ляв ъгъл, всички клетки са разделени с `[|]`.
-Не е нужно да правите потребителски вход/изход, но тествайте ръчно кода си в `main`.
+Не е нужно да правите потребителски вход/изход, но тествайте ръчно кода си в `[main]`.
## Задача 3
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise3.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise3.cpp Решение]
Изграждате "симулация" за трафик върху секция от магистрала.
@@ -166,16 +168,16 @@ Set-ърите трябва да записват стойности в данн
Ако една кола успешно "излиза" от участака на магистралата, тоест тя се опитва да се придвижи някъде след края ѝ, зачитаме че успешно е минала пътя и спираме да я разглеждаме.
Сами определете как ще изглеждат структурите за колата и магистралата, както и нужните методи.
-Имайте предвид, че трябва цялата логика да присъства в тези структури, тоест в `main` трябва да присъства само някакъв инициализиращ код.
+Имайте предвид, че трябва цялата логика да присъства в тези структури, тоест в `[main]` трябва да присъства само някакъв инициализиращ код.
-&:important Не е позволено магистралата да бъде двумерна матрица, координатите на всяка кола се пазят в самата кола.
+.important Не е позволено магистралата да бъде двумерна матрица, координатите на всяка кола се пазят в самата кола.
Накрая пуснете симулацията няколко пъти, на всяко извикване трябва да изкарате на екрана брой получили се сблъсаци, както и броя нужни итерации с които сте обходили всички коли на пътя, докато всички те излязат от магистралата.
Симулации се различават с позиции и началните скорости на колите, бройката коли и размерите на магистралата си стоят.
## Задача 4
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise4.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week02/Exercise4.cpp Решение]
Имате фабрика, цялата ѝ структура се разглежда като един конвейер, тоест като една редица машини, всяка от които приема някакъв материал и връща този материал преобразуван.
@@ -188,7 +190,7 @@ Set-ърите трябва да записват стойности в данн
Типовете на материалите са отделни стойности от идентификационните номера, тоест като е подаден материал, той се превръща в крайния тип, и трябва да намерите на кой материал точва число е началния тип.
Всички тези данни трябва да са скрити, трябва за съответните структури да присъстват конструктори и деструктори.
-Допълнително при машините трябва да има член-функция `convertMaterial`, която получава идентификационен номер на материал и бройка, и връща колко от резултатния материал е успяла да създаде (спрямо ефикасността, закръглена надолу, и дали се нуждае от ремонт по средата на работата).
+Допълнително при машините трябва да има член-функция `[convertMaterial]`, която получава идентификационен номер на материал и бройка, и връща колко от резултатния материал е успяла да създаде (спрямо ефикасността, закръглена надолу, и дали се нуждае от ремонт по средата на работата).
Ще получите данни за всички материали и машини, както и задачи, тоест идентификационни номера на начален и краен материал, както и бройката на началния материал.
Трябва да намерите редицата от машини, които ще създадат възможно най-много краен материал.
diff --git a/src/teaching/oop-2023/week3/index.md b/src/teaching/oop-2023/week3/index.du
index c9b4963..44d23f7 100644
--- a/src/teaching/oop-2023/week3/index.md
+++ b/src/teaching/oop-2023/week3/index.du
@@ -1,25 +1,27 @@
# Задачи - ООП, Седмица 3, 07.03.2024
-GitHub classroom: [classroom.github.com/a/KPMqXsFp](https://classroom.github.com/a/KPMqXsFp)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/KPMqXsFp classroom.github.com/a/KPMqXsFp]
## Преговорни
### Задача 1 - Структури
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise1.cpp)
-
-Имплементирайте структура `Lightbulb`, която запазва идентифициращите данни за една крушка:
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise1.cpp Решение]
+Имплементирайте структура `[Lightbulb]`, която запазва идентифициращите данни за една крушка:
+.bulleted
- диаметър и дължина: и двете са целочислени стойности
- тип: низ с максимална дължина от 100 знака
- серия: буква на латиница
### Задача 2 - Капсулация
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise2.cpp)
-
-Имплементирайте структура `Alarm`, която съдържа следните **скрити** данни:
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise2.cpp Решение]
+Имплементирайте структура `[Alarm]`, която съдържа следните =[скрити]= данни:
+.bulleted
- име на модел: низ с максимална дължина от 1024 знака
- пин код: целочислено число
- ревизия на модела: число с плаваща запетая
@@ -27,7 +29,7 @@ GitHub classroom: [classroom.github.com/a/KPMqXsFp](https://classroom.github.com
За всяка данна трябва да създадете съответните get-ъри и set-ъри: публични член-функции, които съответно връщат и записват всяка от изброените скрити стойности.
При set-ърите имплементирайте следните проверки:
-
+.bulleted
- името на модела може да има само главни букви
- пин кода трябва да бъде 4 цифри (нули са позволени)
- ревизията трябва да бъде положително число
@@ -36,57 +38,57 @@ GitHub classroom: [classroom.github.com/a/KPMqXsFp](https://classroom.github.com
### Задача 3 - Капсулация с динамична памет
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise3.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise3.cpp Решение]
-Имплементирайте структура `Person`, която запазва двете имена на човек, възраст като целочислено число и неговия имейл.
+Имплементирайте структура `[Person]`, която запазва двете имена на човек, възраст като целочислено число и неговия имейл.
Имената и имейла са низвое с произволна дължина.
-Направете конструктор, който приема възрастта и тези три низа, и **копира** стойностите им в динамичната памет.
+Направете конструктор, който приема възрастта и тези три низа, и =[копира]= стойностите им в динамичната памет.
Също напишете и деструктор, който коректно трие нужните данни.
### Задача 4 - Динамично-заделени структури в други структури
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise4.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise4.cpp Решение]
-Имплементирайте структура `Bus`, която публично запазва капацитета хора и километража на един автобус.
+Имплементирайте структура `[Bus]`, която публично запазва капацитета хора и километража на един автобус.
-Имплементирайте структура `BusWarehouse`, която запазва динамично-заделен масив от автобуси.
-В конструктора се въвежда максималния брой автобуси, който може един `BusWarehouse` да съдържа.
+Имплементирайте структура `[BusWarehouse]`, която запазва динамично-заделен масив от автобуси.
+В конструктора се въвежда максималния брой автобуси, който може един `[BusWarehouse]` да съдържа.
Имплементирайте конструктор, който само инициализира нужните данни, и деструктор който трие каквото трябва.
-Имплементирайте член-функция `AddBus`, която добавя автобус в инстанция на `BusWarehouse`, ако има място за него.
+Имплементирайте член-функция `[AddBus]`, която добавя автобус в инстанция на `[BusWarehouse]`, ако има място за него.
## Лесни задачи
### Задача 5
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise5.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise5.cpp Решение]
-Имплементирайте структура `Car`, всяка кола пази скрито своя модел като низ с произволна дължина, брой врати и брой седалки като целочислени числа.
+Имплементирайте структура `[Car]`, всяка кола пази скрито своя модел като низ с произволна дължина, брой врати и брой седалки като целочислени числа.
Направете съответните get-ъри, set-ъри, конструктор и деструктор.
-Имплементирайте структура `TrafficJam`, която пази произволно дълга редица коли в задръстване.
-Направете и член-функция `AddCar`, която вмъква кола в края на редицата.
+Имплементирайте структура `[TrafficJam]`, която пази произволно дълга редица коли в задръстване.
+Направете и член-функция `[AddCar]`, която вмъква кола в края на редицата.
Тази функция може да се извиква произволен брой пъти, затова имплементирайте и оразмеряване на вътрешната редица.
-`TrafficJam` трябва да има конструктор, деструктор и тази член-функция.
+`[TrafficJam]` трябва да има конструктор, деструктор и тази член-функция.
### Задача 6
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise6.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise6.cpp Решение]
Ще работите с N-мерна шахматна дъска.
-Направете структура `ChessPiece`, която запазва цвета и типа на фигурата от шах, като първото е целочислена стойност, второто е буква.
+Направете структура `[ChessPiece]`, която запазва цвета и типа на фигурата от шах, като първото е целочислена стойност, второто е буква.
-Направете структура `ChessBoard`, която по подадено N в конструктора създава шахматна дъска с размер NxN с **указатели** към съответните фигури на дъската.
+Направете структура `[ChessBoard]`, която по подадено N в конструктора създава шахматна дъска с размер NxN с =[указатели]= към съответните фигури на дъската.
Разбира се, някои от тези указатели трябва да сочат към някакви създадени шахматни фигури.
При създаване на дъската, трябва да подредите фигурите.
На най-долните два реда присъстват белите фигури, на най-горните два - черните.
За дъска 8х8, фигурите са подредени както нормално:
-![](https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/The_chess_board_from_Chess.jpg/1024px-The_chess_board_from_Chess.jpg?20210610045654)
+[image https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/The_chess_board_from_Chess.jpg/1024px-The_chess_board_from_Chess.jpg?20210610045654]
При по-големи дъски започвате да повтаряте редиците, докато при по-малките ги режете, от дясната страна.
Тоест в дъска 10x10 първите 8 колони изглеждат като на картинката, на 9та колона (отгоре-надолу) имате черен топ, черна пешка, 6 празни места, бяла пешка, бял топ и на последната колона са черен кон, черна пешка, 6 празни места, бяла пешка, бял кон.
@@ -96,34 +98,34 @@ GitHub classroom: [classroom.github.com/a/KPMqXsFp](https://classroom.github.com
### Задача 7
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise7.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise7.cpp Решение]
Имате затворени интервали от целочислени числа.
Разглеждаме смесване на интервали:
+.bulleted
+- смеската на допиращи се интервали е тяхното слепване, тоест смеската на `[[0, 3]]` и `[[3, 5]]` е `[[0, 5]]`
+- смеската на препокриващи се интервали е тяхното обединение, тоест смеската на `[[0, 5]]` и `[[3, 8]]` е `[[0, 8]]`
-- смеската на допиращи се интервали е тяхното слепване, тоест смеската на `[0, 3]` и `[3, 5]` е `[0, 5]`
-- смеската на препокриващи се интервали е тяхното обединение, тоест смеската на `[0, 5]` и `[3, 8]` е `[0, 8]`
-
-В противен случай не можем да смесим интервалите (примерно не можем да смесим `[0, 3]` и `[4, 8]`).
+В противен случай не можем да смесим интервалите (примерно не можем да смесим `[[0, 3]]` и `[[4, 8]]`).
Започвайки от някакво множество с интервали, смесете колкото се може повече от тях и изкарайте всичките резултатни интервали, които не могат повече да се смесят.
Използвайте структури и член-функции.
### Задача 8
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise8.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week03/Exercise8.cpp Решение]
"Моделирайте" (тоест сами се сетете за типовете данни и нужните структури) един град със следните харакетристики.
В града имате два типа сгради: жилищни и търговски.
-
+.bulleted
- Жилищните се харакетиризират с цена на апратамент, бройката етажи, количеството хора, които се побират на един етаж (една стойност за всички етажи) и дали имат мазе, паркомясто и/или таван.
- Търговските се характеризират с цена на магазин, бройка етажи с паркинг, бройка етажи с магазини и максимално количество магазини, които се побират на един етаж (една стойност за всички етажи).
Градът трябва да пази всички отделни сгради, като допълнително за всяка жилищна трябва да съхранява общата бройка жители, a за всяка търговска - общата бройка отворени магазини.
Освен това трябва да се съхрани и нещо като карта на всичките сгради: допускаме Старозагоско/Манхатънско подреждане на сградите, тоест всички сгради се намират върху някаква "решетка".
-&:question Познавате ли структурата `Pair`?
+.question Познавате ли структурата `[Pair]`?
Имплементирайте възможност за построяване и събаряне на сгради.
Направете нужните проверки на всички данни: цената да не е отрицателна, бройката жители да не надвишава капацитета на сградата и так. нат.
@@ -151,25 +153,25 @@ GitHub classroom: [classroom.github.com/a/KPMqXsFp](https://classroom.github.com
Винаги започваме с една празна начална директория.
Двете функции, за създаване и изтриване, трябва да приемат масив от низове, който определя път от директории към желания файл, започвайки от началния файл.
-Тоест, ако бяха подадени низовете `Documents`, `Personal`, `Health`, `receipt.txt`, тогава от началния файл намираме името `Documents` и "влизаме" в директорията със съответния идентификационен номер, в нея намираме името `Personal` и так. нат.
+Тоест, ако бяха подадени низовете `[Documents]`, `[Personal]`, `[Health]`, `[receipt.txt]`, тогава от началния файл намираме името `[Documents]` и "влизаме" в директорията със съответния идентификационен номер, в нея намираме името `[Personal]` и так. нат.
### Задача 10
-Намираме се в равнината, при която всички (двуизмерни) координати са **целочислени**.
+Намираме се в равнината, при която всички (двуизмерни) координати са =[целочислени]=.
В нея имаме стъклени панели (прави отсечки), дефинирани с координатите на двете им крайни точки.
Допълнително всеки панел си има свой цвят (като проценти, между 0 и 1, от цветовете червено, зелено и синьо) и прозрачност (като процент, между 0 и 1).
Също имаме и един лъч, той се характеризира с началния си координат и единичен двуизмерен вектор, определящ неговата посока на движение.
-Този лъч не се пречупва и винаги се движи напред (преместването на лъча се извършва чрез `позиция = позиция + посока`).
+Този лъч не се пречупва и винаги се движи напред (преместването на лъча се извършва чрез `[позиция = позиция + посока]`).
Чрез този лъч трябва да изкарате композитния цвят, след като лъча е минал през всички стъклени панели пред него.
Нека също композитния цвят винаги да има 100% прозрачност.
-Примерно, ако лъча премине през един панел с цветови проценти `0,1,0` и прозрачност `0.5` и още един панел с цветови проценти `0,1,1` и прозрачност `0.5`, тогава композитния цвят е `0,1,0.5`.
+Примерно, ако лъча премине през един панел с цветови проценти `[0,1,0]` и прозрачност `[0.5]` и още един панел с цветови проценти `[0,1,1]` и прозрачност `[0.5]`, тогава композитния цвят е `[0,1,0.5]`.
-&:question Колко структури ще ви трябват?
+.question Колко структури ще ви трябват?
## Признания
-Изображението на шахматната дъска от chess.com, направено от Hfjhjoiijklij4 за [Уикипедия](https://commons.wikimedia.org/w/index.php?curid=106440749) под лиценз CC BY-SA 4.0
+Изображението на шахматната дъска от chess.com, направено от Hfjhjoiijklij4 за [url https://commons.wikimedia.org/w/index.php?curid=106440749 Уикипедия] под лиценз CC BY-SA 4.0
diff --git a/src/teaching/oop-2023/week4/index.du b/src/teaching/oop-2023/week4/index.du
new file mode 100644
index 0000000..a6e02b9
--- /dev/null
+++ b/src/teaching/oop-2023/week4/index.du
@@ -0,0 +1,115 @@
+# Задачи - ООП, Седмица 4, 14.03.2024
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/qa_FfWeG classroom.github.com/a/qa_FfWeG]
+
+## Преговорни
+
+### Задача 1 - Капсулация
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise1.cpp Решение]
+
+Имплементирайте структура `[Smartphone]`, която запазва =[скрито]=:
+.bulleted
+- марка, низ с максимална дължина от 128 знака
+- модел, низ с максимална дължина от 512 знака
+- година на произвеждане, неотрицателно целочислено число
+- резолюция на камера, число с плаваща запетая (обозначаващо мегапиксели)
+
+За всяка стойност напревете съответните get-ъри и set-ъри, правейки следните проверки при set-ърите:
+.bulleted
+- марката и моделът не могат да бъдат празни низове, или пък да надвишават максималната дължина
+- годината трябва да бъде между 2000 и 2024
+- резолюцията не може да бъде отрицателна (може да бъде нула, което показва, че смартфонът няма камера)
+
+При неизпълнено условие, хвърляте грешка.
+
+### Задача 2 - Капсулация с динамична памет
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise2.cpp Решение]
+
+Имплементирайте структура `[Bee]`, която запазва възрастта на пчела чрез число с плаваща запетая и типа пчела с буква.
+
+Имплементирайте структура `[BeeHive]`, която запазва динамично-заделен масив с всички реещи се пчели и друг динамично-заделен масив с всички яйца в кошера.
+Размерите на двата масива се подават на конструктора.
+Имплементирайте нужните конструктор и деструктор.
+
+## Лесни задачи
+
+### Задача 3
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise3.cpp Решение]
+
+Имплементирайте структура `[Paper]`, която запазва своето текстово съдържание като низ от максимум 1024 знака и положително цяло число, определящо номера на страницата.
+
+От входа получавате на един ред цялото текстото съдържание за един обект от тип `[Paper]` и на следващия ред - бройките копия `[N]` на дадения обект.
+
+Създайте `[Paper]` обект със съответното съдържание и номер на страницата `[1]`.
+Създайте динамично-заделен масив от `[Paper]` с размер `[N]`, като първия му елемент е новосъздадения обект, докато останалите са =[копия]= на първия обект.
+
+При всяко копие, трябва да увеличите номера на страницата.
+Имплементирейте логиката чрез копиращ конструктор.
+
+### Задача 4
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise4.cpp Решение]
+
+Създайте структура `[DynamicString]`, чиито конструктор приема низ с терминираща нула, заделя точно толкова динамична памет, колкото е нужно да се запази целия низ и копира буквите на низа в тази памет.
+Имплементирайте оператор равно.
+
+.question Какви данни трябва `[DynamicString]` да запазва скрито?
+
+:question
+Какво трябва оператор равно да направи, ако записваме в `[DynamicString]` с вече заделена памет?\n
+
+Тоест ако имахме:\n
+`[DynamicString s1("Hello"); DynamicString s2("World"); s2 = s1;]`
+
+
+### Задача 5
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise5.cpp Решение]
+
+Имплементирайте структура `[TVProgram]`, която запазва името на предаването като низ от максимум 1024 знака, начало на излъчване и край на излъчване като неотрицателни целочислени числа (като примерно 1347 е един часа и 47 минути следобед).
+Имплементирайте конструктор, деструктор, оператор равно и копиращ конструктор.
+
+Имплементирайте структура `[TVChannel]`, която запазва динамично заделен масив от `[TVProgram]`, размера на динамично заделената памет и броя "ненулеви" елементи (програми, добавени с `[AddProgram]`).
+
+Имплементирайте нейн метод `[AddProgram]`, който приема `[TVProgram]` =[по копие]= и го вмъква на последната свободна позиция в масива.
+Ако масива е пълен, трябва да го "оразмерите" (да направите нов, по-голям масив, да копирате данните от стария в новия, да изтриете стария и да обновите указателя да сочи към новия).
+
+.question Кога използвате копиращия конструктор на `[TVProgram]` и кога използвате оператор равно?
+
+## Трудни задачи
+
+### Задача 6
+
+Ще разработим (изключително груба) симулация на вселената.
+За нас, гравитацията няма да бъде сила, която просто привлича тела към себе си, а сила която кара телата около нея да се въртят ("орбитират") в перфектен кръг.
+Имаме много звезди и една планета, като звездите са винаги неподвижни, а планетата се влияе от тях.
+
+Гравитационното привличане на звезда в своя център се определя от ъгъла &theta;<sub>max</sub> (в градуси).
+Планетата се върти около една звезда, използвайки стандартната матрица за ротация:
+
+[image ./img/Rotation_matrix.png]
+
+Ъгълът на въртене &theta;, спрямо разстоянието до една звезда, се определя чрез [url https://en.wikipedia.org/wiki/Inverse-square_law закона на обратните квадрати], тоест в зависимост от разстоянието `[d]` между центъра на звездата и центъра на планетата, то истинският ъгъл на завъртане е &theta; = &theta;<sub>max</sub> * 1 / d^2.
+
+Допълнително, ако имаме повече от една звезда, тогава ще използваме &theta;' = max(&theta;<sub>i</sub> - average(&theta;<sub>1</sub>, ..., &theta;<sub>n</sub>)), където &theta;<sub>i</sub> е намереният ъгъл &theta; за i-тата звезда и имаме n на брой звезди.
+
+Ефектът на това е, че ако имаме две звезди на еднакво разстояние с еднакъв ъгъл, тогава планетата е неподвижна, а ако някоя планета е с малко по-близка, тогава се върти около нея и то съвсем бавно.
+
+Приемаме, че отнема единица време планетата да се завърти с ъгъл &theta;', без значение размера на ъгъла.
+Целта на задачата е да върнете при коя звезда и за колко единици време планетата е успяла да извърши пълна ротация (разбира се, &theta;' и планетата може да се измени след всяка ротация).
+
+Имплементирайте структури:
+.bulleted
+- `[Matrix2x2]` и `[Matrix2x1]`, чиито стойности са числа с плаваща запетая, и с член функции за събиране и умножение (не оператор+, оператор\*)
+- `[Coordinate]`, която запазва (=[не наследява]=) точките в пространството като `[Matrix2x1]` и имплементира събиране, умножение и разстояние между координати и матрици
+- `[Star]`, запазваща координатата на своя център (`[Matrix2x1]`) и ъгълът &theta;<sub>max</sub> като число с плаваща запетая.
+ Имплементирайте и метод, който приема планета и връща ъгълът &theta;.
+- `[Planet]`, запазваща своите координати (`[Matrix2x1]`) и изминалото време (тоест колко пъти се е движела от началото на симулацията).
+ Имплементирайте метод `[OrbitPlanet]`, която приема планета и ъгъл &theta;', и се завърта около нея.
+- `[Universe]`, запазваща всички звездите и планетата.
+ Имплементирайте метод `[FullOrbit]`, която връща звездата около която планетата е успяла да извърши пълна ротация и времето за което това се е случило.
diff --git a/src/teaching/oop-2023/week4/index.md b/src/teaching/oop-2023/week4/index.md
deleted file mode 100644
index b89a7a6..0000000
--- a/src/teaching/oop-2023/week4/index.md
+++ /dev/null
@@ -1,110 +0,0 @@
-# Задачи - ООП, Седмица 4, 14.03.2024
-
-GitHub classroom: [classroom.github.com/a/qa_FfWeG](https://classroom.github.com/a/qa_FfWeG)
-
-## Преговорни
-
-### Задача 1 - Капсулация
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise1.cpp)
-
-Имплементирайте структура `Smartphone`, която запазва **скрито**:
-
-- марка, низ с максимална дължина от 128 знака
-- модел, низ с максимална дължина от 512 знака
-- година на произвеждане, неотрицателно целочислено число
-- резолюция на камера, число с плаваща запетая (обозначаващо мегапиксели)
-
-За всяка стойност напревете съответните get-ъри и set-ъри, правейки следните проверки при set-ърите:
-
-- марката и моделът не могат да бъдат празни низове, или пък да надвишават максималната дължина
-- годината трябва да бъде между 2000 и 2024
-- резолюцията не може да бъде отрицателна (може да бъде нула, което показва, че смартфонът няма камера)
-
-При неизпълнено условие, хвърляте грешка.
-
-### Задача 2 - Капсулация с динамична памет
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise2.cpp)
-
-Имплементирайте структура `Bee`, която запазва възрастта на пчела чрез число с плаваща запетая и типа пчела с буква.
-
-Имплементирайте структура `BeeHive`, която запазва динамично-заделен масив с всички реещи се пчели и друг динамично-заделен масив с всички яйца в кошера.
-Размерите на двата масива се подават на конструктора.
-Имплементирайте нужните конструктор и деструктор.
-
-## Лесни задачи
-
-### Задача 3
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise3.cpp)
-
-Имплементирайте структура `Paper`, която запазва своето текстово съдържание като низ от максимум 1024 знака и положително цяло число, определящо номера на страницата.
-
-От входа получавате на един ред цялото текстото съдържание за един обект от тип `Paper` и на следващия ред - бройките копия `N` на дадения обект.
-
-Създайте `Paper` обект със съответното съдържание и номер на страницата `1`.
-Създайте динамично-заделен масив от `Paper` с размер `N`, като първия му елемент е новосъздадения обект, докато останалите са **копия** на първия обект.
-
-При всяко копие, трябва да увеличите номера на страницата.
-Имплементирейте логиката чрез копиращ конструктор.
-
-### Задача 4
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise4.cpp)
-
-Създайте структура `DynamicString`, чиито конструктор приема низ с терминираща нула, заделя точно толкова динамична памет, колкото е нужно да се запази целия низ и копира буквите на низа в тази памет.
-Имплементирайте оператор равно.
-
-&:question Какви данни трябва `DynamicString` да запазва скрито?
-
-&:question Какво трябва оператор равно да направи, ако записваме в `DynamicString` с вече заделена памет?
- Тоест ако имахме:
- `DynamicString s1("Hello"); DynamicString s2("World"); s2 = s1;`
-
-### Задача 5
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week04/Exercise5.cpp)
-
-Имплементирайте структура `TVProgram`, която запазва името на предаването като низ от максимум 1024 знака, начало на излъчване и край на излъчване като неотрицателни целочислени числа (като примерно 1347 е един часа и 47 минути следобед).
-Имплементирайте конструктор, деструктор, оператор равно и копиращ конструктор.
-
-Имплементирайте структура `TVChannel`, която запазва динамично заделен масив от `TVProgram`, размера на динамично заделената памет и броя "ненулеви" елементи (програми, добавени с `AddProgram`).
-
-Имплементирайте нейн метод `AddProgram`, който приема `TVProgram` **по копие** и го вмъква на последната свободна позиция в масива.
-Ако масива е пълен, трябва да го "оразмерите" (да направите нов, по-голям масив, да копирате данните от стария в новия, да изтриете стария и да обновите указателя да сочи към новия).
-
-&:question Кога използвате копиращия конструктор на `TVProgram` и кога използвате оператор равно?
-
-## Трудни задачи
-
-### Задача 6
-
-Ще разработим (изключително груба) симулация на вселената.
-За нас, гравитацията няма да бъде сила, която просто привлича тела към себе си, а сила която кара телата около нея да се въртят ("орбитират") в перфектен кръг.
-Имаме много звезди и една планета, като звездите са винаги неподвижни, а планетата се влияе от тях.
-
-Гравитационното привличане на звезда в своя център се определя от ъгъла &theta;<sub>max</sub> (в градуси).
-Планетата се върти около една звезда, използвайки стандартната матрица за ротация:
-
-![](./img/Rotation_matrix.png)
-
-Ъгълът на въртене &theta;, спрямо разстоянието до една звезда, се определя чрез [закона на обратните квадрати](https://en.wikipedia.org/wiki/Inverse-square_law), тоест в зависимост от разстоянието `d` между центъра на звездата и центъра на планетата, то истинският ъгъл на завъртане е &theta; = &theta;<sub>max</sub> * 1 / d^2.
-
-Допълнително, ако имаме повече от една звезда, тогава ще използваме &theta;' = max(&theta;<sub>i</sub> - average(&theta;<sub>1</sub>, ..., &theta;<sub>n</sub>)), където &theta;<sub>i</sub> е намереният ъгъл &theta; за i-тата звезда и имаме n на брой звезди.
-
-Ефектът на това е, че ако имаме две звезди на еднакво разстояние с еднакъв ъгъл, тогава планетата е неподвижна, а ако някоя планета е с малко по-близка, тогава се върти около нея и то съвсем бавно.
-
-Приемаме, че отнема единица време планетата да се завърти с ъгъл &theta;', без значение размера на ъгъла.
-Целта на задачата е да върнете при коя звезда и за колко единици време планетата е успяла да извърши пълна ротация (разбира се, &theta;' и планетата може да се измени след всяка ротация).
-
-Имплементирайте структури:
-
-- `Matrix2x2` и `Matrix2x1`, чиито стойности са числа с плаваща запетая, и с член функции за събиране и умножение (не оператор+, оператор\*)
-- `Coordinate`, която запазва (**не наследява**) точките в пространството като `Matrix2x1` и имплементира събиране, умножение и разстояние между координати и матрици
-- `Star`, запазваща координатата на своя център (`Matrix2x1`) и ъгълът &theta;<sub>max</sub> като число с плаваща запетая.
- Имплементирайте и метод, който приема планета и връща ъгълът &theta;.
-- `Planet`, запазваща своите координати (`Matrix2x1`) и изминалото време (тоест колко пъти се е движела от началото на симулацията).
- Имплементирайте метод `OrbitPlanet`, която приема планета и ъгъл &theta;', и се завърта около нея.
-- `Universe`, запазваща всички звездите и планетата.
- Имплементирайте метод `FullOrbit`, която връща звездата около която планетата е успяла да извърши пълна ротация и времето за което това се е случило.
diff --git a/src/teaching/oop-2023/week5/index.md b/src/teaching/oop-2023/week5/index.du
index be66316..f159418 100644
--- a/src/teaching/oop-2023/week5/index.md
+++ b/src/teaching/oop-2023/week5/index.du
@@ -1,35 +1,37 @@
# Задачи - ООП, Седмица 5, 21.03.2024
-GitHub classroom: [classroom.github.com/a/42ZZ56Mg](https://classroom.github.com/a/42ZZ56Mg)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/42ZZ56Mg classroom.github.com/a/42ZZ56Mg]
## Преговорни
### 1 задача - Капсулация с динамична памет
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise1.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise1.cpp Решение]
Пациент в болница се характеризира с идентификационен номер (неотрицателно целочислено число) и име (низ от максимум 1024 знака).
Една болница има максимален капацититет на болни, които може да държи (максимален брой легла за тях).
Конструктора за болницата приема максималния капацитет, като структурата за болницата пази всичките си пациенти.
-Имплементирайте методи `AddPatient`, който добавя нов пациент и `RemovePatient`, който го премахва от болницата.
+Имплементирайте методи `[AddPatient]`, който добавя нов пациент и `[RemovePatient]`, който го премахва от болницата.
Не е нужно данните за пациентите да са скрити, но данните в болницата трябва да са.
### 2 задача - Копиращ конструктор и оператор=
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise2.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise2.cpp Решение]
-Имплементирайте структура `FloatArray`, която запазва динамично-заделен масив от `float` стойности.
+Имплементирайте структура `[FloatArray]`, която запазва динамично-заделен масив от `[float]` стойности.
Размерът на масива се подава в конструктора.
-Имплементирайте копиращ конструктор, оператор= и get-ър/set-ър за елемент на индекс `i`.
+Имплементирайте копиращ конструктор, оператор= и get-ър/set-ър за елемент на индекс `[i]`.
## Лесни задачи
### 3 задача
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise3.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise3.cpp Решение]
Имейл се характеризира с две стойности: адресът от който е изпратен (низ с максимална дължина от 128 знака) и съдържание (низ с неограничен размер).
Съобщението се подава като указател към знак, и трябва да заделите точно толкова динамична памет, колкото ви трябва за целия текст.
@@ -38,7 +40,7 @@ GitHub classroom: [classroom.github.com/a/42ZZ56Mg](https://classroom.github.com
### 4 задача
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise4.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise4.cpp Решение]
Имплементирайте структура за касов бон, която запазва скрит динамично-заделен масив от цени (числа с плаваща запетая).
Можете да добавяте неограничен брой цени в края на касовия бон (ако масива е пълен, създавате по-голям и пренасяте стойностите).
@@ -49,7 +51,7 @@ GitHub classroom: [classroom.github.com/a/42ZZ56Mg](https://classroom.github.com
### 5 задача
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise5.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise5.cpp Решение]
Един контролен списък (checklist) пази няколко неща: булева стойност, дали е избран или не, текстово съдържание (низ с "произволна" дължина) и масив от контролни списъци (всеки списък от този масив ще наричам "подсписък" за удобство).
Нека текстовото съдържание да не може да се редактира (задава се в конструктора и няма set-ър).
@@ -59,31 +61,31 @@ GitHub classroom: [classroom.github.com/a/42ZZ56Mg](https://classroom.github.com
### 6 задача
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise6.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise6.cpp Решение]
Имате телефонен указател, който запазва масив от имена (низове).
В началото винаги започва празен.
Имплементирайте голяма четворка.
-Имплементирайте метод `InsertPerson`, който вмъква ново име в указателя, като вмъкването запазва сортировка по азбучен ред.
-Тоест ако указателя беше `{ "Atanas", "Yavor" }`, тогава след вмъкване на `Boris` ще имаме `{ "Atanas", "Boris", "Yavor" }`.
+Имплементирайте метод `[InsertPerson]`, който вмъква ново име в указателя, като вмъкването запазва сортировка по азбучен ред.
+Тоест ако указателя беше `[{ "Atanas", "Yavor" }]`, тогава след вмъкване на `[Boris]` ще имаме `[{ "Atanas", "Boris", "Yavor" }]`.
-&:important Имплементирайте вмъкване, запазващо "сортираност" без функция за сортиране!
+.important Имплементирайте вмъкване, запазващо "сортираност" без функция за сортиране!
### 7 задача
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise7.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week05/Exercise7.cpp Решение]
Имплементирайте структура водомер, която скрито запазва отчетеното количество вода (double).
-Има **единствено** конструктор по подразбиране, при който отчетеното количество е нула, метод `AddWater`, който увеличава брояча с подаденото количество вода и метод `Print`, който изкарва стойността на брояча на екрана.
+Има =[единствено]= конструктор по подразбиране, при който отчетеното количество е нула, метод `[AddWater]`, който увеличава брояча с подаденото количество вода и метод `[Print]`, който изкарва стойността на брояча на екрана.
Имплементирайте голяма четворка (когато е нужно).
Имплементирайте структура сграда, която има инсталирани подаден брой водомери.
-Имплементирайте метод `SimulateDay`, който "симулира" ден в сградата - към всички датчици се добавят между 0 и 0.42 вода (разглеждаме само числа с максимум 3 цифри след запетаята).
+Имплементирайте метод `[SimulateDay]`, който "симулира" ден в сградата - към всички датчици се добавят между 0 и 0.42 вода (разглеждаме само числа с максимум 3 цифри след запетаята).
Количеството е случайно за всеки ден.
-Имплементирайте метод `SimulateMonth`, който "симулира" 30 дена в сградата, като на всеки 5 дена се прави "отчет" - всичките водомери се **копират** и запазват във вътрешен масив.
+Имплементирайте метод `[SimulateMonth]`, който "симулира" 30 дена в сградата, като на всеки 5 дена се прави "отчет" - всичките водомери се =[копират]= и запазват във вътрешен масив.
На края на месеца изкарайте на екрана, на един ред, всичките водомери от първите дни (първи ден на първи отчет, първи ден на втори отчет, ...), вторите дни, ...
### 8 задача
@@ -91,15 +93,15 @@ GitHub classroom: [classroom.github.com/a/42ZZ56Mg](https://classroom.github.com
Една интернет заявка се характеризира с тип (низ от максимум 4 знака), версия на протокола (положително число с плаваща запетая) и идентификатор (буква).
Нека тези данни да са скрити, като единствено могат да се set-нат от конструктора (тоест няма set-ъри, но има get-ъри) и е имлементирана голяма четворка (когато е нужно).
-Интернет сървър обработва интернет заявки, като всяка получена заявка я запазва в нормалните логове (динамично-заделен масив със заявки) **и** в логовете за грешки (друг динамично-заделен масив със заявки).
+Интернет сървър обработва интернет заявки, като всяка получена заявка я запазва в нормалните логове (динамично-заделен масив със заявки) =[и]= в логовете за грешки (друг динамично-заделен масив със заявки).
-Разглеждаме четири типа заявки: `GET`, `HEAD`, `POST` и `PUT`.
+Разглеждаме четири типа заявки: `[GET]`, `[HEAD]`, `[POST]` и `[PUT]`.
За всяка сървърът съдържа динамично-заделен масив от низове.
Имплементирайте методи за добавяне на низ към всеки тип.
Ако съответния масив от низове е пълен, тогава трябва да го уголемите.
-Имплементирайте метод `HandleRequest`, който приема интернет заявка **по копие**, запазва я в нормалните логове и връща първия низ от масива на съответния тип, който започва с идентификатор-буквата.
-Ако такъв низ не съществува, тогава връща низа "Bad request" и добавя заявката **и** в логовете за грешки.
+Имплементирайте метод `[HandleRequest]`, който приема интернет заявка =[по копие]=, запазва я в нормалните логове и връща първия низ от масива на съответния тип, който започва с идентификатор-буквата.
+Ако такъв низ не съществува, тогава връща низа "Bad request" и добавя заявката =[и]= в логовете за грешки.
Размерите на логовете се подават на конструктора.
По принцип добавяте нови заявки в края на лога.
diff --git a/src/teaching/oop-2023/week6/index.du b/src/teaching/oop-2023/week6/index.du
new file mode 100644
index 0000000..9a2947e
--- /dev/null
+++ b/src/teaching/oop-2023/week6/index.du
@@ -0,0 +1,104 @@
+# Задачи - ООП, Седмица 6, 28.03.2024
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/rzSTn5pu classroom.github.com/a/rzSTn5pu]
+
+.warn В задачите за файлове имплементирайте всички нужни проверки и затваряния
+
+## Преговорни
+
+### 1 задача - Копиращ конструктор и оператор=
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise01.cpp Решение]
+
+Имплементирайте структура `[WoodenPlank]`, която скрито запазва ширина, дължина и височина на дъската (целочислено), цената ѝ (число с плаваща запетая) и типа дърво (низ с максимум 1024 знака).
+
+Имплементирайте get-ъри, set-ъри, копиращ конструктор, оператор=
+
+### 2 задача - Голяма четворка
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise02.cpp Решение]
+
+Имплементирайте структура `[DynamicString]`, която скрито запазва указател към низ (в динамичната памет) и неговия размер.
+
+Имплементирайте голяма четворка.
+
+## Лесни задачи
+
+### 3 задача
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise03.cpp Решение]
+
+Имплементирайте програма, която отваря файл (създава го, ако вече не е създаден) и вкарва текста "Hello World!" във файла.
+Името на файла се подава от стандартния вход на един ред.
+
+### 4 задача
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise04.cpp Решение]
+
+Имплементирайте програма, която приема име на файл от стандартния вход.
+Изкарайте последния ред от файла.
+
+Редовете са разделени със знака `[\\n]`.
+
+### 5 задача
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise05.cpp Решение]
+
+Имплементирайте програма, която приема име на файл от стандартния вход.
+Изкарайте броя редове и броя думи във файла.
+
+### 6 задача
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise06.cpp Решение]
+
+От стандартния вход получавате, на два отделни реда, две имена на файлове.
+Вмъкнете съдържанието на втория файл по средата на първия файл.
+
+### 7 задача
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise07.cpp Решение]
+
+От стандартния вход получавате числата m и n, както и името на файл (на свой си ред).
+Изкарайте на екрана от m-тата до n-тата буква (включително) от всеки ред във файла.
+Първата буква на един ред е на индекс 1.
+
+### 8 задача
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise08.cpp Решение]
+
+Имплементирайте структура `[FileBuffer]`, която в конструктора си приема име на файл, отваря го и запазва (копира) цялото му съдържание в динамичната памет (с указател член-данна).
+
+.question Кога трябва да затворим файла?
+
+Имплементирайте голяма четворка.
+
+### 9 задача
+
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise09.cpp Решение]
+
+Имплементирайте структура `[Person]`, която приема име на човек (низ с максимална дължина от 1024 знака) и неговата възраст (целочислена стойност).
+Имплементирайте методи `[Save]` и `[Load]`, които съответно запазват/прочитат данните в (двоичен) файл с подадено име.
+
+## Трудни задачи
+
+### 10 задача
+
+Имплементирайте структура `[Table]`, която запазва произволен брой колони и редове с низови стойности.
+Броя редове/колони може да се уразмерява по време на изпълнение.
+Имплементирайте голяма четворка.
+
+Имплементирайте методи `[AddRow]` и `[AddColumn]`, които вмъкват подадените стойности като нов ред/колона на дадения индекс.
+Аналогично имплементирайте методи `[RemoveRow]` и `[RemoveColumn]`.
+=[Чрез всички тези]= имплементирайте метода `[ModifyValue]`, който променя стойността на клетката на дадените индекси.
+
+Имплементирайте методи `[Save]` и `[Load]`, които запазват/зреждат таблицата в/от файл с подадено име, в текстовия CSV формат (всеки ред в таблицата е ред във файла, всички стойности в реда от таблицата са разделени със запетая в реда във файла).
+
+### 11 задача
+
+Имплементирайте структура `[City]`, която запазва името на даден град (низ с максимална дължина от 1024 знака) и масив от указатели към други градове, които са негови съседи.
+Имплементирайте методи `[AddNeighbour]` и `[RemoveNeighbour]` (броя съседи може да се променя), както и голяма четворка.
+
+Имплементирайте методи `[Save]` и `[Load]`, които запазват/зреждат всичките достижими градове от сегашния в/от (бинарен) файл с подадено име.
+Подсказвам, че не можете да запазите указателите ей-така.
diff --git a/src/teaching/oop-2023/week6/index.md b/src/teaching/oop-2023/week6/index.md
deleted file mode 100644
index c5bd777..0000000
--- a/src/teaching/oop-2023/week6/index.md
+++ /dev/null
@@ -1,102 +0,0 @@
-# Задачи - ООП, Седмица 6, 28.03.2024
-
-GitHub classroom: [classroom.github.com/a/rzSTn5pu](https://classroom.github.com/a/rzSTn5pu)
-
-&:warn В задачите за файлове имплементирайте всички нужни проверки и затваряния
-
-## Преговорни
-
-### 1 задача - Копиращ конструктор и оператор=
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise01.cpp)
-
-Имплементирайте структура `WoodenPlank`, която скрито запазва ширина, дължина и височина на дъската (целочислено), цената ѝ (число с плаваща запетая) и типа дърво (низ с максимум 1024 знака).
-
-Имплементирайте get-ъри, set-ъри, копиращ конструктор, оператор=
-
-### 2 задача - Голяма четворка
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise02.cpp)
-
-Имплементирайте структура `DynamicString`, която скрито запазва указател към низ (в динамичната памет) и неговия размер.
-
-Имплементирайте голяма четворка.
-
-## Лесни задачи
-
-### 3 задача
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise03.cpp)
-
-Имплементирайте програма, която отваря файл (създава го, ако вече не е създаден) и вкарва текста "Hello World!" във файла.
-Името на файла се подава от стандартния вход на един ред.
-
-### 4 задача
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise04.cpp)
-
-Имплементирайте програма, която приема име на файл от стандартния вход.
-Изкарайте последния ред от файла.
-
-Редовете са разделени със знака `\n`.
-
-### 5 задача
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise05.cpp)
-
-Имплементирайте програма, която приема име на файл от стандартния вход.
-Изкарайте броя редове и броя думи във файла.
-
-### 6 задача
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise06.cpp)
-
-От стандартния вход получавате, на два отделни реда, две имена на файлове.
-Вмъкнете съдържанието на втория файл по средата на първия файл.
-
-### 7 задача
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise07.cpp)
-
-От стандартния вход получавате числата m и n, както и името на файл (на свой си ред).
-Изкарайте на екрана от m-тата до n-тата буква (включително) от всеки ред във файла.
-Първата буква на един ред е на индекс 1.
-
-### 8 задача
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise08.cpp)
-
-Имплементирайте структура `FileBuffer`, която в конструктора си приема име на файл, отваря го и запазва (копира) цялото му съдържание в динамичната памет (с указател член-данна).
-
-&:question Кога трябва да затворим файла?
-
-Имплементирайте голяма четворка.
-
-### 9 задача
-
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week06/Exercise09.cpp)
-
-Имплементирайте структура `Person`, която приема име на човек (низ с максимална дължина от 1024 знака) и неговата възраст (целочислена стойност).
-Имплементирайте методи `Save` и `Load`, които съответно запазват/прочитат данните в (двоичен) файл с подадено име.
-
-## Трудни задачи
-
-### 10 задача
-
-Имплементирайте структура `Table`, която запазва произволен брой колони и редове с низови стойности.
-Броя редове/колони може да се уразмерява по време на изпълнение.
-Имплементирайте голяма четворка.
-
-Имплементирайте методи `AddRow` и `AddColumn`, които вмъкват подадените стойности като нов ред/колона на дадения индекс.
-Аналогично имплементирайте методи `RemoveRow` и `RemoveColumn`.
-**Чрез всички тези** имплементирайте метода `ModifyValue`, който променя стойността на клетката на дадените индекси.
-
-Имплементирайте методи `Save` и `Load`, които запазват/зреждат таблицата в/от файл с подадено име, в текстовия CSV формат (всеки ред в таблицата е ред във файла, всички стойности в реда от таблицата са разделени със запетая в реда във файла).
-
-### 11 задача
-
-Имплементирайте структура `City`, която запазва името на даден град (низ с максимална дължина от 1024 знака) и масив от указатели към други градове, които са негови съседи.
-Имплементирайте методи `AddNeighbour` и `RemoveNeighbour` (броя съседи може да се променя), както и голяма четворка.
-
-Имплементирайте методи `Save` и `Load`, които запазват/зреждат всичките достижими градове от сегашния в/от (бинарен) файл с подадено име.
-Подсказвам, че не можете да запазите указателите ей-така.
diff --git a/src/teaching/oop-2023/week7/index.md b/src/teaching/oop-2023/week7/index.du
index 0eb3899..04800db 100644
--- a/src/teaching/oop-2023/week7/index.md
+++ b/src/teaching/oop-2023/week7/index.du
@@ -1,21 +1,23 @@
# Задачи - ООП, Седмица 7, 04.04.2024
-GitHub classroom: [classroom.github.com/a/vvZENbkX](https://classroom.github.com/a/vvZENbkX)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/vvZENbkX classroom.github.com/a/vvZENbkX]
## Преговорни
### Задача 1 - Голяма петица
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise1.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise1.cpp Решение]
Една съставка е композирана от низ (с максимална дължина от 511 знака) определящ името ѝ и грамаж (число с плаваща запетая).
-Създайте клас `Recipe`, към който могат да се прибавят и премахват произволен брой съставки.
+Създайте клас `[Recipe]`, към който могат да се прибавят и премахват произволен брой съставки.
Имплементирайте голяма петица (голяма четворка плюс move семантики) за него.
### Задача 2 - Работа с файлове
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise2.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise2.cpp Решение]
От един ред на входа получавате името на текстови файл.
Изкарайте на екрана средната една трета от файла, като буквите са в обратен ред.
@@ -24,25 +26,25 @@ GitHub classroom: [classroom.github.com/a/vvZENbkX](https://classroom.github.com
### Задача 3
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise3.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise3.cpp Решение]
-Имплементирайте клас `Thermometer`, който запазва максималната и минималната възможна температура за измерване, както и сегашната температура, всичките които са цели неотрицателни числа.
+Имплементирайте клас `[Thermometer]`, който запазва максималната и минималната възможна температура за измерване, както и сегашната температура, всичките които са цели неотрицателни числа.
-Имплементирайте методи `SaveText` и `LoadText`, които съответно записват и четат (тоест член-данните стават равни на тези от файла) данните си в/от **текстови** файл с подадено име.
-Аналогично имплементирайте `SaveBinary` и `LoadBinary`, които работят с **двоични** файлове.
+Имплементирайте методи `[SaveText]` и `[LoadText]`, които съответно записват и четат (тоест член-данните стават равни на тези от файла) данните си в/от =[текстови]= файл с подадено име.
+Аналогично имплементирайте `[SaveBinary]` и `[LoadBinary]`, които работят с =[двоични]= файлове.
### Задача 4
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise4.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise4.cpp Решение]
-Имплементирайте клас `Street`, който запазва скрито името на улицата като низ с произволна дължина и номер като цяло число.
+Имплементирайте клас `[Street]`, който запазва скрито името на улицата като низ с произволна дължина и номер като цяло число.
Имплементирайте голяма петица.
-Имплементирайте методите `SaveText`, `LoadText`, `SaveBinary`, `LoadBinary`.
+Имплементирайте методите `[SaveText]`, `[LoadText]`, `[SaveBinary]`, `[LoadBinary]`.
### Задача 5
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise5.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise5.cpp Решение]
За един транспортен билет е нужно скрито да пазим началната и крайната дестинация като динамично-заделени низове с произволна дължина, неговата цена като число с плаваща запетая и идентификационен номер като цяло неотрицателно число.
@@ -50,17 +52,17 @@ GitHub classroom: [classroom.github.com/a/vvZENbkX](https://classroom.github.com
### Задача 6
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise6.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week07/Exercise6.cpp Решение]
-Имплементирайте клас `Matrix`, който запазва стойностите на матрица 2 на 2.
+Имплементирайте клас `[Matrix]`, който запазва стойностите на матрица 2 на 2.
Предефинирайте операторите за инкрементиране, декрементиране, събиране, изваждане, умножение и вход/изход от/към поток.
Имплементирайте четирите функции за записване и четене от файлове.
### Задача 7
-Имплементирайте клас `Paragraph`, който съдържа текст с много редове в него.
-Текстът се запазва като низ с произволна дължина, а редовете се разделят със знака `'\n'`.
+Имплементирайте клас `[Paragraph]`, който съдържа текст с много редове в него.
+Текстът се запазва като низ с произволна дължина, а редовете се разделят със знака `['\\n']`.
Имплементирайте голяма петица.
Имплементирайте четирите функции за записване и четене от файлове.
@@ -71,7 +73,7 @@ GitHub classroom: [classroom.github.com/a/vvZENbkX](https://classroom.github.com
### Задача 8
-Имплементирайте клас `MatrixNМ`, който запазва стойностите на матрица с N реда и M колони (подадени на конструктор).
+Имплементирайте клас `[MatrixNМ]`, който запазва стойностите на матрица с N реда и M колони (подадени на конструктор).
Имплементирайте голяма петица.
Имплементирайте четирите функции за записване и четене от файлове.
diff --git a/src/teaching/oop-2023/week8/index.md b/src/teaching/oop-2023/week8/index.du
index be78f9f..6d48934 100644
--- a/src/teaching/oop-2023/week8/index.md
+++ b/src/teaching/oop-2023/week8/index.du
@@ -1,46 +1,48 @@
# Задачи - ООП, Седмица 8, 11.04.2024
-GitHub classroom: [classroom.github.com/a/7d0MBjcK](https://classroom.github.com/a/7d0MBjcK)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/7d0MBjcK classroom.github.com/a/7d0MBjcK]
## Преговорни
### Задача 1 - Голяма петица
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise1.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise1.cpp Решение]
-Имплементирайте клас `StreetList`, който запазва имената на улици (низове с произволна дължина) в динамичен масив.
+Имплементирайте клас `[StreetList]`, който запазва имената на улици (низове с произволна дължина) в динамичен масив.
Може да се добавят нови имена в края на списъка, като съответния (вътрешен) масив трябва да се уголеми.
Имплементирайте голяма петица за класа.
### Задача 2 - Файлове и класове
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise2.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise2.cpp Решение]
-Имплементирайте клас `Person`, който запазва трите имена (низове с произволна дължина) и идентификационния номер (цяло неотрицателно число) на човек.
+Имплементирайте клас `[Person]`, който запазва трите имена (низове с произволна дължина) и идентификационния номер (цяло неотрицателно число) на човек.
Имплементирайте голяма петица.
-Имплементирайте методи `SaveText` и `LoadText`, които съответно записват и четат (тоест член-данните стават равни на тези от файла) данните си в/от **текстови** файл с подадено име.
-Аналогично имплементирайте `SaveBinary` и `LoadBinary`, които работят с **двоични** файлове.
+Имплементирайте методи `[SaveText]` и `[LoadText]`, които съответно записват и четат (тоест член-данните стават равни на тези от файла) данните си в/от =[текстови]= файл с подадено име.
+Аналогично имплементирайте `[SaveBinary]` и `[LoadBinary]`, които работят с =[двоични]= файлове.
## Лесни
### Задача 3
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise3.hpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise3.hpp Решение]
-Имплементирайте шаблонната структура `Pair`, която приема два типа и запазва по една стойност от всеки тип.
+Имплементирайте шаблонната структура `[Pair]`, която приема два типа и запазва по една стойност от всеки тип.
### Задача 4
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise4.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise4.cpp Решение]
-Имплементирайте клас `FloatArray`, който съдържа списък с числа с плаваща запетая.
+Имплементирайте клас `[FloatArray]`, който съдържа списък с числа с плаваща запетая.
Може да добавяте нови числа в края на този списък.
Имплементирйате голяма петица.
Имплементирайте оператори:
-
+.bulleted
- += и +, които конкатенират два FloatArray-я. += вмъква елементите от десния масив в края на левия, + връща нов масив в който първо са елементите от левия масив и след тях са тези от десния.
- += и +, които приемат FloatArray и число (с плаваща запетая) и го прибавят към всеки елемент на FloatArray-я
- [], които връщат референция към елементът на подадения индекс. При невалиден хвърлят грешка.
@@ -51,16 +53,16 @@ GitHub classroom: [classroom.github.com/a/7d0MBjcK](https://classroom.github.com
### Задача 5
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise5.hpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise5.hpp Решение]
-Имплементирайте класът и неговите оператори от предходната задача като темплейтен (шаблонен) клас с име `DynamicArray`.
+Имплементирайте класът и неговите оператори от предходната задача като темплейтен (шаблонен) клас с име `[DynamicArray]`.
Очевидно шаблонния тип определя типа на списъка с елементи.
### Задача 6
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise6.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise6.cpp Решение]
-Имплементирайте клас `NumberInput`, който запазва целочислена стойност.
+Имплементирайте клас `[NumberInput]`, който запазва целочислена стойност.
В конструктора се подава минимална и максимална възможна стойност, след това (все още в конструктора) се изкарва на екрана съответно съобщение и се приема потребителски вход.
Ако той не е валиден или е извън подадения обхват, трябва да хвърлите грешка.
@@ -70,26 +72,26 @@ GitHub classroom: [classroom.github.com/a/7d0MBjcK](https://classroom.github.com
### Задача 7
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise7.cpp)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week08/Exercise7.cpp Решение]
-Имплементирайте клас `UserError`, чиято употреба е да се хвърля като грешка.
+Имплементирайте клас `[UserError]`, чиято употреба е да се хвърля като грешка.
За тази цел нека да запазва два низа, които се приемат в конструктора: името на клас и името на член-данната.
Имплементирайте голяма петица и оператор<<, който изкарва съобщение с информация за класа и член-данната в подадения поток.
-Следете бройката на създадени `UserError` инстанции в самия клас (статична променлива) и имплементирате нужната (статична) член-функция, която връща този брой.
+Следете бройката на създадени `[UserError]` инстанции в самия клас (статична променлива) и имплементирате нужната (статична) член-функция, която връща този брой.
Преобразувайте последната задача, така че да хвърля грешка от този клас.
-В края на програмата изкарайте колко грешки са се хвърлили **използвайки статичните членове на UserError**.
+В края на програмата изкарайте колко грешки са се хвърлили =[използвайки статичните членове на UserError]=.
## Трудни задачи
### Задача 8
-Имплементирайте шаблонен клас `UserInput`, който запазва стойност от подадения тип.
+Имплементирайте шаблонен клас `[UserInput]`, който запазва стойност от подадения тип.
Ако типа е указател, тогава заделяте динамична памет за един такъв елемент.
-За проверка на типа използвайте [partial template specialization](https://en.cppreference.com/w/cpp/language/partial_specialization).
+За проверка на типа използвайте [url https://en.cppreference.com/w/cpp/language/partial_specialization partial template specialization].
-В шаблона (`template <...>`) се приема указател към валидираща функция, която приема стойността от съответния тип и връща булева стойност.
+В шаблона (`[template <...>]`) се приема указател към валидираща функция, която приема стойността от съответния тип и връща булева стойност.
В конструктора се приема от входа нужната стойност и ако стойността е неуспешно приета или валидиращата функция върне false, тогава хвърляте грешка.
Ако типа е указател, не забравяйте да освободите паметта.
@@ -97,35 +99,39 @@ GitHub classroom: [classroom.github.com/a/7d0MBjcK](https://classroom.github.com
### Задача 9
-&:important В тази задача се изикват помощни класове, прочетете цялото условие преди имплементиране!
+.important В тази задача се изикват помощни класове, прочетете цялото условие преди имплементиране!
-Имплементирайте шаблонен клас `Dictionary`, който запазва два динамично-заделени масива: първия е със стойност от подадения тип, втория е с низове.
+Имплементирайте шаблонен клас `[Dictionary]`, който запазва два динамично-заделени масива: първия е със стойност от подадения тип, втория е с низове.
Низовете ще се използват за индексиране, вместо числа.
Разбира се, очаквайте да може да се уразмерява.
Имплементирайте голяма петица.
Имплементирайте оператор:
-- <<=, който вмъква всички стойности от десния `Dictionary` в левия
+:bulleted
+- <<=, който вмъква всички стойности от десния `[Dictionary]` в левия
- [], който приема низ и връща референция "към" стойността.
Ако няма записана стойност на съответния индекс, тогава връщате референция в която може да се запише стойност.
- [], който приема число, което се конвертира до низ и работи както предходния оператор
- [], който приема низове (или числа), разделени със запетая и връща "масив" само с тези стойности
-- delete, който приема стойност, върната от оператор[] и "премахва" съответната стойност от `Dictionary`
+- delete, който приема стойност, върната от оператор[] и "премахва" съответната стойност от `[Dictionary]`
- префиксен++, префиксен+ и префиксен-, които ще се използват за итериране.
+ .bulleted
- ++ връща инкрементира индекса на сегашната стойност.
Ако индекса е равен на броя запазени стойности, тогава става нула.
По подразбиране индекса е броя.
Връща true ако след инкрементиране индекса не е броя.
- + връща референция към стойността на сегашния индекс
- - връща сегашния (низов) индекс
-- ->, такъв че можем да правим `a->(&func1)->(&func2)` и `a->[&func3]->[&func4]`.
- Върху всяка двойка индекс-стойност се прилагат &func1 и &func2 (приемат индекс и стойност като параметри), които връщат нова стойност, заместваща сегашната.
+
+- ->, такъв че можем да правим `[a->(&func1)->(&func2)]` и `[a->[&func3]->[&func4]]`.\n
+ Върху всяка двойка индекс-стойност се прилагат &func1 и &func2 (приемат индекс и стойност като параметри), които връщат нова стойност, заместваща сегашната.\n
&func3, &func4 аналогично приемат индекс и стойност, но връщат нов индекс.
+
В края на задачата трябва да можете да правите:
-```cpp
+:code_c++
int doubleUp(const char* index, int value) {
return value * 2;
}
@@ -164,4 +170,3 @@ int main() {
*/
}
}
-```
diff --git a/src/teaching/oop-2023/week9/index.md b/src/teaching/oop-2023/week9/index.du
index 50cea93..56ac747 100644
--- a/src/teaching/oop-2023/week9/index.md
+++ b/src/teaching/oop-2023/week9/index.du
@@ -1,38 +1,40 @@
# Задачи - ООП, Седмица 9, 18.04.2024
-На днешното упражнение ще решаваме [задачата от Контролно 1](https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=311448), затова задачите ще са в същия дух (макар и да не включват най-новия материал).
+\n
-Решението, което писахме по време на практикума, с някои разширения и коментари, може да намерите [тук](https://github.com/Syndamia/oop-2023-solutions/tree/main/week09/Exam1).
+На днешното упражнение ще решаваме [url https://learn.fmi.uni-sofia.bg/mod/resource/view.php?id=311448 задачата от Контролно 1], затова задачите ще са в същия дух (макар и да не включват най-новия материал).
-GitHub classroom: [classroom.github.com/a/wlL1oUg2](https://classroom.github.com/a/wlL1oUg2)
+Решението, което писахме по време на практикума, с някои разширения и коментари, може да намерите [url https://github.com/Syndamia/oop-2023-solutions/tree/main/week09/Exam1 тук].
+
+GitHub classroom: [url https://classroom.github.com/a/wlL1oUg2 classroom.github.com/a/wlL1oUg2]
## Преговорни
### Задача 1 - Голяма петица
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week09/Exercise1)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week09/Exercise1 Решение]
Реализирайте клас Printer, който съдържа модел като низ с произволна дължина и брой принтирани страници като неотрицателно цяло число.
Имплементирайте голяма петица.
### Задача 2 - Файлове и класове
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week09/Exercise2)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week09/Exercise2 Решение]
Реализирайте клас Date, който съдържа номера на деня, месеца и годината в три отделни целочислени член-данни.
-Имплементирайте член-методи `storeText`, `storeBinary`, които съответно запазват данните в текстов файл (във формата "YEAR MONTH DAY") и в двоичен файл с подадени имена.
-Аналогично имплементирайте `loadText` и `loadBinary`, които презаписват член-данните с тези от подадените (имена на) файлове.
+Имплементирайте член-методи `[storeText]`, `[storeBinary]`, които съответно запазват данните в текстов файл (във формата "YEAR MONTH DAY") и в двоичен файл с подадени имена.
+Аналогично имплементирайте `[loadText]` и `[loadBinary]`, които презаписват член-данните с тези от подадените (имена на) файлове.
-В главната функция създайте 5 дати, запазете всяка в **един и същ текстов файл**, след това прочетете датите в **нови** 5 променливи и изкарайте датите в обратен ред.
+В главната функция създайте 5 дати, запазете всяка в =[един и същ текстов файл]=, след това прочетете датите в =[нови]= 5 променливи и изкарайте датите в обратен ред.
## Лесни
### Задача 3
-&::solution-link [Решение](https://github.com/Syndamia/oop-2023-solutions/blob/main/week09/Exercise3)
+.solution-link [url https://github.com/Syndamia/oop-2023-solutions/blob/main/week09/Exercise3 Решение]
Реализирайте клас Train, който съдържа:
-
+.bulleted
- модел като низ с максимална дължина от 127 знака
- идентификационен номер на релсовата линия върху която се намира, като целочислена неотрицателна стойност
- име на текстов файл, съдържащ всички райони от сегашната релсова линия, всеки на нов ред.
@@ -41,72 +43,72 @@ GitHub classroom: [classroom.github.com/a/wlL1oUg2](https://classroom.github.com
Тази локация не се подава, и при създаване на обекта винаги е първата във файла.
Имплементирайте методите:
-
+.bulleted
- от голямата петица
-- `TransferNextRegion`, който променя сегашната локация на следващата по ред в текстовия файл (чието име е подадено в конструктор).
+- `[TransferNextRegion]`, който променя сегашната локация на следващата по ред в текстовия файл (чието име е подадено в конструктор).
Ако няма следващо по ред, тогава локацията да си остане същата и да се хвърли грешка.
Ако се срещнат проблеми с файла, хвърлете грешка.
-- `SwitchRailLine`, който приема идентификационен номер на релсовата линия и име на текстов файл, и променя вътрешните стойности.
+- `[SwitchRailLine]`, който приема идентификационен номер на релсовата линия и име на текстов файл, и променя вътрешните стойности.
Съответно локацията трябва да бъде първата в подадения файл.
Ако се срещнат проблеми с файла, хвърлете грешка.
Реализирайте клас TrainNetwork, който съдържа:
-
+.bulleted
- идентификационен код, като низ с максимална дължина от 7 знака
- масив, запазващ максимум 511 влака (типа се оставя по ваша преценка)
За този клас имплементирайте методите:
-
-- `HaveCollided`, който приема индекс на два влака и връща дали са се блъснали.
+.bulleted
+- `[HaveCollided]`, който приема индекс на два влака и връща дали са се блъснали.
Това се случва ако в една и съща релсова линия и един и същи регион, когато регионът не е последния възможен.
-- `RunTrains`, който придвижва напред всички влакове, докато не стигнат финалната си възможна дестинация.
+- `[RunTrains]`, който придвижва напред всички влакове, докато не стигнат финалната си възможна дестинация.
Влакове които са се ударили не се придвижват напред.
Връщате броя ударили се влакове.
Да се имплементира главна функция, в която приемате име на двоичен файл от потребителя.
В този файл имате някакъв брой редици с идентификационен номер на релсова линия, брой локации върху съответната линия и всички локации като нормални низове, разделени с нови редове.
-Допълнително в главната функция приемайте от потребителя влаковете, като имената на текстовите файлове се избират от програмата (**НЕ** от потребителя) според идентификационния номер на релсовата линия и информацията във файла с редиците.
-**Не може да променяте Train класа!**
+Допълнително в главната функция приемайте от потребителя влаковете, като имената на текстовите файлове се избират от програмата (=[НЕ]= от потребителя) според идентификационния номер на релсовата линия и информацията във файла с редиците.
+=[Не може да променяте Train класа!]=
-Последно в главната функция създайте обект от тип TrainNetwork и изкарайте резултата от `RunTrains` на екрана.
+Последно в главната функция създайте обект от тип TrainNetwork и изкарайте резултата от `[RunTrains]` на екрана.
## Трудни
### Задача 4
Реализирайте клас Car, в който се запазват:
-
+.bulleted
- марка като низ с максимум 31 знака
- модел като низ с произволна дължина
- брой седалки като положително цяло число
- гладност на човека на всяка седлка като целочислен масив с размер броя седалки
Имплементирайте методи:
-
+.bulleted
- от голямата петица
-- `AddPassenger`, който добавя нов човек на дадения индекс на седалка
-- `RemovePassenger`, който премахва човека от дадения индекс
-- `TotalHunger`, който връща общото количество гладност в колата
-- `StoreData`, който запазва всички данни от колата в **двоичен** файл с подадено име
-- `LoadData`, който презаписва всички данни с тези от подадения по име **двоичен** файл
+- `[AddPassenger]`, който добавя нов човек на дадения индекс на седалка
+- `[RemovePassenger]`, който премахва човека от дадения индекс
+- `[TotalHunger]`, който връща общото количество гладност в колата
+- `[StoreData]`, който запазва всички данни от колата в =[двоичен]= файл с подадено име
+- `[LoadData]`, който презаписва всички данни с тези от подадения по име =[двоичен]= файл
Реализирайте клас DriveThrough, в който се запазват:
-
+.bulleted
- име на ресторант, към който е свързано съответния проход, като низ с произволна дължина
- коли на опашка, като масив с коли с произволна дължина
Имплементирайте методи:
-
+.bulleted
- от голяма петица
-- `QueueUp`, който приема кола и я вкарва в края на опашката.
+- `[QueueUp]`, който приема кола и я вкарва в края на опашката.
Разбира се, масивът се уголемява ако е нужно.
-- `Serve`, който изпълнява поръчката на най-предната кола в опашката.
- За единица глад, ресторанта може да сготви достатъчно храна (за да нахрани клиента с "единица" храна) за единици време между половината от дължината на името на ресторанта и три пъти дължината на името на ресторанта време.
+- `[Serve]`, който изпълнява поръчката на най-предната кола в опашката.
+ За единица глад, ресторанта може да сготви достатъчно храна (за да нахрани клиента с "единица" храна) за единици време между половината от дължината на името на ресторанта и три пъти дължината на името на ресторанта време.\n
Максималното възможно количество време за изпълнение на поръчката варира и според броя коли в опашка: ако са под 6 на брой, тогава тогава се увеличава с 10%, а ако са над 10 тогава се намалява с по 5% за всяка кола след десетата.
-- `EfficiencyService`, който изпълнява поръчките на всички коли в опашката и връща средно колко време е отнело на поръчка.
-- `StoreData`, който запазва всички данни в **текстов** файл с подадено име
-- `LoadData`, който презаписва всички данни с тези от подадения по име **текстов** файл
+- `[EfficiencyService]`, който изпълнява поръчките на всички коли в опашката и връща средно колко време е отнело на поръчка.
+- `[StoreData]`, който запазва всички данни в =[текстов]= файл с подадено име
+- `[LoadData]`, който презаписва всички данни с тези от подадения по име =[текстов]= файл
Имплементирайте главна функция, в която от потребителския вход приемате име на текстов файл.
-Създайте обект от тип DriveThrough, който да запълни своите стойности с тези от подадения файл и изкарайте на екрана стойността от `EfficiencyService`.
+Създайте обект от тип DriveThrough, който да запълни своите стойности с тези от подадения файл и изкарайте на екрана стойността от `[EfficiencyService]`.
diff --git a/src/teaching/upp-2023/additional1/index.md b/src/teaching/upp-2023/additional1/index.du
index f366858..3cb8140 100644
--- a/src/teaching/upp-2023/additional1/index.md
+++ b/src/teaching/upp-2023/additional1/index.du
@@ -1,24 +1,26 @@
# Допълнително упражнение 1 - УПП, 04.11.2023
-GitHub classroom: [classroom.github.com/a/nlFuKALw](https://classroom.github.com/a/nlFuKALw)
+\n
-При изображението ![](/img/dialog-question.png) трябва да спрете, да помислите и да си отговорите на дадения въпрос.
+GitHub classroom: [url https://classroom.github.com/a/nlFuKALw classroom.github.com/a/nlFuKALw]
+
+При изображението [image /img/dialog-question.png трябва да спрете, да помислите и да си отговорите на дадения въпрос.
Почти винаги ако не може да отговорите, ще имате проблеми в бъдеще с решаването.
Понякога ще ви спираме и ще ви питаме за тези въпроси.
## Задача - База гаднни
-&:warn **Нямате** право да използвате каквито и да е функции, които вие не сте написали, както и неизучаван материал като двуизмерни масиви или динамична памет.
-**Не** употребявайте търсачки, ако ви трябва информация за нещо, ще може да си я изкарате с една проста тестова програма или калкулатор.
+.warn =[Нямате]= право да използвате каквито и да е функции, които вие не сте написали, както и неизучаван материал като двуизмерни масиви или динамична памет.
+=[Не]= употребявайте търсачки, ако ви трябва информация за нещо, ще може да си я изкарате с една проста тестова програма или калкулатор.
-<br>
+\n
Ще работим върху нещо като база данни, може да си го представете като един файл на Excel.
Имаме две таблици, за удобство първата ще я наричаме "Таблица А", а втората "Таблица Б".
Таблица А има максимум 8 реда, като всеки ред е едно цяло число с 9 цифри.
Таблица Б има максимум 8 реда, като всеки ред е число между 1 и 4294967295.
-&:question В какъв тип ще запазим всяка таблица?
+.question В какъв тип ще запазим всяка таблица?
В задачата винаги номерираме редовете (числата) на всяка таблица, започвайки от индекс 1.
Чрез различни комбинации на ред в таблица А и ред в таблица Б получаваме различни стойности.
@@ -39,142 +41,142 @@ GitHub classroom: [classroom.github.com/a/nlFuKALw](https://classroom.github.com
Стойностите от таблица А са винаги ограничени отгоре с най-големия брой битове, които комфортно може да поберем в 7 цифри.
Тоест 9999999 не е валидна стойност от таблица А, докато 8388608 e.
-&:question Колко най-много *битове* можем със сигурност да поберем в 7 цифри?
+.question Колко най-много *[битове]* можем със сигурност да поберем в 7 цифри?
Понеже редовете са от 1 до 9, ако в таблица А имаме ред 0 правим нещо специално, но това ще видите в бъдеще.
-&:question Разбрахте ли как таблиците "изглеждат"?
+.question Разбрахте ли как таблиците "изглеждат"?
### a) разделяне на реда от таблица А
Преди да започнем, трябва да имплементираме функция, която разделя дадения ред от таблица А на трите му компонента (ред, тип и стойност):
-`getRow` - приема ред от таблица А и указатели към променливи за ред, тип и стойност; не връща нищо
+`[getRow]` - приема ред от таблица А и указатели към променливи за ред, тип и стойност; не връща нищо\n
В подадените указатели пази съответните стойности от реда
-&:question Защо приемаме указатели към променливи? Каква е "сигнатурата" на функцията?
+.question Защо приемаме указатели към променливи? Каква е "сигнатурата" на функцията?
-<br>
-**Примери:**
+\n
+=[Примери:]=
-|Извикване|Резултат|
-|---------|--------|
-|getRow(1234567, &row, &type, &value)|row = 0, type = 0, value = 1234567|
-|getRow(12345678, &row, &type, &value)|row = 0, type = 1, value = 2345678|
-|getRow(123456789, &row, &type, &value)|row = 1, type = 2, value = 3456789|
+.table
+|=Извикване=||=Резултат=|
+|:getRow(1234567, &row, &type, &value):||:row = 0, type = 0, value = 1234567:|
+|:getRow(12345678, &row, &type, &value):||:row = 0, type = 1, value = 2345678:|
+|:getRow(123456789, &row, &type, &value):||:row = 1, type = 2, value = 3456789:|
### б) обикновенно число
Ако типа е цифрата "0", тогава стойността в базата данни е някакво число с плаваща запетая.
Самото число е разделено на две части: цифрите преди запетаята се намират в стойността от таблица А, докато цифрите след запетаята са в реда от таблица Б.
-&:question В какъв тип данни трябва да запазим числото? Как ще "слепим" двете му части.
+.question В какъв тип данни трябва да запазим числото? Как ще "слепим" двете му части.
Имплементирайте функция:
-`parseNumber` - приема стойност от таблица А и ред от таблица Б; връща полученото число от тези стойности
+`[parseNumber]` - приема стойност от таблица А и ред от таблица Б; връща полученото число от тези стойности
-<br>
-**Примери:**
-*Възможно е отклонението на последния пример да бъде повече от 2 единици*
+\n
+=[Примери:]=
+*[Възможно е отклонението на последния пример да бъде повече от 2 единици]*
-|Извикване|Резултат|
-|---------|--------|
-|a = parseNumber(1, 5)|a = 1.5|
-|a = parseNumber(0, 37)|a = 0.37|
-|a = parseNumber(913, 0)|a = 913.0|
-|a = parseNumber(8388607, 18446744073709551615)|a = 8388607.18446744073709551615|
+.table
+|=Извикване=||=Резултат=|
+|:a = parseNumber(1, 5):||:a = 1.5:|
+|:a = parseNumber(0, 37):||:a = 0.37:|
+|:a = parseNumber(913, 0):||:a = 913.0:|
+|:a = parseNumber(8388607, 18446744073709551615):||:a = 8388607.18446744073709551615:|
### в) числов текст (част едно)
Ако типа е "1", тогава стойността в базата данни е някакъв низ (последователност от букви), която е кодирана в числата.
Всеки 5 бита в реда (от дясно на ляво) от таблица Б определя буква, като:
-|Битове|Десетично число|Буква|
-|------|---------------|-----|
-|00000 |0 |A |
-|00001 |1 |B |
-|00010 |2 |C |
-|...|||
-|11001 |25 |Z |
-|11010 |26 |*шпация*|
-|11011 |27 |. |
-|11100 |28 |, |
-|11101 |29 |: |
-|11110 |30 |? |
-|11111 |31 |! |
+.table
+|:Битове:||:Десетично число:||:Буква:|
+|:00000 :||:0 :||:A :|
+|:00001 :||:1 :||:B :|
+|:00010 :||:2 :||:C :|
+|:... :||: :||: :|
+|:11001 :||:25 :||:Z :|
+|:11010 :||:26 :||:*[шпация]*:|
+|:11011 :||:27 :||:. :|
+|:11100 :||:28 :||:, :|
+|:11101 :||:29 :||:: :|
+|:11110 :||:30 :||:? :|
+|:11111 :||:31 :||:! :|
-Тоест ако в нашия тип данни запазваме само 10 бита, тогава числото "2" ще бъде `0000000010` и имаме низа "AC".
+Тоест ако в нашия тип данни запазваме само 10 бита, тогава числото "2" ще бъде `[0000000010]` и имаме низа "AC".
Игнорирайте старшите битове, които остават като "остатък" (по-малко от 5 бита ширина).
-&:question Колко бита наистина запазваме в нашия тип данни? Колко бита ще трябва да игнорираме? Колко най-много букви може да поберем?
+.question Колко бита наистина запазваме в нашия тип данни? Колко бита ще трябва да игнорираме? Колко най-много букви може да поберем?
Имплементирайте функция:
-`decodeNumberText` - приема ред от таблица Б и указател към "низ"; не връща нищо
+`[decodeNumberText]` - приема ред от таблица Б и указател към "низ"; не връща нищо\n
Записва декодиран текстът от реда в указателя
-&:question Нарочно има кавички около думата "низ", какъв трябва наистина да е типа на указателя?
+.question Нарочно има кавички около думата "низ", какъв трябва наистина да е типа на указателя?
-<br>
-**Примери:**
+\n
+=[Примери:]=
-|Извикване|Резултат|
-|---------|--------|
-|decodeNumberText(2, decodedText)|decodedText = "AAAAAAAAAAAC"|
-|decodeNumberText(257104811188071551, decodedText)|decodedText = "HELLO WORLD!"|
-|decodeNumberText(1148238614786569150, decodedText)|decodedText = "!. ,:?!. ,:?"|
+.table
+|=Извикване=||=Резултат=|
+|:decodeNumberText(2, decodedText):||:decodedText = "AAAAAAAAAAAC":|
+|:decodeNumberText(257104811188071551, decodedText):||:decodedText = "HELLO WORLD!":|
+|:decodeNumberText(1148238614786569150, decodedText):||:decodedText = "!. ,:?!. ,:?":|
### г) числов текст (част две)
Дотук добре, обаче не сме свършили съвсем.
-От гледна точка на сигурност, искаме дори някой да получи достъп до таблица Б, да не може да разбере текста дори след като е използвал `decodeNumberText`.
+От гледна точка на сигурност, искаме дори някой да получи достъп до таблица Б, да не може да разбере текста дори след като е използвал `[decodeNumberText]`.
-Ще използваме [шифъра на Цезар](https://en.wikipedia.org/wiki/Caesar_cipher): един много прост шифър, където отместваме позицията на всяка буква с няколко места "напред".
+Ще използваме [url https://en.wikipedia.org/wiki/Caesar_cipher шифъра на Цезар]: един много прост шифър, където отместваме позицията на всяка буква с няколко места "напред".
Тоест, при отместаване 3, буквата A става D, B става E, и так. нат.
Как декодираме?
Отместваме буквите назад, тоест ако имаме текста "KHOOR" и ви кажа, че съм го кодирал като съм отместил всяка буква напред с 3 позиции, тогава при декодиране от K става на H, от H става на E, от О става на L и от R става на O.
-&:question Какво става със знака "!"? Има ли лесен (математически) начин да дешифрираме всяка буква?
+.question Какво става със знака "!"? Има ли лесен (математически) начин да дешифрираме всяка буква?
Текстът, преди да е въведен в нашата база данни, ще бъде кодиран с шифъра на Цезар, като броя позиции с които сме отместили буквите се намира в стойността в таблица А.
Промененте функцията:
-`decodeNumberText` - приема ред от таблица Б, стойност от таблица А и указател към "низ"; не връща нищо
+`[decodeNumberText]` - приема ред от таблица Б, стойност от таблица А и указател към "низ"; не връща нищо\n
След като декодира текста от реда от Б, дешифрира го със стойността от таблица А
-<br>
-**Примери:**
+\n
+=[Примери:]=
-|Извикване|Резултат|
-|---------|--------|
-|decodeNumberText(0, 2, decodedText)|decodedText = "AAAAAAAAAAAC"|
-|decodeNumberText(0, 257104811188071551, decodedText)|decodedText = "HELLO WORLD!"|
-|decodeNumberText(0, 1148238614786569150, decodedText)|decodedText = "!. ,:?!., :?"|
-|decodeNumberText(17, 632247276719883827, decodedText)|decodedText = "AAAAAAAAAAAC"|
-|decodeNumberText(3, 368677860020992194, decodedText)|decodedText = "HELLO WORLD!"|
-|decodeNumberText(30, 1073856582231288700, decodedText)|decodedText = "!. ,:?!., :?"|
-|decodeNumberText(32, 1148238614786569150, decodedText)|decodedText = "!. ,:?!., :?"|
+.table
+|=Извикване=||=Резултат=|
+|:decodeNumberText(0, 2, decodedText):||:decodedText = "AAAAAAAAAAAC":|
+|:decodeNumberText(0, 257104811188071551, decodedText):||:decodedText = "HELLO WORLD!":|
+|:decodeNumberText(0, 1148238614786569150, decodedText):||:decodedText = "!. ,:?!., :?":|
+|:decodeNumberText(17, 632247276719883827, decodedText):||:decodedText = "AAAAAAAAAAAC":|
+|:decodeNumberText(3, 368677860020992194, decodedText):||:decodedText = "HELLO WORLD!":|
+|:decodeNumberText(30, 1073856582231288700, decodedText):||:decodedText = "!. ,:?!., :?":|
+|:decodeNumberText(32, 1148238614786569150, decodedText):||:decodedText = "!. ,:?!., :?":|
### д) масив (част едно)
Ако типа е "2", тогава в реда от Б сме вложили масив от стойности (числа).
Всеки 4 бита определят една стойност, като първия елемент е старшите (най-левите) битове, докато последния е младшите (най-десните) битове.
-&:question Коколо на брой елемента пазим в реда от Б?
+.question Коколо на брой елемента пазим в реда от Б?
Имплементирайте функцията:
-`decodeArray` - приема ред от таблица Б и указател към масив; не връща нищо
+`[decodeArray]` - приема ред от таблица Б и указател към масив; не връща нищо\n
Декодира елементите от реда и ги запазва в указателя
-<br>
-**Пример:**
+\n
+=[Пример:]=
-|Извикване|Резултат|
-|---------|--------|
-|decodeArray(846406911526255600, arr)|arr = { 0, 11, 11, 15, 0, 10, 9, 10, 0, 0, 15, 5, 3, 11, 15, 0 }|
+.table
+|=Извикване=||=Резултат=|
+|:decodeArray(846406911526255600, arr):||:arr = { 0, 11, 11, 15, 0, 10, 9, 10, 0, 0, 15, 5, 3, 11, 15, 0 }:|
### е) масив (част две)
@@ -183,61 +185,68 @@ GitHub classroom: [classroom.github.com/a/nlFuKALw](https://classroom.github.com
В старшите 20 бита от стойността в таблица А ще пазим общо 5 възможни валидни стойности, а в останалите (младши) 3 бита ще пазим индекс към тези стойности, който индекс (започвайки от 1) определя стойността по подразбиране.
-Пример: ако имаме побитово `1111100000100011101101010101`, тогава:
-
-- валидните числа са `11111, 00000, 10001, 11011 и 01010`
-- числото по подразбиране е 5-тото (`101 = 5`), което е числото `01010`
-- ако от реда в Б изкараме `11011`, тогава го запазваме, обаче ако изкараме примерно `11000` тогава го превръщаме в стойността по подразбиране, а именно `01010`
+Пример: ако имаме побитово `[1111100000100011101101010101]`, тогава:
+.bulleted
+- валидните числа са `[11111, 00000, 10001, 11011 и 01010]`
+- числото по подразбиране е 5-тото (`[101 = 5]`), което е числото `[01010]`
+- ако от реда в Б изкараме `[11011]`, тогава го запазваме, обаче ако изкараме примерно `[11000]` тогава го превръщаме в стойността по подразбиране, а именно `[01010]`
Разширете функцията:
-`decodeArray` - приема стойност от таблица А, ред от таблица Б и указател към масив; не връща нищо
+`[decodeArray]` - приема стойност от таблица А, ред от таблица Б и указател към масив; не връща нищо\n
Декодира елементите от реда, като всички невалидни стойност се превръщат в стойността по подразбиране, и ги запазва в указателя
-<br>
-**Примери:**
+\n
+=[Примери:]=
-|Извикване|Резултат|
-|---------|--------|
-|decodeArray(360537, 846406911526255600, arr)|arr = { 0, 11, 11, 11, 0, 11, 11, 11, 0, 0, 11, 11, 11, 11, 11, 0 }|
-|decodeArray(3119812, 846406911526255600, arr)|arr = { 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 15, 5, 3, 8, 15, 8 }|
+.table
+|=Извикване=||=Резултат=|
+|:decodeArray(360537, 846406911526255600, arr):||:arr = { 0, 11, 11, 11, 0, 11, 11, 11, 0, 0, 11, 11, 11, 11, 11, 0 }:|
+|:decodeArray(3119812, 846406911526255600, arr):||:arr = { 8, 8, 8, 15, 8, 8, 8, 8, 8, 8, 15, 5, 3, 8, 15, 8 }:|
### ж) компресирани стойности
Ако редът в таблица А е 0, тогава цялата стойност в базата данни е побрана в стойността на таблица А.
Очевидно само в стойност на таблица А имаме по-малко битове, отколкото в стойност на таблица А плюс ред в таблица Б, затова се налага по някакъв начин да "компресираме" информацията, така че да се побере.
-&:question Колко бита побираме в стойност на таблица А? Колко бита ни трябват общо, за да обработим една стойност в базата данни?
+.question Колко бита побираме в стойност на таблица А? Колко бита ни трябват общо, за да обработим една стойност в базата данни?
Ще го направим така: в стойността от таблица А ще пазим индекси, и всеки индекс ще съответства на някакво по-голямо число, което се съдържа в друг масив, който ще наричаме криптографски ред.
Пример (всички числа са представени двоично; стойностите не са напълно валидни за базата данни, но са логически коректни):
-<!-- 000 001 010 011 100 101 -->
-- Kриптографски ред е `00000, 10101, 11011, 10001, 01101, 10100`
+.comment 000 001 010 011 100 101
+
+:bulleted
+- Kриптографски ред е `[00000, 10101, 11011, 10001, 01101, 10100]`
+ .bulleted
- Индексираме от 0 до 5, което побитово е от 000 до 101
-- Стойност в таблицата А е `011001000001101101`
- - Разделяйки го на индекси, това са `011, 001, 000, 001, 101, 101`
-- Слепвайки от криптографския ред на тези индекси получаваме `100011010100000101011010010100`
+
+- Стойност в таблицата А е `[011001000001101101]`
+ .bulleted
+ - Разделяйки го на индекси, това са `[011, 001, 000, 001, 101, 101]`
+
+- Слепвайки от криптографския ред на тези индекси получаваме `[100011010100000101011010010100]`
+
Във вашата програма ще се наложи да направите още една променлива, в която пазите криптографския ред.
Всяка стойност в реда ще съдържа 21 бита.
Първите (най-левите) три бита от стойността в таблица А не са индекси, а трябва да се копират дословно.
След тях има 4 индекса, всеки с по 5 бита.
-&:question Как е разделена побитово една стойност от таблица А? Кои индекси за кои стойности ще се ползват? Достатъчно ли е всеки индекс към криптографския ред да бъде само 5 бита (тоест може ли да има повече от 2&#8309; числа в реда)? Защо имаме само 4 индекса?
+.question Как е разделена побитово една стойност от таблица А? Кои индекси за кои стойности ще се ползват? Достатъчно ли е всеки индекс към криптографския ред да бъде само 5 бита (тоест може ли да има повече от 2&#8309; числа в реда)? Защо имаме само 4 индекса?
Напишете функция:
-`decompress` - приема стойност от таблица А, криптографски ред, указател за запазване на декомпресираната стойност от таблица А и указател за запазване на декомпресирания ред от таблица Б; не връща нищо
+`[decompress]` - приема стойност от таблица А, криптографски ред, указател за запазване на декомпресираната стойност от таблица А и указател за запазване на декомпресирания ред от таблица Б; не връща нищо
-<br>
-**Примери:**
+\n
+=[Примери:]=
-|Извикване|Резултат|
-|---------|--------|
-|crypt = { 0, 2, 5 }<br>decompress(32770, crypt, &decompA, &decompB)|decompA = 1, decompB = 5|
-|crypt = { 2097151 }<br>decompress(7340032, crypt, &decompA, &decompB)|decompA = 8388607, decompB = 18446744073709551615|
+.table
+|=Извикване=||=Резултат=|
+|:crypt = { 0, 2, 5 }\ndecompress(32770, crypt, &decompA, &decompB):||:decompA = 1, decompB = 5:|
+|:crypt = { 2097151 }\ndecompress(7340032, crypt, &decompA, &decompB):||:decompA = 8388607, decompB = 18446744073709551615:|
### з) входни данни
@@ -248,22 +257,24 @@ GitHub classroom: [classroom.github.com/a/nlFuKALw](https://classroom.github.com
### и) четене от базата данни
След това получавате команди (знак):
-
-- `g X`: изкарвате на екрана стойността в базата данни, започвайки с ред X от таблица А
-- `i`: Връщате информация за базата данни
-- `q`: спиране на програмата
+.bulleted
+- `[g X]`: изкарвате на екрана стойността в базата данни, започвайки с ред X от таблица А
+- `[i]`: Връщате информация за базата данни
+- `[q]`: спиране на програмата
### й) заявки
-- `t X`: връщате броя и след това всички редове от таблица А с тип X
-- `r X`: връщате броя и всички редове от таблица А, които използват реда Х
+.bulleted
+- `[t X]`: връщате броя и след това всички редове от таблица А с тип X
+- `[r X]`: връщате броя и всички редове от таблица А, които използват реда Х\n
Ако реда е 0, тогава трябва да върнете и размера на криптографския ред
### к) презаписване в базата данни
-- `w T R V`: запазвате (презаписвате) стойност V в таблица Т (може да бъде `A` или `B`) на ред R
-- `s T V`: запазвате стойност V от тип Т в базата данни
+.bulleted
+- `[w T R V]`: запазвате (презаписвате) стойност V в таблица Т (може да бъде `[A]` или `[B]`) на ред R
+- `[s T V]`: запазвате стойност V от тип Т в базата данни\n
Пробвате се да я запазите, използвайки и двете таблици, но ако Б вече е запълнена, добавяте я като компресирана стойност в таблица А.
Ако и А е запълнена, изкарвате съобщение за запълнена база данни и не запазвате стойността.
-&:question Какво трябва да направите, ако получите компресирана стойност за таблица А?
+.question Какво трябва да направите, ако получите компресирана стойност за таблица А?
diff --git a/src/teaching/upp-2023/additional2/index.md b/src/teaching/upp-2023/additional2/index.du
index d4e07b4..d562120 100644
--- a/src/teaching/upp-2023/additional2/index.md
+++ b/src/teaching/upp-2023/additional2/index.du
@@ -1,15 +1,18 @@
# Допълнително упражнение 2 - УПП, 04.12.2023
-GitHub classroom: [classroom.github.com/a/CrerXpf6](https://classroom.github.com/a/CrerXpf6)
+\n
-&:important Следете внимателно дали триете всичката си динамична памет коректно на всяка подточка!
- Случвало се е на контролни да се пишат двойки ако всичко друго е коректно, но има неизтрита памет!
+GitHub classroom: [url https://classroom.github.com/a/CrerXpf6 classroom.github.com/a/CrerXpf6]
+
+.important
+Следете внимателно дали триете всичката си динамична памет коректно на всяка подточка!
+Случвало се е на контролни да се пишат двойки ако всичко друго е коректно, но има неизтрита памет!
## Задача - текстов редактор
Ще направим един прост текстов редактор.
От входа ще получавате редове текст, в общия случай редовете ще бъдат някакво текстово съдъражение, което ще трябва да запазите в паметта.
-Определени редове ще имат команди, чрез които ще *редактирате* вече въведения текст.
+Определени редове ще имат команди, чрез които ще *[редактирате]* вече въведения текст.
Задачата е сравнително голяма, затова е разделена на подточки, като всяка надгражда предходната.
@@ -18,14 +21,15 @@ GitHub classroom: [classroom.github.com/a/CrerXpf6](https://classroom.github.com
Като за начало, нека да имплементираме запазването на текст.
От конзолата ще получавате редове текст, всеки ред ще е с максимална дължина от 1024 знака, след това трябва да го запазите.
-&:important Може да използвате масив със статична дължина за буфер, обаче трябва да използвате възможно най-малко памет за "перманентното" запазване на реда текст във вашата програма.
- Използвайте многомерен масив за запазване на редовете, вместо всичко да се запазва в един голям низ.
- Това е нужно за бъдещи подточки.
+.important
+Може да използвате масив със статична дължина за буфер, обаче трябва да използвате възможно най-малко памет за "перманентното" запазване на реда текст във вашата програма.
+Използвайте многомерен масив за запазване на редовете, вместо всичко да се запазва в един голям низ.
+Това е нужно за бъдещи подточки.
-*Само за тестване*, набързо имплементирайте проверка, ако първата буква от реда е `Q`, тогава програмата да спре да приема вход, да изкара въведения текст до сега и да приключи.
+*[Само за тестване]*, набързо имплементирайте проверка, ако първата буква от реда е `[Q]`, тогава програмата да спре да приема вход, да изкара въведения текст до сега и да приключи.
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -37,37 +41,35 @@ DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
earth-bank where a little-traveled trail led east through the pine for-
est. It was a high bank, and he paused to breathe at the top.
-```
### б) функция за извеждане на команди
-Команда е един ред текст, като първата буква, различна от шпация, е `:`.
+Команда е един ред текст, като първата буква, различна от шпация, е `[:]`.
След нея има нула или повече шпации и още една буква, тази буква определя коя команда искаме да използваме.
В зависимост от командата, може да имаме параметри, поставени след буквата за командата.
Параметрите не съдържат шпации и параметрите са разделени помежду си с поне една шпация.
Тоест, един команден ред ще бъде в този формат (като нещата в квадратните скоби са описания, какво има на конкретното място):
-```
[≥0 шпации]:[≥0 шпации][буква][≥0 шпации][параметър 1][≥1 шпации][параметър 2]...[≥1 шпации][последен параметър]
-```
Командите не се запазват като част от текста.
-Имплементирайте функция `extractCommand`, която приема низ.
+Имплементирайте функция `[extractCommand]`, която приема низ.
Ако низът е команда, тогава връща масив от низове, първия от които съдържа буквата, определяща командата, докато останалите низове са параметрите.
Ако низът не е команда, тогава връща празен масив.
-&:warn Какво означава празен масив зависи от имплементацията ви.
- За предпочитане е да не заделяте памет, когато не е нужно.
+.warn
+Какво означава празен масив зависи от имплементацията ви.
+За предпочитане е да не заделяте памет, когато не е нужно.
-&:question Как ще върнем масив? Нужно ли е да връщаме бройката елементи?
+.question Как ще върнем масив? Нужно ли е да връщаме бройката елементи?
-*Само за тестване*, след всеки въведен ред, ако е команда, изкарайте извлечените стойности от `extractCommand`, със запетайки след всяка.
-Като при [подточка a)](#section), ако редът започва с `Q`, спирате приемане на вход и изкарвате запазения текст.
+*[Само за тестване]*, след всеки въведен ред, ако е команда, изкарайте извлечените стойности от `[extractCommand]`, със запетайки след всяка.
+Като при [url #section подточка a)], ако редът започва с `[Q]`, спирате приемане на вход и изкарвате запазения текст.
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -89,21 +91,19 @@ DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
earth-bank where a little-traveled trail led east through the pine for-
est. It was a high bank, and he paused to breathe at the top.
-```
### в) команда print
-Имплементирайте функция `print`, която приема масив, съдържащ целия запазен текст, и го изкарва на екрана, като преди всеки ред изкарва неговия номер (първи ред има номер 1, втори има номер 2, так. нат.) с **вмъкнати водещи нули** (така че всяко число да бъде съставено от един и същ брой знаци).
+Имплементирайте функция `[print]`, която приема масив, съдържащ целия запазен текст, и го изкарва на екрана, като преди всеки ред изкарва неговия номер (първи ред има номер 1, втори има номер 2, так. нат.) с =[вмъкнати водещи нули]= (така че всяко число да бъде съставено от един и същ брой знаци).
Ако текстът е празен, не изкарва нищо.
-Тоест, ако сме въвели текст от 7 реда, `print` ще изкара:
+Тоест, ако сме въвели текст от 7 реда, `[print]` ще изкара:
```terminal
1 First line
2 Second line
...
7 Last line
-```
Ако сме въвели 23 реда:
@@ -116,7 +116,6 @@ est. It was a high bank, and he paused to breathe at the top.
11 Eleventh line
...
23 Last line
-```
Ако сме въвели 130 реда:
@@ -130,18 +129,17 @@ est. It was a high bank, and he paused to breathe at the top.
100 100th line
...
130 Last line
-```
-
-Командата, която използва тази функция, се определя с главната буква `P` и няма параметри.
-За всички команди (за момента само `P`):
+Командата, която използва тази функция, се определя с главната буква `[P]` и няма параметри.
+За всички команди (за момента само `[P]`):
+.bulleted
- Обновете програмата, така че при валидна команда, да изпълни съответната и функция и да продължи изпълнение.
- Ако срещнете недефинирана команда, трябва да изкарате на екрана "; Not an editor command" и изпълнението на програмата да продължи.
- Ако срещнете допълнителни/излишни параметри, трябва да изкарате "; Excess parameters", но функцията да се изпълни с коректния брой параметри.
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -162,16 +160,15 @@ DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
earth-bank where a little-traveled trail led east through the pine for-
est. It was a high bank, and he paused to breathe at the top.
-```
### г) команда quit
-Вече може да премахнете временната функционалност, където ако реда започва с `Q` програмата спира и изкарва целия текст.
-Добавете командата `Q`, която изкарва на екрана целия текст (без номера на редове) и спира програмата.
+Вече може да премахнете временната функционалност, където ако реда започва с `[Q]` програмата спира и изкарва целия текст.
+Добавете командата `[Q]`, която изкарва на екрана целия текст (без номера на редове) и спира програмата.
-**Примери:**
-*Смесен вход/изход*
+=[Примери:]=
+*[Смесен вход/изход]*
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -179,7 +176,6 @@ the man turned aside from the main Yukon trail. He climbed the high
:Q
DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
-```
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -188,28 +184,27 @@ the man turned aside from the main Yukon trail. He climbed the high
; Excess parameters
DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
-```
### д) команда delete
-Имплементирайте функцията `deleteRow`, която получава целия текст, въведен до сега, и номер на реда (редовете се индексират от 1 до N).
+Имплементирайте функцията `[deleteRow]`, която получава целия текст, въведен до сега, и номер на реда (редовете се индексират от 1 до N).
Тя променя текста, като премахва реда на дадения номер.
-&:important Не забравяйте да промените размера на масива с низове! Не е решение просто да промените указателя към дадения ред на `nullptr`, не искаме да използваме излишна памет.
+.important Не забравяйте да промените размера на масива с низове! Не е решение просто да промените указателя към дадения ред на `[nullptr]`, не искаме да използваме излишна памет.
-&:question Какъв ще бъде типа на аргумента, който приема целия текст?
+.question Какъв ще бъде типа на аргумента, който приема целия текст?
-Добавете командата `D`, която приема един параметър - цяло положително число, и го прилага върху функцията `deleteRow`.
+Добавете командата `[D]`, която приема един параметър - цяло положително число, и го прилага върху функцията `[deleteRow]`.
Ако номера на реда е невалиден, трябва да изкарате съобщение "; Invalid row number".
Имплементирайте следните функционалности за всички команди:
-
+.bulleted
- Ако срещнете команда, на която не са и подадени нужния брой параметри, изкарайте съобщението "; Not enough parameters" и продължете изпълнение.
- Ако даден параметър на команда е от невалиден тип (подадени букви, когато се иска число, примерно), изкарайте "; Invalid parameter type".
Единствените типове на параметри са цели числа и произволни низове (без шпации).
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```terminal
dAY HAD DAWNED COLD AND GRAY WHEN
@@ -242,20 +237,19 @@ est. It was a high bank, and he paused to breathe at the top.
DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
earth-bank where a little-traveled trail led east through the pine for-
-```
### e) команда insert
-Имплементирайте функция `insertRow`, която приема целия текст, низ и номер на реда.
-Функцията вмъква низа в целия текст като ред **над** този на подадения номер.
+Имплементирайте функция `[insertRow]`, която приема целия текст, низ и номер на реда.
+Функцията вмъква низа в целия текст като ред =[над]= този на подадения номер.
Ако номерът е над броя въведени редове до сега, редът се вмъква като последен.
-Добавете команда `O`, която приема един параметър - неотрицателен ред.
-Следващия написан ред ще се вмъкне преди реда на дадения номер, използвайки функцията `insertRow`.
+Добавете команда `[O]`, която приема един параметър - неотрицателен ред.
+Следващия написан ред ще се вмъкне преди реда на дадения номер, използвайки функцията `[insertRow]`.
Ако номера е невалиден изкарва "; Invalid row number".
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```terminal
the man turned aside from the main Yukon trail. He climbed the high
@@ -288,23 +282,22 @@ He excused
3 earth-bank where a little-traveled trail led east through the pine for-
4 est. It was a high bank, and he paused to breathe at the top.
5 He excused
-```
### ж) команда join
-Имплементирайте функция `joinRows`, която приема текстът, въведен до сега, и номер на ред N.
+Имплементирайте функция `[joinRows]`, която приема текстът, въведен до сега, и номер на ред N.
Функцията вмъква текста от ред N+1 в края на ред N, като ги разделя с една шпация.
Ред N+1 се изтрива.
Ако N е 0 или номера на последния ред, не прави нищо.
-&:important Не забравяйте да промените размера на масива с низове! Не е решение просто да промените указателя към дадения ред на `nullptr`, не искаме да използваме излишна памет.
+.important Не забравяйте да промените размера на масива с низове! Не е решение просто да промените указателя към дадения ред на `[nullptr]`, не искаме да използваме излишна памет.
-Добавете команда `J`, която приема номер на ред - положително число.
-Следващия ред ще се вмъкне в края на сегашния, с една шпация между тях, използвайки функцията `joinRows`.
+Добавете команда `[J]`, която приема номер на ред - положително число.
+Следващия ред ще се вмъкне в края на сегашния, с една шпация между тях, използвайки функцията `[joinRows]`.
При подаден невалиден ред изкарвате "; Invalid row number".
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```terminal
DAY HAD DAWNED
@@ -332,20 +325,19 @@ the man turned aside from the main Yukon trail. He climbed the high
:Q
DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
-```
### з) команда word info
-Имплементирайте функция `wordOccurrences`, която приема целия текст и дума (низ без шпации).
+Имплементирайте функция `[wordOccurrences]`, която приема целия текст и дума (низ без шпации).
Тя изкарва на екрана броя на срещания на дадената дума в целия текст, като изхода е във формата "; N occurrences" (където N е броя на срещания).
-*Подсказвам, че за следващата подточка ще е полезно ако първо имплементирате функция, която връща броя срещания на дума в един ред.*
+*[Подсказвам, че за следващата подточка ще е полезно ако първо имплементирате функция, която връща броя срещания на дума в един ред.]*
-Добавете команда `n`, която приема един аргумент - низ беш шпации.
-Използвайки `wordOccurrences` изкарва броя срещания на дадена дума в целия текст.
+Добавете команда `[n]`, която приема един аргумент - низ беш шпации.
+Използвайки `[wordOccurrences]` изкарва броя срещания на дадена дума в целия текст.
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -365,17 +357,16 @@ DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
earth-bank where a little-traveled trail led east through the pine for-
est. It was a high bank, and he paused to breathe at the top.
-```
### и) команда word substitute
-Имплементирайте функция `substituteWord`, която приема целия текст и две думи (низове без шпации).
+Имплементирайте функция `[substituteWord]`, която приема целия текст и две думи (низове без шпации).
В текстът, всяко срещане на първата дума е заменено с втората дума.
-&:question Какво ще стане с размера на един ред, ако някоя дума/някои думи трябва да се заменят?
+.question Какво ще стане с размера на един ред, ако някоя дума/някои думи трябва да се заменят?
-Добавете команда `s`, която приема две думи - низове без шпации.
-Използвайки функцията `substituteWord` замества всяко срещане на първата дума с втората.
+Добавете команда `[s]`, която приема две думи - низове без шпации.
+Използвайки функцията `[substituteWord]` замества всяко срещане на първата дума с втората.
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -403,25 +394,24 @@ DAY HAD DAWNED COLD AND GRAY WHEN
the man turned aside from the main Yukon trail. He climbed the high
earth-bank where a little-traveled trail led east through the pine for-
est. It was a high bank, and he paused to breathe at the top.
-```
### й) команда word delete
-Имплементирайте функция `deleteWord`, която приема целия текст и дума (низ без шпации).
-В текстът, всяко срещане на думата, заедно с *излишните* шпации около нея, са премахнати.
+Имплементирайте функция `[deleteWord]`, която приема целия текст и дума (низ без шпации).
+В текстът, всяко срещане на думата, заедно с *[излишните]* шпации около нея, са премахнати.
Ето в кои случаи шпации са излишни (където "WORD" е подадената дума, която ще изтрием, а "\_" е някаква буква, която не е шпация):
-
-- `WORD _` (WORD е в началото на реда или има знаци преди нея) - шпацията след думата е излишна, трябва да стане `_`.
- Отбелязвам, че шпациите в ляво се запазват: ` WORD _` става ` _`.
-- `_ WORD` (WORD е в края на реда или има знаци след нея) - шпацията преди думата е излишна, трябва да стане `_`.
-- `_ WORD _` - шпацията, която следва думата, е излишна, тоест трябва да стане `_ _`.
- Трябва да отбележа, че шпациите в ляво се запазват така както са: `_ WORD _` става `_ _`.
+.bulleted
+- `[WORD _]` (WORD е в началото на реда или има знаци преди нея) - шпацията след думата е излишна, трябва да стане `[_]`.
+ Отбелязвам, че шпациите в ляво се запазват: `[ WORD _]` става `[ _]`.
+- `[_ WORD]` (WORD е в края на реда или има знаци след нея) - шпацията преди думата е излишна, трябва да стане `[_]`.
+- `[_ WORD _]` - шпацията, която следва думата, е излишна, тоест трябва да стане `[_ _]`.
+ Трябва да отбележа, че шпациите в ляво се запазват така както са: `[_ WORD _]` става `[_ _]`.
Във всичките случаи, като имам предвид "шпацията е излишна", означава че тази шпация, заедно с всички съседни.
-Тоест, `WORD _` трябва да стане `_`, а не ` _`.
+Тоест, `[WORD _]` трябва да стане `[_]`, а не `[ _]`.
-Добавете команда `d`, която приема един параметър - дума, низ без шпации.
-Използвайки функцията `deleteWord` премахва самата дума и излишните шпации.
+Добавете команда `[d]`, която приема един параметър - дума, низ без шпации.
+Използвайки функцията `[deleteWord]` премахва самата дума и излишните шпации.
```terminal
DAY HAD DAWNED COLD AND GRAY WHEN
@@ -434,4 +424,3 @@ DAY HAD DAWNED COLD AND GRAY WHEN
man turned aside from main Yukon trail. He climbed high
earth-bank where a little-traveled trail led east through pine for-
est. It was a high bank, and he paused to brea at top.
-```
diff --git a/src/teaching/upp-2023/index.du b/src/teaching/upp-2023/index.du
new file mode 100644
index 0000000..3dc2808
--- /dev/null
+++ b/src/teaching/upp-2023/index.du
@@ -0,0 +1,37 @@
+# Увод в програмирането - практикум, Компютърни науки, 8 група
+
+Материали на проведените през 2023/2024 практикуми по Увод в програмирането на Компютърни науки (2 поток), 8 група.
+
+.warn
+От сега нататък ще може да продължите да предавате решения след крайния срок в classroom.
+Не мога да гарантирам кога ще погледна предадени решения след срока, но ще ги погледна!
+
+=[Зала:]= ФМИ 309 ||
+=[Време:]= 10:15 - 12:00 ||
+=[Ден:]= Петък
+\n
+=[Директни връзки:]=
+[url ./week1/welcome.html?a#section-4 Контакт с мен] |
+[url https://github.com/Syndamia/upp-2023-solutions Решения на задачи] |
+[url https://github.com/ivanahristova/introduction-to-programming-2023-2024 Материали от семинари] |
+[url https://learn.fmi.uni-sofia.bg/course/view.php?id=9567 Курс в мудъл]
+
+:table
+|=&#8470;=||=Дата=||=Материали=|
+
+|:1 :||:06.10.2023:||:[url ./week1/welcome.html Добре дошли] \|\| [url ./week1/setup.html?a Конфигуриране на GitHub classroom и Visual Studio] \|\| [url ./week1/?a Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week01 Решения]:|
+|:2 :||:13.10.2023:||:[url ./week2/revision.html?a Преговор] \|\| [url ./week2 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week02 Решения]:|
+|:3 :||:20.10.2023:||:[url ./week3/revision.html?a Преговор] \|\| [url ./week3 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week03 Решения]:|
+|:4 :||:27.10.2023:||:[url ./week4/revision.html?a Преговор] \|\| [url ./week4 Задачи] \|\| [url https://classroom.github.com/a/jqKaO1ny GitHub classroom] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week04 Решения (само 1ва)]:|
+|:5 :||:03.11.2023:||:[url ./week5/revision.html Преговор] \|\| [url ./week5 Задачи] \|\| [url https://classroom.github.com/a/3KoIQ71H GitHub classroom] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week05 Решения]:|
+|: :||:04.11.2023:||:[url ./additional1/ Допълнително упражнение 1] \|\| [url https://classroom.github.com/a/nlFuKALw GitHub classroom] \|\| [url https://github.com/Syndamia/upp-2023-solutions/blob/main/additional1/exercise.cpp Решение]:|
+|:6 :||:10.11.2023:||:[url ./week6 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week06 Решения] \|\| [url https://classroom.github.com/a/BBLlWMOy GitHub classroom]:|
+|:7 :||:17.11.2023:||:[url ./week7 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week07 Решения] \|\| [url https://classroom.github.com/a/m5M2_CWD GitHub classroom]:|
+|:8 :||:24.11.2023:||:[url ./week8 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week08 Решения] \|\| [url https://classroom.github.com/a/Big7FRUG GitHub classroom]:|
+|:9 :||:01.12.2023:||:[url ./week9 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week09 Решения] \|\| [url https://classroom.github.com/a/lGXxCRZO GitHub classroom]:|
+|: :||:04.12.2023:||:[url ./additional2/ Допълнително упражнение 2] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/additional2 Решения] \|\| [url https://classroom.github.com/a/CrerXpf6 GitHub classroom]:|
+|:10:||:15.12.2023:||:[url ./week10 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week10 Решения] \|\| [url https://classroom.github.com/a/EJcTQRz4 GitHub classroom]:|
+|:11:||:22.12.2023:||:[url ./week11 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week11 Решения] \|\| [url https://classroom.github.com/a/cZRnZj9y GitHub classroom]:|
+|:12:||:05.01.2024:||:[url ./week12 Задачи] \|\| [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week12 Решения] \|\| [url https://classroom.github.com/a/KEDSxDjl GitHub classroom]:|
+|:13:||:12.01.2024:||:[url ./week13 Задачи] \|\| [url https://classroom.github.com/a/bgiFD6SB GitHub classroom]:|
+|:14:||:19.01.2024:||:[url ./week14 Задачи] \|\| [url https://classroom.github.com/a/B08TtnnW GitHub classroom]:|
diff --git a/src/teaching/upp-2023/index.md b/src/teaching/upp-2023/index.md
deleted file mode 100644
index 624a312..0000000
--- a/src/teaching/upp-2023/index.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# Увод в програмирането - практикум, Компютърни науки, 8 група
-
-Материали на проведените през 2023/2024 практикуми по Увод в програмирането на Компютърни науки (2 поток), 8 група.
-
-&:warn От сега нататък ще може да продължите да предавате решения след крайния срок в classroom.
- Не мога да гарантирам кога ще погледна предадени решения след срока, но ще ги погледна!
-
-**Зала:** ФМИ 309 ||
-**Време:** 10:15 - 12:00 ||
-**Ден:** Петък
-<br>
-**Директни връзки:**
-[Контакт с мен](./week1/welcome.html?a#section-4) |
-[Решения на задачи](https://github.com/Syndamia/upp-2023-solutions) |
-[Материали от семинари](https://github.com/ivanahristova/introduction-to-programming-2023-2024) |
-[Курс в мудъл](https://learn.fmi.uni-sofia.bg/course/view.php?id=9567)
-
-|&#8470;|Дата|Материали|
-|-------|----|---------|
-|1 |06.10.2023|[Добре дошли](./week1/welcome.html) \|\| [Конфигуриране на GitHub classroom и Visual Studio](./week1/setup.html?a) \|\| [Задачи](./week1/?a) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week01)|
-|2 |13.10.2023|[Преговор](./week2/revision.html?a) \|\| [Задачи](./week2) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week02)|
-|3 |20.10.2023|[Преговор](./week3/revision.html?a) \|\| [Задачи](./week3) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week03)|
-|4 |27.10.2023|[Преговор](./week4/revision.html?a) \|\| [Задачи](./week4) \|\| [GitHub classroom](https://classroom.github.com/a/jqKaO1ny) \|\| [Решения (само 1ва)](https://github.com/Syndamia/upp-2023-solutions/tree/main/week04)|
-|5 |03.11.2023|[Преговор](./week5/revision.html) \|\| [Задачи](./week5) \|\| [GitHub classroom](https://classroom.github.com/a/3KoIQ71H) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week05)|
-||04.11.2023|[Допълнително упражнение 1](./additional1/) \|\| [GitHub classroom](https://classroom.github.com/a/nlFuKALw) \|\| [Решение](https://github.com/Syndamia/upp-2023-solutions/blob/main/additional1/exercise.cpp)|
-|6 |10.11.2023|[Задачи](./week6) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week06) \|\| [GitHub classroom](https://classroom.github.com/a/BBLlWMOy)|
-|7 |17.11.2023|[Задачи](./week7) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week07) \|\| [GitHub classroom](https://classroom.github.com/a/m5M2_CWD)|
-|8 |24.11.2023|[Задачи](./week8) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week08) \|\| [GitHub classroom](https://classroom.github.com/a/Big7FRUG)|
-|9 |01.12.2023|[Задачи](./week9) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week09) \|\| [GitHub classroom](https://classroom.github.com/a/lGXxCRZO)|
-| |04.12.2023|[Допълнително упражнение 2](./additional2/) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/additional2) \|\| [GitHub classroom](https://classroom.github.com/a/CrerXpf6)|
-|10|15.12.2023|[Задачи](./week10) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week10) \|\| [GitHub classroom](https://classroom.github.com/a/EJcTQRz4)|
-|11|22.12.2023|[Задачи](./week11) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week11) \|\| [GitHub classroom](https://classroom.github.com/a/cZRnZj9y)|
-|12|05.01.2024|[Задачи](./week12) \|\| [Решения](https://github.com/Syndamia/upp-2023-solutions/tree/main/week12) \|\| [GitHub classroom](https://classroom.github.com/a/KEDSxDjl)|
-|13|12.01.2024|[Задачи](./week13) \|\| [GitHub classroom](https://classroom.github.com/a/bgiFD6SB)|
-|14|19.01.2024|[Задачи](./week14) \|\| [GitHub classroom](https://classroom.github.com/a/B08TtnnW)|
diff --git a/src/teaching/upp-2023/week1/index.md b/src/teaching/upp-2023/week1/index.du
index 314a8ab..2bdf99d 100644
--- a/src/teaching/upp-2023/week1/index.md
+++ b/src/teaching/upp-2023/week1/index.du
@@ -1,14 +1,16 @@
# Задачи - УПП, Седмица 1, 06.10.2023
-GitHub classroom: [classroom.github.com/a/W7hZDMgC](https://classroom.github.com/a/W7hZDMgC)
+\n
-Решения: [GitHub](https://github.com/Syndamia/upp-2023-solutions/tree/main/week01)
+GitHub classroom: [url https://classroom.github.com/a/W7hZDMgC classroom.github.com/a/W7hZDMgC]
+
+Решения: [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week01 GitHub]
### 1 задача - Hello, World!
Още от "древни" времена програмистите са си измисляли малки програмки, с които да тестват дали всичко работи.
-Традиция в модерното време е да изкараш на екрана съобщението ["Hello, World!"](https://en.wikipedia.org/wiki/%22Hello,_World!%22_program#History).
-Това е главно популяризирано от книгата [The C Programming Language](https://en.wikipedia.org/wiki/The_C_Programming_Language), централния материал върху езика С (един от най-значимите езици за програмиране някога).
+Традиция в модерното време е да изкараш на екрана съобщението [url https://en.wikipedia.org/wiki/%22Hello,_World!%22_program#History "Hello, World!"].
+Това е главно популяризирано от книгата [url https://en.wikipedia.org/wiki/The_C_Programming_Language The C Programming Language], централния материал върху езика С (един от най-значимите езици за програмиране някога).
Изкарайте на екрана съобщението "Hello, World!".
@@ -16,14 +18,14 @@ GitHub classroom: [classroom.github.com/a/W7hZDMgC](https://classroom.github.com
Във входа получавате цифра, трябва да върнете нейната числена стойност, умножена по две.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|2 |4 |
-|8 |16 |
+.table
+|=Вход=||=Изход=|
+|:2 :||:4 :|
+|:8 :||:16 :|
-**Упътване:**
+=[Упътване:]=
Цифрата е просто знак, и за да извършите коректно умножението трябва да превърнете знака в число.
### 3 задача - От Фаренхайт в Целзий
@@ -34,11 +36,10 @@ GitHub classroom: [classroom.github.com/a/W7hZDMgC](https://classroom.github.com
```
C = (F - 32) * 5/9
-```
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|32 |0 |
-|107 |41 |
+.table
+|=Вход=||=Изход=|
+|:32 :||:0 :|
+|:107 :||:41 :|
diff --git a/src/teaching/upp-2023/week1/setup.md b/src/teaching/upp-2023/week1/setup.du
index 9327b2b..9865737 100644
--- a/src/teaching/upp-2023/week1/setup.md
+++ b/src/teaching/upp-2023/week1/setup.du
@@ -1,455 +1,444 @@
# Конфигуриране на GitHub classroom и Visual Studio - УПП, Седмица 1, 06.10.2023
-&.presentation
+\n
-&[title
+[$presentation-controller]
-# Конфигуриране на GitHub classroom и Visual Studiо
-
-&]
+:title_slide
+# Конфигуриране на GitHub classroom и Visual Studiо
-&[slide
+:slide
## Теория относно GitHub classroom
+.p
Ще използваме активно GitHub classroom за упражненията.
Едва ли знаете какво е, затова ще трябва да поясня някои неща.
### Проблемът със синхронизиране на работа
+.unordered
- Системи като Dropbox, Google Drive, etc. ти позволяват да качиш файл в сървър и след това да го споделиш
-
- Върху една програма ще работят много хора, затова се налага всички разработчици да споделят своят код
-
- Различни хора могат да правят различни промени в едно и също място
-
- Обединението на труда на всички, особено в огромни екипи, става супер трудно
-&]
-
-
-&[slide
+:slide
### Git
-&.br1
+[$br1]
-git е програма (система) за [контрол на версиите](https://en.wikipedia.org/wiki/Distributed_version_control).
-В един проект, git пази **списък от всички commit-и**.
-Един commit в себе си **съдържа какви са точно промените**, кой ги е направил, кога са направени, защо са направени и так. нат.
-Този списък, заедно с още неща за които не е нужно да мислите, се нарича **repository**.
+.p
+git е програма (система) за [url https://en.wikipedia.org/wiki/Distributed_version_control контрол на версиите].
+В един проект, git пази =[списък от всички commit-и]=.
+Един commit в себе си =[съдържа какви са точно промените]=, кой ги е направил, кога са направени, защо са направени и так. нат.
+Този списък, заедно с още неща за които не е нужно да мислите, се нарича =[repository]=.
-Обаче, **commit-ове не се правят автоматично**, не е като историята с промени в един Word файл.
-**Commit се прави от разработчика**, и то за предпочитане на всеки няколко (свързани) промени.
+.p
+Обаче, =[commit-ове не се правят автоматично]=, не е като историята с промени в един Word файл.
+=[Commit се прави от разработчика]=, и то за предпочитане на всеки няколко (свързани) промени.
-Така, когато смесваме кода от многото разработчици, ще можем да засечем **какви точно са различията** между работата на двама човека.
+.p
+Така, когато смесваме кода от многото разработчици, ще можем да засечем =[какви точно са различията]= между работата на двама човека.\n
Често промените не си "противоречат" и могат да бъдат смесени директно, понякога се налага ръчно да решим какво точно да се случи с тези парчета код.
-&]
-
-
-&[slide
+:slide
### GitHub
-&.br5
+[$br5]
+.p
Всички repository-та трябва да се пазят някъде и да може лесно да се споделят и гледат.
-Има много сайтове за тази цел, най-популярния се нарича [GitHub](https://github.com).
+Има много сайтове за тази цел, най-популярния се нарича [url https://github.com GitHub].
+.p
Напомням, че git и GitHub са напълно отделни неща, направени от различни хора с различни функционалности.
Свързаността с имената е както свързаността между думите "чар" и "чаршаф".
-&]
-
-
-&[slide
+:slide
## Сега всички трябва да си направят GitHub акаунти
-Отивате на [github.com/signup](https://github.com/signup), въвеждате си данните една по една и се регистрирате
-
-![](./img/github-signup.gif)
-
-&]
+.p
+Отивате на [url https://github.com/signup github.com/signup], въвеждате си данните една по една и се регистрирате
+.p [image ./img/github-signup.gif]
-&[middle
+:middle_slide
+.p
След това, като влезете в акаунтите си (което става автоматично след регистрация), на заглавната страница ще имате нещо такова:
-&(width75% ![](./img/github-index.gif) &)
+.width75% [image ./img/github-index.gif]
+.p
В горния десен ъгъл, където е иконката с квадрати на бял фон, след натискане получавате sidebar.
От него, може да достъпите профила си, repository-та които имате, и так. нат.
-&]
-
-
-&[slide
+:slide
### Проверете дали сте маркирани!
+.p
Понякога при създаване на нов акаунт, GitHub го маркира (като "проблемен").
В такава ситуация, няма да можете сами да го изтриете и няма да можете да го ползвате за GitHub classroom.
-Най-простия начин, който намерих, е да отворите
-[support.github.com/contact/reinstatement](https://support.github.com/contact/reinstatement)
+.p
+Най-простия начин, който намерих, е да отворите
+[url https://support.github.com/contact/reinstatement support.github.com/contact/reinstatement]\n
Ако отгоре пише "Your account has been flagged", тогава имаме проблем.
-![](./img/github-support-flagged.gif)
-
-&]
-
+.p
+[image ./img/github-support-flagged.gif]
-&[slide
+:slide
## GitHub classroom
-&.br3
+[$br3]
+.p
За всеки практикум ще ви направя линк, чрез който след малко кликане ще се създаде ново лично repository за всеки от вас.
-До 12:20 трябва да сте качили работата си **по време** на упражнението в това repository.
+.p
+До 12:20 трябва да сте качили работата си =[по време]= на упражнението в това repository.
GitHub предоставя лесни начини да правите промени по файлове директно чрез браузъра, така че за незаинтересуваните, може да го ползвате като усложнен Google Drive.
+.p
След това аз ще направя отзиви върху вашата работа.
Те ще се намират в таба "Pull Requests" на конкретното repository.
Четете ги, отговаряйте, целта е да дискутираме какво сте направили.
-&]
-
-
-&[slide
+:slide
### Как ползваме GitHub classroom
-За всяко упражнение ще има отделен линк.
-Този за днеска е: [classroom.github.com/a/W7hZDMgC](https://classroom.github.com/a/W7hZDMgC)
-
-&.br1
+.p
+За всяко упражнение ще има отделен линк.\n
+Този за днеска е: [url https://classroom.github.com/a/W7hZDMgC classroom.github.com/a/W7hZDMgC]
-&{row
+[$br1]
-След като го отворите, ще видите съобщение за разрешение, авторизирайте го.
+:row
+.p След като го отворите, ще видите съобщение за разрешение, авторизирайте го.
-![](./img/github-classroom-authorize.gif)
+.p [image ./img/github-classroom-authorize.gif]
-&}
-&]
+:middle_slide
-&[middle
+:row
-&{row
+.width60% [image ./img/join-the-classroom.gif]
-&(width60% ![](./img/join-the-classroom.gif) &)
+:column
-&{column
+.p При първо влизане ще получите страница с имената и факултетните имена на всички студенти от групата.
-При първо влизане ще получите страница с имената и факултетните имена на всички студенти от групата.
+.p Изберете своето.
-Изберете своето.
+.p Това се прави само веднъж, и след това никога пак.
-Това се прави само веднъж, и след това никога пак.
-&}
-&}
-&]
+:slide
+.p След това, би трябвало да видите страницата за "Приемане на заданието".
-&[slide
+.width40% [image ./img/accept-assignment.gif]
-След това, би трябвало да видите страницата за "Приемане на заданието".
-
-&(width40% ![](./img/accept-assignment.gif) &)
-
-След като го приемете, на новата страница, изчакайте няколко секунди и презаредете.
+.p След като го приемете, на новата страница, изчакайте няколко секунди и презаредете.
Трябва да видите това:
-&(width40% ![](./img/ready-to-go.gif) &)
-
-&]
+.width40% [image ./img/ready-to-go.gif]
+:middle_slide
-&[middle
+.p Сега сте готови, кликнете върху синия линк и ще стигнете във вашето GitHub repository.
-Сега сте готови, кликнете върху синия линк и ще стигнете във вашето GitHub repository.
-
-Вътре в това конкретно repository очаквам да качвате работата ви през упражнението.
+.p Вътре в това конкретно repository очаквам да качвате работата ви през упражнението.
Повтарям, дори да е недовършено, дори да има някакви празни файлове и такива, трябва да го качите.
-Който иска спокойно може да прави няколко commit-и, да им прави съобщения и так. нат., ама към този етап, това не е нужно.
-
-В края на презентация показвам как точно е най-лесно да качите работата си.
-
-&]
+.p Който иска спокойно може да прави няколко commit-и, да им прави съобщения и так. нат., ама към този етап, това не е нужно.
+.p В края на презентация показвам как точно е най-лесно да качите работата си.
-&[slide
+:slide
+.p
В таба "Pull requests", още от началото, ще имате едно "Feedback".
В него ще ви връщам отзиви относно работата ви, и вие също можете да пишете неща и да ми отговаряте.
+.p
Целта е да видя какво правите и да ви помогна, моля проверявайте какво съм ви писал, по подразбиране би трябвало да получавате известия на имейл-а.
-&(centered &(width80% ![](./img/feedback.gif) &) &)
+.centered
+.width80% [image ./img/feedback.gif]
-&]
-
-
-&[slide
+:slide
## Къде пишем код?
-&.br2
+[$br2]
-**Кодът е чисто и просто текст**, компилаторът е специалната програма, която превръща този текст в нещо, което може компютъра да изпълни.
+.p
+=[Кодът е чисто и просто текст]=, компилаторът е специалната програма, която превръща този текст в нещо, което може компютъра да изпълни.
-За писане и редактиране на текст ползваме **текстови редактори**.
+.p
+За писане и редактиране на текст ползваме =[текстови редактори]=.
Програмистите са искали да улеснят работата си, затова модерните текстови редактори поддържат много помощни функционалности: показване на грешки на точния ред, автоматично форматиране, ...
-За някои и това не е било достатъчно удобно, затова са създадени **Integrated Development Environment** (IDE), програми които съдържат в себе си всичко нужно за разработка на код.
+.p
+За някои и това не е било достатъчно удобно, затова са създадени =[Integrated Development Environment]= (IDE), програми които съдържат в себе си всичко нужно за разработка на код.
Тоест, те са текстови редактори, но "вградено" могат да компилират код, да менижират сегашното repository, ...
-&]
-
-
-&[middle
+:middle_slide
+.p
Главно очакваме да пишете на IDE-то наречено Visual Studio.
Разработено е от Microsoft и е едно от най-използваните и развитите IDE-та на пазара.
+.p
Разбира се, може да ползвате и текстови редактори като Visual Studio Code, vim, emacs, ...
-
+.bulleted
- Главния проблем с тях е, че ще се налага повече конфигурация, но пък ще са по-леки и по-флексибилни
- Главния плюс е, че те са налични за операционни системи извън Microsoft Windows, за разлика от Visual Studio
+.p
Ивана ви говори за Visual Studio Code, аз ще ви говоря за Visual Studio.
+.p
Извън това, по лично желание, с мен може да говорите за vim, а за neovim може би ще мога да ви насоча към някой с опит.
-&]
-
-
-&[slide
+:slide
### Инсталация
-&.br1
+[$br1]
+.p
Намираме се в компютърна зала, така че всички предоставени компютри би трябвало вече да са налични на предоставените компютри.
За ваши лични машини, ще минем набързо през информацията тук.
-За Visual Studio Code, отивате на [code.visualstudio.com/Download](https://code.visualstudio.com/Download), избирате своята операционна система (за Уиндоус, ако не сте сигурни, изберете "System Installer x64") и инсталирате.
+.p
+За Visual Studio Code, отивате на [url https://code.visualstudio.com/Download code.visualstudio.com/Download], избирате своята операционна система (за Уиндоус, ако не сте сигурни, изберете "System Installer x64") и инсталирате.
-За Visual Studio, отивате на [visualstudio.microsoft.com](https://visualstudio.microsoft.com/), скролвате малко надолу, избирате "Download Visual Studio" и след това "Community 2022".
+.p
+За Visual Studio, отивате на [url https://visualstudio.microsoft.com/ visualstudio.microsoft.com], скролвате малко надолу, избирате "Download Visual Studio" и след това "Community 2022".
+.bulleted
+'footnote vs-2022-old-win Може би има трикове с които да инсталирате 2022 версията, но те не са официални и затова няма да го преподам
+- Ако искате да ползвате по-стара ОС, като Windows 8.1 или Windows 7 ще трябва да използвате "Community 2019"[$vs-2022-old-win], разликата между версиите не е съществена, затова не се притеснявайте.
-- Ако искате да ползвате по-стара ОС, като Windows 8.1 или Windows 7 ще трябва да използвате "Community 2019"[^vs-2022-old-win], разликата между версиите не е съществена, затова не се притеснявайте.
-&]
-
-
-
-&[slide
+:slide
+.p
След като изтеглите инсталатора за Visual Studio и след като изчакате да заредят работи, би трябвало да имате прозорец на име "Installing - Visual Studio Community 2022".
+.p
Единствено избирате "Desktop development with C++" в таба Worloads, и натискате "Install".
Би трябвало да заема към 11 GB памет и в моето тестване се инсталира за 10тина минути.
-&(centered &(width80% ![](./img/vs-install.gif) &) &)
-
-&]
+.centered
+.width80% [image ./img/vs-install.gif]
+:slide
-&[slide
-
+.p
Когато е готово, би трябвало да се включи автоматично и да имате прозорец с име "Sign in to Visual Studio".
За сега това не е нужно, спокойно изберете "Not now, maybe later."
+.p
След това, на "Start with a familiar environment", отново, не е нужно да променяте нищо, просто натиснете "Start Visual Studio".
-&(centered &(width75% &{row
+:centered
+:width75%
+:row
-![](./img/vs-signin.gif)
+.p [image ./img/vs-signin.gif]
-![](./img/vs-start-env.gif)
+.p [image ./img/vs-start-env.gif]
-&} &) &)
-&]
-&[slide
+:slide
### Как да създадем проект с Visual Studio
+.p
Това е първия прозорец, който се отваря.
В лявата колона имате скорошни проекти, в дясната имате начини да създадете нов проект.
-&(centered &(width80% ![](./img/vs-open-recent.gif) &) &)
+:centered
+:width80% [image ./img/vs-open-recent.gif]
-&]
-&[slide
+:slide
+.p
Нека да направим нов проект, кликнете "Create a new project".
В този прозорец избирате началната "конфигурация" на проекта.
В този курс ще работим само и единствено с "Console App", затова изберете него и кликнете "Next".
-&(centered &(width75% ![](./img/vs-create-project.gif) &) &)
+:centered
+:width75% [image ./img/vs-create-project.gif]
-&]
-&[slide
+:slide
+.p
Последния прозорец преди писането на код е за конфигурация на проекта.
Тук единствено може да искате да промените Project Name и Location, другото не е важно.
-&(centered &(width80% ![](./img/vs-configure-project.gif) &) &)
+:centered
+:width80% [image ./img/vs-configure-project.gif]
-&]
-&[slide
+:slide
#### Бърза вметка, какво и защо конзолата?
+.p
През 19ти век са изобретени teleprinters: пишещи машини с възможности да печат текст от електрически сигнал.
Използвали са се в телеграфията: пишеш като на пишеща машина съобщението и отговора се напечатва на същия лист хартия.
В ранните години на компютрите, точно тези teleprinters са били използвани, все пак са били съществуваща технология, която "изпраща" текст като ел. сигнали и може да принтира ел. сигнали като текст.
+.p
Имало е неудобства, използвало се е много хартия, и механиката на бутоните е била сложна.
С времето компаниите са разработвали такива устройства, който обаче ползват електронно-лъчева тръба и "нормални" бутони за клавиши.
+.p
Чисто практически, ние това знаем като конзолата: устройство (или в модерно време, програма) което може да получи входен текст и да изкара текст.
-&]
-
-
-&[slide
+:slide
### Как да компилираме с Visual Studio
+.p
След малко чакане, най-после ще се намираме в средата за писане на код.
-&(centered &(width60% ![](./img/vs-general.gif) &) &)
+:centered
+:width60%
+.p [image ./img/vs-general.gif]
-В Solution Explorer имате всички файлове от проекта (Visual Studio позволява да групирате няколко проекта в едно, наречено Solution, не е нужно да се занимавате).
-Тук **единственото важно за вас се намира в папката "Source Files"**.
-В нея ще се намира вашия код, всичко останало са допълнителни неща, които са релевантни за по-големи проекти.
-&]
+.p
+В Solution Explorer имате всички файлове от проекта (Visual Studio позволява да групирате няколко проекта в едно, наречено Solution, не е нужно да се занимавате).
+.p
+Тук =[единственото важно за вас се намира в папката "Source Files"]=.
+В нея ще се намира вашия код, всичко останало са допълнителни неща, които са релевантни за по-големи проекти.
-&[slide
+:slide
-&{row
+:row
+.p
Компилирането на код става от менюто "Debug" най-отгоре, и след това избиране на "Start Without Debugging".
-&(width50% &(fright ![](./img/vs-debug-menu.gif) &) &)
+:width50%
+:fright
+.p [image ./img/vs-debug-menu.gif]
-&}
-След малко чакане, би трябвало да излезе един прозорец, който изглежда горе-долу така:
-![](./img/vs-console.gif)
-&]
+.p
+След малко чакане, би трябвало да излезе един прозорец, който изглежда горе-долу така:
+.p [image ./img/vs-console.gif]
-&[slide
+:slide
### Как да дебъгваме с Visual Studio
-&.br1
+[$br1]
+.p
Bug е когато нещо непланирано се случи в кода.
Debuging е глаголът за откриване на причината за един bug.
Visual Studio предоставя много функционалности, които да ускорят debugging.
+.p
Нека да въведем една грешка, в реда на който изкараме "Hello, World!", нека да махнем последната ";".
+.p
При компилиране, ще получим съобщение за грешки по време на компилирането.
-![](./img/vs-build-errors.gif)
-
-&]
+.p [image ./img/vs-build-errors.gif]
+:slide
-&[slide
-
+.p
Нека да натиснем "No" и да погледнем Visual Studio.
+.p
Грешките, или поне където то си мисли че са, ще бъдат подчертани с червена зигзагообразна линия.
Ако сложим мишката върху тях, ще получим popup, в който ще пише каква е грешката на това място.
Грешки също се виждат в така наречения "Error List", който се намира директно под кода.
Той се появява когато при компилиране получим грешки и изчезва когато няма.
-&(centered &(width70% ![](./img/vs-errors.gif) &) &)
+:centered
+:width70% [image ./img/vs-errors.gif]
-&]
-&[slide
+:slide
### Качване на решенията
+.p
След като сте решили една задача, имате два варианта за писане на следващата: или да създадете нов проект, или да презапишете кода.
Второто е най-лесно.
+.p
Във всеки случай, ще се наложи сегашния файл с код да го качите.
Най-елементарния начин: копирате всичко, след това отивате на вашето GitHub repository, кликвате "Add", после "Create new file".
-Отгоре на "Name your file..." пишете някакво име, което **моля да завърша на `.cpp`!**
+.p
+Отгоре на "Name your file..." пишете някакво име, което =[моля да завърша на `[.cpp]`!]=
Това показва, че файла съдържа код на C++.
-Също, когато решавате много задачи и създавате много такива файлове, **напомням че имената на файловете трябва да са различни.**
+Също, когато решавате много задачи и създавате много такива файлове, =[напомням че имената на файловете трябва да са различни.]=
+.p
В "Enter file contents here" пействате копирания код.
Горе в дясно натискате "Commit changes...", в pop-up-a после пак натискате "Commit changes" (ако искате, променяйте "Commit message" и "Extended description", но не е нужно) и сте готови с този файл/задача.
-&]
-
-
-
-&[middle
-
-## Вече имате достатъчно информация да пишете код сами, [време е за задачи](./)
-
-&]
+:middle_slide
-[^vs-2022-old-win]: Може би има трикове с които да инсталирате 2022 версията, но те не са официални и затова няма да го преподам
+## Вече имате достатъчно информация да пишете код сами, [url ./ време е за задачи]
diff --git a/src/teaching/upp-2023/week1/welcome.md b/src/teaching/upp-2023/week1/welcome.du
index a1cb6a0..e1690a2 100644
--- a/src/teaching/upp-2023/week1/welcome.md
+++ b/src/teaching/upp-2023/week1/welcome.du
@@ -1,370 +1,352 @@
# Добре дошли - УПП, Седмица 1, 06.10.2023
-&.presentation
+\n
-&[title35
+[$presentation-controller]
-# Добре дошли
+:title_slide35
-&(width65%
-[![](https://upload.wikimedia.org/wikipedia/commons/3/3c/Chimpanzee_seated_at_typewriter.jpg)](https://en.wikipedia.org/wiki/Infinite_monkey_theorem)
-&)
+# Добре дошли
-&]
+:width65%
+[image_url https://upload.wikimedia.org/wikipedia/commons/3/3c/Chimpanzee_seated_at_typewriter.jpg https://en.wikipedia.org/wiki/Infinite_monkey_theorem]
-&[slide
+:slide
## Кой съм аз
-&.br2
+[$br2]
-&(font35
+:font35
-Казвам се Камен (моля не ми говорете на Вие), в момента съм третокурсник в КН2.
+Казвам се Камен (моля не ми говорете на Вие), в момента съм третокурсник в КН2.\n
-&.br1
+[$br1]
-Ще водя практикуми - давам ви задачи, вие ги решавате и на живо оправяме проблеми.
+Ще водя практикуми - давам ви задачи, вие ги решавате и на живо оправяме проблеми.\n
-&.br1
+[$br1]
Също ще проверявам част от домашните и контролните през семестъра.
-&)
-
-&]
-
-&[slide
+:slide
## Кои сте вие
Айде сега, ред по ред:
-&.br3
-
-&(font35
+[$br3]
+:font35
+:bulleted
- Име
+ .bulleted
- Едва ли ще го запомня сега, не ми се сърдете :)
+
- Коя операционна система ползвате
- Писали ли сте код преди? Ако да:
+ .bulleted
- на кои езици?
- в какво IDE/текстов редактор?
- как сте се научили (чрез интернет, курсове, ...)? Ходили ли сте на курсове? Къде?
-&)
-
-&]
-&[slide
+:slide
## Чисто организационно
-&.br3
+[$br3]
+
+:centered35
+Задачи, презентации, ...\n
+[url /teaching/upp-2023 syndamia.com/teaching/upp-2023]
-&(centered35
-Задачи, презентации, ...
-[syndamia.com/teaching/upp-2023](/teaching/upp-2023)
-&)
-&.br3
+[$br3]
+:unordered
- Не сме в училище, ако трябва да излезете за разговор или до тоалетна, просто си излезте (за предпочитане по-тихичко).
- Ако ви се наложи да пропуснете някой практикум, пропускайте.
+ .bulleted
- Само ако решите за постоянно да ходите при някой друг, кажете за да се организираме екипа.
- Оценяване: ще разберете на първата лекция
-&]
-
-&[slide
+:slide
## Как можете да се свържете
+:unordered
- Facebook messenger: <img class="file-type-icon" src="/files/ephemeral/facebook.png">
- Discord: <img class="file-type-icon" src="/files/ephemeral/discord.png">
- Имейл:
+ .bulleted
- <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;">&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#97;&#109;&#101;&#110;&#46;&#100;&#46;&#109;&#108;&#97;&#100;&#101;&#110;&#111;&#118;&#64;&#112;&#114;&#111;&#116;&#111;&#110;&#109;&#97;&#105;&#108;&#46;&#99;&#111;&#109;-62ca52e87475c874b9e6ebf3c4c9f716b6ce4c9d.asc"><img class="borderless unzoomable" src="/img/pgpkey.gif" alt="PGP key"></a>
- - <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;">&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;-0x354C5F95.asc"><img class="borderless unzoomable" src="/img/pgpkey.gif" alt="PGP key"></a> **(гледайте си спама!)**
- - [kdmladenov@uni-sofia.bg](mailto:kdmladenov@uni-sofia.bg)
+ - <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;">&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;</a> <a class="borderless" href="/files/publickey-&#107;&#097;&#109;&#101;&#110;&#064;&#115;&#121;&#110;&#100;&#097;&#109;&#105;&#097;&#046;&#099;&#111;&#109;-0x354C5F95.asc"><img class="borderless unzoomable" src="/img/pgpkey.gif" alt="PGP key"></a> =[(гледайте си спама!)]=
+ - [url mailto:kdmladenov@uni-sofia.bg kdmladenov@uni-sofia.bg]
-Директни линкове към Facebook и Discord има на [профила ми в мудъл](https://learn.fmi.uni-sofia.bg/user/profile.php?id=23229).
-&]
+Директни линкове към Facebook и Discord има на [url https://learn.fmi.uni-sofia.bg/user/profile.php?id=23229 профила ми в мудъл].\n
-&[slide
+:slide
## Как ще протичат практикумите
-- Ще започнем всяко упражнение с 5 минутки преговор, какво ново трябва да приложим
+:unordered
+- Ще започнем всяко упражнение с 5 минутки преговор, какво ново трябва да приложим\n
и ще го завършим с 15-20 минути (ако има желание/смисъл) обяснение на задача
- Ще гледам винаги да има задачи с връзка към реален софтуер.
За любителите, където е възможно, ще добавям външни препратки.
-- Давам ви *много* повече задачи, отколкото очаквам да решите на живо!
+- Давам ви *[много]* повече задачи, отколкото очаквам да решите на живо!\n
Хубаво е да имате с какво още да се упражните след практикума, 2 часа писане на код седмично е малко!
-- Ще качвам решения на задачите, заедно с подробно коментари върху тях, тук: [github.com/Syndamia/upp-2023-solutions](https://github.com/Syndamia/upp-2023-solutions).
+- Ще качвам решения на задачите, заедно с подробно коментари върху тях, тук: [url https://github.com/Syndamia/upp-2023-solutions github.com/Syndamia/upp-2023-solutions].
Това ще се случва в началото на следващия практикум, тоест ще имате една седмица, от деня в който ви давам задачите, през която няма да имате решения.
-&]
-
-&[middle
-
+:middle_slide
+:unordered
- Ще използваме GitHub classroom, където ще трябва да качите работата си през упражнението.
Целта е да видя какво сте правили и да връщам обратна връзка на всеки.
Дори нещо да е недовършено, да не работи, так. нат. качвайте!
-
+ .bulleted
- Това ще играе роля върху оценката ви, но колко ще допринесе зависи изцяло от преценката ми
- Обратна връзка със сигурност ще правя за нещата, предадени по време на практикума.
Окуражавам ви да си решите всички задачи и след упражнението, обаче все пак имам лимитирано време, ако искате можете да се свържете с мен за работата ви по някоя от тях, но не гарантирам кога ще мога да го видя.
-&]
-
-&[slide
+:slide
## Оплаквайте се!
+.bulleted
- За първи път водя практикум (и никога не съм преподавал формално)
- Задачите сам си ги измислям
Ако задачите са трудни, зле направени, ако нещо не обяснявам като хората, изобщо ако нещо не е ок, свържете се с мен, ще го обсъдим.
-&.br3
+[$br3]
## Помагайте си!
+.bulleted
- Аз съм един, вие сте >20
-<br>
+\n
Със сигурност няма да успея да помогна на всеки по всяко време от практикума, не се страхувайте да питате съседите си за помощ.
-&]
-
-
-&[slide
+:slide
## Няколко съвета в позицията ми на третокурсник
-&.br2
+[$br2]
-&(font35
-
-- **НЕ плагиатствайте!**
- **НЕ си качвайте решенията на контролни или домашни онлайн!**
+:font35
+:unordered
+- =[НЕ плагиатствайте!]=
+ =[НЕ си качвайте решенията на контролни или домашни онлайн!]=
Формално плагиатството е незаконно, ако някой Ви направи доклад, възможно е да бъдете изключени.
-- **Следвайте материала, който ви се преподава!**
+- =[Следвайте материала, който ви се преподава!]=
За хората с опит, ще дойде време когато ще искате да приложите лични знания и практики.
Ако не е казано някъде, не го правите и не го обмисляте!
-&) &]
-&[title
+:title_slide
# Въпроси ?
-&]
-
-
-&[title
+:title_slide
# ФМИ в контекста на програмирането
Или защо учим толкова много математика
-&.br2
+[$br2]
-&(font22
-Ще си позволя едно отклонение.
-Искам да обясня как **аз лично** виждам
+:font22
+Ще си позволя едно отклонение.\n
+Искам да обясня как =[аз лично]= виждам\n
математиката в компютърния свят.
-&)
-
-&]
-&[slide
+:slide
## В КН2 има много и трудна математика
-&{row
+:row
-&(width35%
-![](./img/u4-mat-hard.gif)
-&)
+.width35% [image ./img/u4-mat-hard.gif]
-&{column
-
-- Жълто - математически предмет
+:column
+.bulleted
+- Жълто - математически предмет\n
- Червено - проблемни предмети
-<br>
+\n
+.bulleted
- Всички проблемни предмети също са математики
- Към половината предмети са математики
- Почти всички проблемни са наблъскани в 1ви курс
-&}
-&}
-&]
-&[slide
+:slide
## Защо учим толкова много математика?
+.p
Има добра причина, има директни и основни приложения в компютрите, и без тях до никъде нямаше да сме стигнали.
Нека обясня защо:
### Дискретни структури
+.p
Смесица на уводите в няколко предмета:
-&{row
+:row
-&(font35
-![](https://upload.wikimedia.org/wikipedia/commons/9/99/ClaudeShannon_MFO3807.jpg?20190622223728)
-Claude Shannon
-&)
+.font35
+[image https://upload.wikimedia.org/wikipedia/commons/9/99/ClaudeShannon_MFO3807.jpg?20190622223728 Claude Shannon]
-&{column
+:column
-- **Булева алгебра**: как работим с истина/лъжа, с 0/1
+:unordered
+- =[Булева алгебра]=: как работим с истина/лъжа, с 0/1
- - Доказана е [еквивалентност между ел. вериги и булевата алгебра](https://en.wikipedia.org/wiki/A_Symbolic_Analysis_of_Relay_and_Switching_Circuits).
+ .bulleted
+ - Доказана е [url https://en.wikipedia.org/wiki/A_Symbolic_Analysis_of_Relay_and_Switching_Circuits еквивалентност между ел. вериги и булевата алгебра].
- Много типове данни и математически операции могат да се сведат до булева алгебра и работа с памет.
-&}
-&} &]
-&[slide
+:slide
### Дискретни структури (продължение)
-&.br1
+[$br1]
-- **Теория на множествата**: множество е някаква съвкупност от обекти
+:unordered
+- =[Теория на множествата]=: множество е някаква съвкупност от обекти
- - Позволява ни да третираме колекция от математически обекти като математически обект[^importance-of-sets].
+ .bulleted
+ 'footnote importance-of-sets [url https://math.stackexchange.com/a/536172 https://math.stackexchange.com/a/536172]
+ - Позволява ни да третираме колекция от математически обекти като математически обект[$importance-of-sets].
Използва се в основата на много математики; колкото са полезни те, толкова са и множествата.
-&.br2
+[$br2]
-- **Комбинаторика**[^importance-of-combinatorics]: изследва бройки на неща
+'footnote importance-of-combinatorics [url https://math.stackexchange.com/questions/2146051/where-do-combinatorics-play-a-role-in-computer-science https://math.stackexchange.com/questions/2146051/where-do-combinatorics-play-a-role-in-computer-science]
+- =[Комбинаторика]= [$importance-of-combinatorics]: изследва бройки на неща
+ .bulleted
- Често се ползва за анализ и дизайн на алгоритми и структури от данни
- Употребява се при оптимизации и теория на кодирането (компресиране на данни, отстраняване на грешки, криптография)
- Есенциална в теория на графите
-&]
-
-&[slide
+:slide
### Дискретни структури (продължение)
-&.br5
-
-- **Теория на графите**: граф е съвкупност от някакви обекти и връзки между тях.
+[$br5]
+:unordered
+- =[Теория на графите]=: граф е съвкупност от някакви обекти и връзки между тях.
+ .bulleted
- Позволява моделиране на много естествени структури: интернет мрежите, географски карти (места и пътищата между тях), йерархии, биологически мрежи и так. нат.
- - Използва се във важни структури от данни като [heap](https://en.wikipedia.org/wiki/Heap_%28data_structure%29) (и интересната [fibonacci heap](https://www.youtube.com/watch?v=6JxvKfSV9Ns)) и [trie](https://en.wikipedia.org/wiki/Trie)
+ - Използва се във важни структури от данни като [url https://en.wikipedia.org/wiki/Heap_%28data_structure%29 heap] (и интересната [url https://www.youtube.com/watch?v=6JxvKfSV9Ns fibonacci heap]) и [url https://en.wikipedia.org/wiki/Trie trie]
-&]
-
-&[slide
+:slide
### Езици, автомати и изчислимост
-&.br5
+[$br5]
-&{row
+:row
-&(font35
-&(width85% ![](https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Kleene.jpg/421px-Kleene.jpg?20230630215747) &)
-Stephen Kleene
-&)
+:font35
-&{column
+.width85% [image https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Kleene.jpg/421px-Kleene.jpg?20230630215747]
-Това е част от материала в по-общото "theoretical computer science".
-Можем формално да опишем и работим с теоретични компютри и програми.
+.p Stephen Kleene
-- Позволява ни да използваме математика за създаване, обработка и доказване на програми
-&}
+:column
-&}
-&]
+.p
+Това е част от материала в по-общото "theoretical computer science".\n
+Можем формално да опишем и работим с теоретични компютри и програми.
+.bulleted
+- Позволява ни да използваме математика за създаване, обработка и доказване на програми
-&[slide
-&.br1
+:slide
+
+[$br1]
### Алгебра 1
Линейни уравнения и операции върху тях.
+.bulleted
- Линейни уравнения и матрици се срещат сравнително често в софтуер
- Основоположна в компютърната графика
- Много използвана в machine learning
-&.br3
+[$br3]
### Диференциално и интегрално смятане
Разглежда функции и по-общо, непрекъснатата промяна на стойности.
+.bulleted
- Част от компютърната графика (особено обработка на изображения)
- Напреднал machine learning, главно заради употребата на статистиката (която на свой ред се основава на линейната алгебра)
- Анализ на алгоритми
-&]
-
-
-&[slide35
+:slide35
## В по-общ план
Какво не би било възможно без математика в софтуер:
+.bulleted
- компютрите
- компютърната графика (особено 3D)
- интернет
@@ -373,59 +355,54 @@ Stephen Kleene
- самолетни системи и инженерство
- ...
-Математиката е **неразделима** част от софтуера!
+.p
+Математиката е =[неразделима]= част от софтуера!\n
Друг е въпросът дали на вас лично ще ви се налага да я използвате...
-&]
-
-
-&[slide
+:slide
## Какво означава да пишеш софтуер?
+.bulleted
- Инженерите и физиците са създали компютрите, едни специални калкулатори с много памет
- Математиката представя света с абстрактни модели/шаблони
- Компютърната наука свързва теоретичната математика с физичната машина
-<span></span>
+.p
-- Най-великият труд на тази дисциплина е постигнат чрез **синхрон** между тези три предмета
+.bulleted
+- Най-великият труд на тази дисциплина е постигнат чрез =[синхрон]= между тези три предмета
- &(centered &(width60% &{row
-
- ![](https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Black_hole_-_Messier_87_crop_max_res.jpg/600px-Black_hole_-_Messier_87_crop_max_res.jpg)
-
- ![](https://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Internet_map_1024.jpg/600px-Internet_map_1024.jpg?20121030160606)
-
- &} &) &)
+:centered
+:width60%
+:row
-&]
+.p [image https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Black_hole_-_Messier_87_crop_max_res.jpg/600px-Black_hole_-_Messier_87_crop_max_res.jpg]
+.p [image https://upload.wikimedia.org/wikipedia/commons/thumb/d/d2/Internet_map_1024.jpg/600px-Internet_map_1024.jpg?20121030160606]
-&[title35
-# Означава да създадеш<br>deus ex machina
-С други думи, позволява ни да разрешим неразрешими проблеми
-&]
+:title_slide35
-&[title35
+# Означава да създадеш\ndeus ex machina
-# [Достатъчно философия, сега ще конфигурираме всичко нужно за първото ни упражнение](./setup.html)
+С други думи, позволява ни да разрешим неразрешими проблеми
-&]
-### Употреба на изображения
+:title_slide35
+
+# [url ./setup.html Достатъчно философия, сега ще конфигурираме всичко нужно за първото ни упражнение]
-Снимки на [Claude Shannon](https://upload.wikimedia.org/wikipedia/commons/9/99/ClaudeShannon_MFO3807.jpg?20190622223728) и [Stephen Cole Kleen](https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Kleene.jpg/421px-Kleene.jpg?20230630215747), предоставени от Konrad Jacobs с авторско право от [MFO](https://opc.mfo.de/), лицензирано с [CC BY-SA 2.0 DE](https://creativecommons.org/licenses/by-sa/2.0/de/deed.en) в Уикипедия.
-Снимка на черната дупка Messier 87, предоставена от [ESO](https://www.eso.org/public/) с лиценз [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/deed.en) в [Уикипедия](https://en.wikipedia.org/wiki/File:Black_hole_-_Messier_87_crop_max_res.jpg).
+### Употреба на изображения
+
+Снимки на [url https://upload.wikimedia.org/wikipedia/commons/9/99/ClaudeShannon_MFO3807.jpg?20190622223728 Claude Shannon] и [url https://upload.wikimedia.org/wikipedia/commons/thumb/1/1c/Kleene.jpg/421px-Kleene.jpg?20230630215747 Stephen Cole Kleen], предоставени от Konrad Jacobs с авторско право от [url https://opc.mfo.de/ MFO], лицензирано с [url https://creativecommons.org/licenses/by-sa/2.0/de/deed.en CC BY-SA 2.0 DE] в Уикипедия.
-Изображение на интернет мрежата направено от [Matt Britt](https://en.wikipedia.org/wiki/User:Matt_Britt) с данни от [The Opte Project](https://www.opte.org/), лицензирано с [CC BY 2.5](https://creativecommons.org/licenses/by/2.5/deed.en) в [Уикипедия](https://commons.wikimedia.org/wiki/File:Internet_map_1024.jpg).
+Снимка на черната дупка Messier 87, предоставена от [url https://www.eso.org/public/ ESO] с лиценз [url https://creativecommons.org/licenses/by/4.0/deed.en CC BY 4.0] в [url https://en.wikipedia.org/wiki/File:Black_hole_-_Messier_87_crop_max_res.jpg Уикипедия].
-[^importance-of-sets]: [https://math.stackexchange.com/a/536172](https://math.stackexchange.com/a/536172)
-[^importance-of-combinatorics]: [https://math.stackexchange.com/questions/2146051/where-do-combinatorics-play-a-role-in-computer-science](https://math.stackexchange.com/questions/2146051/where-do-combinatorics-play-a-role-in-computer-science)
+Изображение на интернет мрежата направено от [url https://en.wikipedia.org/wiki/User:Matt_Britt Matt Britt] с данни от [url https://www.opte.org/ The Opte Project], лицензирано с [url https://creativecommons.org/licenses/by/2.5/deed.en CC BY 2.5] в [url https://commons.wikimedia.org/wiki/File:Internet_map_1024.jpg Уикипедия].
diff --git a/src/teaching/upp-2023/week10/index.du b/src/teaching/upp-2023/week10/index.du
new file mode 100644
index 0000000..04889c4
--- /dev/null
+++ b/src/teaching/upp-2023/week10/index.du
@@ -0,0 +1,91 @@
+# Задачи - УПП, Седмица 10, 15.12.2023
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/EJcTQRz4 classroom.github.com/a/EJcTQRz4]
+
+.important Във всички задачи =[трябва]= да използвате рекурсия!
+
+## Задача 1
+
+Най-големия общ делител на числата `[a]` и `[b]` е най-голямото, число което ги дели без остатък.
+Евклидовият алгоритъм се базира на факта, че за две положителни числа `[a]` и `[b]`, като `[a > b]`, НОД на `[a]` и `[b]` е същия като НОД на `[a - b]` и `[b]` и когато `[a = b]`, тогава НОД на `[a]` и `[b]` е тяхната стойност.
+
+От входа получавате две цели положителни числа и трябва да изкарате техния НОД, чрез алгоритъма на Евклид =[имплементиран с рекурсия]=.
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:6 6 :||:6 :|
+|:48 18:||:6 :|
+
+## Задача 2
+
+От входа получавате неотрицателно число `[N]`, което ще бъде някое число на Фибоначи.
+Трябва да върнете кое по ред е, като 0 е нулевото, 1 е първото, 2 е третото, 3 е четвъртото и так. нат.
+Напомням, че математически фибоначи се дефинира така:
+
+.comment
+\begin{align*}
+F_n = \left\{ \begin{array}{ll}
+0, & n=0 \\
+1, & n=1 \\
+F_{n-1} + F_{n-2} & \text{иначе} \\
+\end{array} \right.
+\end{align*}
+
+[image ./img/fib.png F(0) = 0; F(1) = 1; F(n) = F(n-1) + F(n-2)]
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:0 :||:0 :|
+|:1 :||:1 :|
+|:3 :||:4 :|
+|:144 :||:12 :|
+|:1597 :||:17 :|
+|:46368:||:24 :|
+
+## Задача 3
+
+От входа получавате положително число `[N]`, трябва да изкарате на екрана "рисунка", показваща формата на пясъчен часовник с височина `[2N]` (вижте примерите).
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:1 :||:<pre>+\n#</pre>:|
+|:2 :||:<pre>+++\n +\n #\n###</pre>:|
+|:3 :||:<pre>+++++\n +++\n +\n #\n ###\n#####</pre>:|
+|:5 :||:<pre>+++++++++\n +++++++\n +++++\n +++\n +\n #\n ###\n #####\n #######\n#########</pre>:|
+
+## Задача 4
+
+От входа получавате число `[N]`, след това тябва да изкарате на нови редове, в нарастващ ред, всички двоични числа, които могат да се представят с `[N]`-бита.
+Вкарвате и водещи нули, тоест всяко число е съставено от точно `[N]` букви (`[N]` нули и единици).
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:1 :||:0\n1:|
+|:2 :||:00\n01\n10\n11:|
+|:3 :||:000\n001\n010\n011\n100\n101\n110\n111:|
+|:4 :||:0000\n0001\n...\n0111\n1000\n1001\n...\n1101\n1110\n1111:|
+
+## Задача 5
+
+Получавате един ред от терминала, в който ще имате скоби, знакът `[+]` и `[*]`, шпации и числа.
+Това е прост математически израз, трябва да изкарате резултата след неговото пресмятане, като винаги около `[число + число]` и `[число * число]` има скоби (тоест не е нужно да се притеснявате от приоритет и асоциативност).
+
+За удобство спокойно може да ползвате `[atoi]` за конверитране на числовите части от низа в числа.
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:(1 + 2):||:3 :|
+|:((2 + 9) * 3):||:33:|
+|:(((8 * 1) * (56 + 4)) + (19 * 2)):||:518:|
diff --git a/src/teaching/upp-2023/week10/index.md b/src/teaching/upp-2023/week10/index.md
deleted file mode 100644
index 722e705..0000000
--- a/src/teaching/upp-2023/week10/index.md
+++ /dev/null
@@ -1,90 +0,0 @@
-# Задачи - УПП, Седмица 10, 15.12.2023
-
-GitHub classroom: [classroom.github.com/a/EJcTQRz4](https://classroom.github.com/a/EJcTQRz4)
-
-&:important Във всички задачи **трябва** да използвате рекурсия!
-
-## Задача 1
-
-Най-големия общ делител на числата `a` и `b` е най-голямото, число което ги дели без остатък.
-Евклидовият алгоритъм се базира на факта, че за две положителни числа `a` и `b`, като `a > b`, НОД на `a` и `b` е същия като НОД на `a - b` и `b` и когато `a = b`, тогава НОД на `a` и `b` е тяхната стойност.
-
-От входа получавате две цели положителни числа и трябва да изкарате техния НОД, чрез алгоритъма на Евклид **имплементиран с рекурсия**.
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|6 6 |6 |
-|48 18|6 |
-
-## Задача 2
-
-От входа получавате неотрицателно число `N`, което ще бъде някое число на Фибоначи.
-Трябва да върнете кое по ред е, като 0 е нулевото, 1 е първото, 2 е третото, 3 е четвъртото и так. нат.
-Напомням, че математически фибоначи се дефинира така:
-
-<!--
-\begin{align*}
-F_n = \left\{ \begin{array}{ll}
-0, & n=0 \\
-1, & n=1 \\
-F_{n-1} + F_{n-2} & \text{иначе} \\
-\end{array} \right.
-\end{align*}
--->
-
-![F(0) = 0; F(1) = 1; F(n) = F(n-1) + F(n-2)](./img/fib.png)
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|0 |0 |
-|1 |1 |
-|3 |4 |
-|144 |12 |
-|1597 |17 |
-|46368|24 |
-
-## Задача 3
-
-От входа получавате положително число `N`, трябва да изкарате на екрана "рисунка", показваща формата на пясъчен часовник с височина `2N` (вижте примерите).
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|1 |<pre>+<br>#</pre>|
-|2 |<pre>+++<br> +<br> #<br>###</pre>|
-|3 |<pre>+++++<br> +++<br> +<br> #<br> ###<br>#####</pre>|
-|5 |<pre>+++++++++<br> +++++++<br> +++++<br> +++<br> +<br> #<br> ###<br> #####<br> #######<br>#########</pre>|
-
-## Задача 4
-
-От входа получавате число `N`, след това тябва да изкарате на нови редове, в нарастващ ред, всички двоични числа, които могат да се представят с `N`-бита.
-Вкарвате и водещи нули, тоест всяко число е съставено от точно `N` букви (`N` нули и единици).
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|1 |0<br>1|
-|2 |00<br>01<br>10<br>11|
-|3 |000<br>001<br>010<br>011<br>100<br>101<br>110<br>111|
-|4 |0000<br>0001<br>...<br>0111<br>1000<br>1001<br>...<br>1101<br>1110<br>1111|
-
-## Задача 5
-
-Получавате един ред от терминала, в който ще имате скоби, знакът `+` и `*`, шпации и числа.
-Това е прост математически израз, трябва да изкарате резултата след неговото пресмятане, като винаги около `число + число` и `число * число` има скоби (тоест не е нужно да се притеснявате от приоритет и асоциативност).
-
-За удобство спокойно може да ползвате `atoi` за конверитране на числовите части от низа в числа.
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|(1 + 2)|3 |
-|((2 + 9) * 3)|33|
-|(((8 * 1) * (56 + 4)) + (19 * 2))|518|
diff --git a/src/teaching/upp-2023/week11/index.du b/src/teaching/upp-2023/week11/index.du
new file mode 100644
index 0000000..3f7d8f8
--- /dev/null
+++ b/src/teaching/upp-2023/week11/index.du
@@ -0,0 +1,129 @@
+# Задачи - УПП, Седмица 11, 22.12.2023
+
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/cZRnZj9y classroom.github.com/a/cZRnZj9y]
+
+.important Във всички задачи =[трябва]= да използвате рекурсия!
+
+.warn Някои задачи се повтарят с тези от миналия път, ако преди не сте ги решили, сега ги решете
+
+## Алтернативни задачи
+
+Считайте [url https://github.com/ivanahristova/introduction-to-programming-2023-2024/tree/main/sem11#%D0%B7%D0%B0%D0%B4%D0%B0%D1%87%D0%B8 задачите от семинара] като задачи преди тези.
+Тоест, за хората които се затрудняват повечко, решете семинарните и след това се върнете тук.
+Разбира се, ще помагам и със семинарните задачи.
+
+## Задача 1
+
+От входа получавате неотрицателно число `[N]`, което ще бъде някое число на Фибоначи.
+Трябва да върнете кое по ред е, като 0 е нулевото, 1 е първото, 2 е третото, 3 е четвъртото и так. нат.
+
+Напомням, че нормално Фибоначи се дефинира като редица, която започва с числата 0 и 1, и всяко следващо е сумата на предходните две.
+Тоест, нулевото число е 0, първото 1, второто е `[0 + 1 = 1]` (понеже 1 се повтаря, зачитаме го за първото число), третото е `[1 + 1 = 2]`, четвъртото е `[1 + 2 = 3]` и так. нат.
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:0 :||:0 :|
+|:1 :||:1 :|
+|:3 :||:4 :|
+|:144 :||:12 :|
+|:1597 :||:17 :|
+|:46368:||:24 :|
+
+## Задача 2
+
+От входа получавате положително число `[N]`, трябва да изкарате на екрана "рисунка" на триъгълници.
+
+### a) горен триъгълник
+
+Рисунката е един правоъгълен равнобедрен триъгълник от знака `[+]`, като `[N]` определя размера на равнобедрените страни (вижте примерите).
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:1 :||:<pre>+</pre>:|
+|:2 :||:<pre>+\n++</pre>:|
+|:3 :||:<pre>+\n++\n+++</pre>:|
+|:5 :||:<pre>+\n++\n+++\n++++\n+++++</pre>:|
+
+### б) долен триъгълник
+
+Подобно на предходната подточка, обаче обърнат по хоризонтала, и със знака `[#]`.
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:1 :||:<pre>#</pre>:|
+|:2 :||:<pre>##\n#</pre>:|
+|:3 :||:<pre>###\n##\n#</pre>:|
+|:5 :||:<pre>#####\n####\n###\n##\n#</pre>:|
+
+### в) пълен триъгълник
+
+=[Използвайки само една рекурсивна функция,]= сега трябва да изкарате първо горния триъгълник и след това долния.
+Ако просто извикате предходните две функции една след друга, задачата се обезсмисля.
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:1 :||:<pre>+\n#</pre>:|
+|:2 :||:<pre>+\n++\n##\n#</pre>:|
+|:3 :||:<pre>+\n++\n+++\n###\n##\n#</pre>:|
+|:5 :||:<pre>+\n++\n+++\n++++\n+++++\n#####\n####\n###\n##\n#</pre>:|
+
+## Задача 3
+
+Направете програма която разрешава проблема с [url https://en.wikipedia.org/wiki/Ages_of_Three_Children_puzzle възрастта на трите деца].
+
+Една жена има три деца за които знаем три неща: умножението на техните възрасти, сбора на техните възрасти и факта, че има едно дете, което е най-голямо.
+Трябва да намерите възрастта на всяко дете, само по тази информация.
+
+Разбира се, от входа получавате две числа, съответно умножението и сбора на възрастите им.
+Трябва на екрана да изкарате три числа - възрастите на трите деца.
+
+=[Подсказка:]= най-лесното решение е да пробвате всички възможни възрасти, като избягвате техни пермутации
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:72 14:||:3 3 8:|
+|:36 13:||:2 2 9:|
+|:350 42:||:2 5 35:|
+
+## Задача 4
+
+От входа получавате число `[N]`, след това трябва да изкарате на нови редове, в нарастващ ред, всички двоични числа, които могат да се представят с `[N]`-бита.
+Вкарвате и водещи нули, тоест всяко число е съставено от точно `[N]` букви (`[N]` нули и единици).
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:1 :||:0\n1:|
+|:2 :||:00\n01\n10\n11:|
+|:3 :||:000\n001\n010\n011\n100\n101\n110\n111:|
+|:4 :||:0000\n0001\n...\n0111\n1000\n1001\n...\n1101\n1110\n1111:|
+
+## Задача 5
+
+Направете програма която разрешава [url https://en.wikipedia.org/wiki/Takuzu Такузо пъзели].
+
+Започвате с дъска 4х4, в тази дъска може да имате само цифрите 0 и 1, като няколко клетки вече идват с попълнени стойности (но повечето са празни).
+Обаче, на всяка колона и ред трябва да има еднакъв брой 0ли и 1ци, и не трябва да има повече от две последователни еднакви цифри (в реда или колоната).
+
+От входа получавате дъската, като с -1 обозначаваме празна клетка.
+
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:-1 1 -1 0\n-1 -1 0 -1\n-1 0 -1 -1\n1 1 -1 0:||:0 1 1 0\n1 0 0 1\n0 0 1 1\n1 1 0 0:|
+|:-1 0 1 -1\n1 -1 0 -1\n0 1 -1 -1\n0 0 1 -1:||:1 0 1 0\n1 1 0 0\n0 1 0 1\n0 0 1 1:|
+|:-1 0 -1 -1\n-1 0 0 -1\n0 -1 -1 -1\n-1 -1 -1 0:||:0 0 1 1\n1 0 0 1\n0 1 1 0\n1 1 0 0:|
diff --git a/src/teaching/upp-2023/week11/index.md b/src/teaching/upp-2023/week11/index.md
deleted file mode 100644
index 92ce89e..0000000
--- a/src/teaching/upp-2023/week11/index.md
+++ /dev/null
@@ -1,127 +0,0 @@
-# Задачи - УПП, Седмица 11, 22.12.2023
-
-GitHub classroom: [classroom.github.com/a/cZRnZj9y](https://classroom.github.com/a/cZRnZj9y)
-
-&:important Във всички задачи **трябва** да използвате рекурсия!
-
-&:warn Някои задачи се повтарят с тези от миналия път, ако преди не сте ги решили, сега ги решете
-
-## Алтернативни задачи
-
-Считайте [задачите от семинара](https://github.com/ivanahristova/introduction-to-programming-2023-2024/tree/main/sem11#%D0%B7%D0%B0%D0%B4%D0%B0%D1%87%D0%B8) като задачи преди тези.
-Тоест, за хората които се затрудняват повечко, решете семинарните и след това се върнете тук.
-Разбира се, ще помагам и със семинарните задачи.
-
-## Задача 1
-
-От входа получавате неотрицателно число `N`, което ще бъде някое число на Фибоначи.
-Трябва да върнете кое по ред е, като 0 е нулевото, 1 е първото, 2 е третото, 3 е четвъртото и так. нат.
-
-Напомням, че нормално Фибоначи се дефинира като редица, която започва с числата 0 и 1, и всяко следващо е сумата на предходните две.
-Тоест, нулевото число е 0, първото 1, второто е `0 + 1 = 1` (понеже 1 се повтаря, зачитаме го за първото число), третото е `1 + 1 = 2`, четвъртото е `1 + 2 = 3` и так. нат.
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|0 |0 |
-|1 |1 |
-|3 |4 |
-|144 |12 |
-|1597 |17 |
-|46368|24 |
-
-## Задача 2
-
-От входа получавате положително число `N`, трябва да изкарате на екрана "рисунка" на триъгълници.
-
-### a) горен триъгълник
-
-Рисунката е един правоъгълен равнобедрен триъгълник от знака `+`, като `N` определя размера на равнобедрените страни (вижте примерите).
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|1 |<pre>+</pre>|
-|2 |<pre>+<br>++</pre>|
-|3 |<pre>+<br>++<br>+++</pre>|
-|5 |<pre>+<br>++<br>+++<br>++++<br>+++++</pre>|
-
-### б) долен триъгълник
-
-Подобно на предходната подточка, обаче обърнат по хоризонтала, и със знака `#`.
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|1 |<pre>#</pre>|
-|2 |<pre>##<br>#</pre>|
-|3 |<pre>###<br>##<br>#</pre>|
-|5 |<pre>#####<br>####<br>###<br>##<br>#</pre>|
-
-### в) пълен триъгълник
-
-**Използвайки само една рекурсивна функция,** сега трябва да изкарате първо горния триъгълник и след това долния.
-Ако просто извикате предходните две функции една след друга, задачата се обезсмисля.
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|1 |<pre>+<br>#</pre>|
-|2 |<pre>+<br>++<br>##<br>#</pre>|
-|3 |<pre>+<br>++<br>+++<br>###<br>##<br>#</pre>|
-|5 |<pre>+<br>++<br>+++<br>++++<br>+++++<br>#####<br>####<br>###<br>##<br>#</pre>|
-
-## Задача 3
-
-Направете програма която разрешава проблема с [възрастта на трите деца](https://en.wikipedia.org/wiki/Ages_of_Three_Children_puzzle).
-
-Една жена има три деца за които знаем три неща: умножението на техните възрасти, сбора на техните възрасти и факта, че има едно дете, което е най-голямо.
-Трябва да намерите възрастта на всяко дете, само по тази информация.
-
-Разбира се, от входа получавате две числа, съответно умножението и сбора на възрастите им.
-Трябва на екрана да изкарате три числа - възрастите на трите деца.
-
-**Подсказка:** най-лесното решение е да пробвате всички възможни възрасти, като избягвате техни пермутации
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|72 14|3 3 8|
-|36 13|2 2 9|
-|350 42|2 5 35|
-
-## Задача 4
-
-От входа получавате число `N`, след това трябва да изкарате на нови редове, в нарастващ ред, всички двоични числа, които могат да се представят с `N`-бита.
-Вкарвате и водещи нули, тоест всяко число е съставено от точно `N` букви (`N` нули и единици).
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|1 |0<br>1|
-|2 |00<br>01<br>10<br>11|
-|3 |000<br>001<br>010<br>011<br>100<br>101<br>110<br>111|
-|4 |0000<br>0001<br>...<br>0111<br>1000<br>1001<br>...<br>1101<br>1110<br>1111|
-
-## Задача 5
-
-Направете програма която разрешава [Такузо пъзели](https://en.wikipedia.org/wiki/Takuzu).
-
-Започвате с дъска 4х4, в тази дъска може да имате само цифрите 0 и 1, като няколко клетки вече идват с попълнени стойности (но повечето са празни).
-Обаче, на всяка колона и ред трябва да има еднакъв брой 0ли и 1ци, и не трябва да има повече от две последователни еднакви цифри (в реда или колоната).
-
-От входа получавате дъската, като с -1 обозначаваме празна клетка.
-
-**Примери:**
-
-|Вход|Изход|
-|----|-----|
-|-1 1 -1 0<br>-1 -1 0 -1<br>-1 0 -1 -1<br>1 1 -1 0|0 1 1 0<br>1 0 0 1<br>0 0 1 1<br>1 1 0 0|
-|-1 0 1 -1<br>1 -1 0 -1<br>0 1 -1 -1<br>0 0 1 -1|1 0 1 0<br>1 1 0 0<br>0 1 0 1<br>0 0 1 1|
-|-1 0 -1 -1<br>-1 0 0 -1<br>0 -1 -1 -1<br>-1 -1 -1 0|0 0 1 1<br>1 0 0 1<br>0 1 1 0<br>1 1 0 0|
diff --git a/src/teaching/upp-2023/week12/index.md b/src/teaching/upp-2023/week12/index.du
index d914431..ed380cf 100644
--- a/src/teaching/upp-2023/week12/index.md
+++ b/src/teaching/upp-2023/week12/index.du
@@ -1,12 +1,14 @@
# Задачи - УПП, Седмица 12, 05.01.2024
-GitHub classroom: [classroom.github.com/a/KEDSxDjl](https://classroom.github.com/a/KEDSxDjl)
+\n
-&:important Във всички задачи **трябва** да използвате рекурсия!
+GitHub classroom: [url https://classroom.github.com/a/KEDSxDjl classroom.github.com/a/KEDSxDjl]
+
+.important Във всички задачи =[трябва]= да използвате рекурсия!
## Алтернативни задачи
-Считайте [задачите от семинара](https://github.com/ivanahristova/introduction-to-programming-2023-2024/tree/main/sem12) и [тези от миналия път](../week11/) като част от днешните задачи.
+Считайте [url https://github.com/ivanahristova/introduction-to-programming-2023-2024/tree/main/sem12 задачите от семинара] и [url ../week11/ тези от миналия път] като част от днешните задачи.
Тоест, за хората които се затрудняват повечко, решете ги и след това се върнете тук.
Разбира се, ще помагам и с тях.
@@ -19,20 +21,20 @@ GitHub classroom: [classroom.github.com/a/KEDSxDjl](https://classroom.github.com
Накрая получавате максималната обща тежест за раницата.
Трябва да изкарате на екрана максималната възможна обща ценност.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|3<br>1 4<br>2 5<br>3 1<br>4|3|
-|3<br>1 4<br>2 5<br>3 6<br>3|0|
-|6<br>50 56<br>50 59<br>64 80<br>46 64<br>50 75<br>5 17<br>190|150<!-- https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html -->|
+.table
+|=Вход=||=Изход=|
+|:3\n1 4\n2 5\n3 1\n4:||:3:|
+|:3\n1 4\n2 5\n3 6\n3:||:0:|
+|:6\n50 56\n50 59\n64 80\n46 64\n50 75\n5 17\n190:||:150<!-- https://people.sc.fsu.edu/~jburkardt/datasets/knapsack_01/knapsack_01.html -->:|
## Задача 2
Получавате N и M, съответно броя редове и колони в дъска.
Всяка клетка от дъската е пълна или празна.
-След това получавате NxM на брой символа за всяка клетка, като `-` означава празна клетка, докато `#` означава пълна.
+След това получавате NxM на брой символа за всяка клетка, като `[-]` означава празна клетка, докато `[#]` означава пълна.
Накрая получавате две числа - координати (започващи от нула, като 0,0 е горния-ляв ъгъл) в дъската.
От подадените координати трябва да запълните "фигурата" в която се намира (фигурата която огражда) дадената плочка.
@@ -40,13 +42,13 @@ GitHub classroom: [classroom.github.com/a/KEDSxDjl](https://classroom.github.com
Оцветяването да се случва само в 4те прави посоки (без диагонали).
-![](https://upload.wikimedia.org/wikipedia/commons/7/7e/Recursive_Flood_Fill_4_%28aka%29.gif)
+[image https://upload.wikimedia.org/wikipedia/commons/7/7e/Recursive_Flood_Fill_4_%28aka%29.gif]
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|5 11<br><pre>- - # # - - - - - - -<br>- # - - # - - - - - -<br># - - - - # # # # # #<br>- # - - # - - - # - #<br>- - # # - - - - - - -</pre>2 2|<pre>- - # # - - - - - - -<br>- # # # # - - - - - -<br># # # # # # # # # # #<br>- # # # # - - - # - #<br>- - # # - - - - - - -</pre>|
+.table
+|=Вход=||=Изход=|
+|:5 11\n<pre>- - # # - - - - - - -\n- # - - # - - - - - -\n# - - - - # # # # # #\n- # - - # - - - # - #\n- - # # - - - - - - -</pre>2 2:||:<pre>- - # # - - - - - - -\n- # # # # - - - - - -\n# # # # # # # # # # #\n- # # # # - - - # - #\n- - # # - - - - - - -</pre>:|
## Задача 3
@@ -56,54 +58,59 @@ GitHub classroom: [classroom.github.com/a/KEDSxDjl](https://classroom.github.com
Интересуваме се от такова поставяне на всички царици, че нито една няма да вземе никоя друга царица в един ход.
Пример:
-![](https://upload.wikimedia.org/wikipedia/commons/6/69/Solution_A_for_8_Queen_Puzzles.png)
+[image https://upload.wikimedia.org/wikipedia/commons/6/69/Solution_A_for_8_Queen_Puzzles.png]
Напишете програма, която намира броя на възможните такива поставяния на цариците.
От входа не получавате нищо.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-| |92 |
+.table
+|=Вход=||=Изход=|
+|: :||:92 :|
-**Бонус:** направете програмата да изкарва всяко решение
+=[Бонус:]= направете програмата да изкарва всяко решение
## Задача 4
-<!-- https://mathcenter.oxford.emory.edu/site/cs171/probSetUsingStacks/ -->
+.comment https://mathcenter.oxford.emory.edu/site/cs171/probSetUsingStacks/
-Нормално ние представяме математически операции чрез "инфиксен" запис, тоест операторът е по средата, между нещата върху които работи (пример: `1 + 2`).
-Обаче, това не е задължително, по обратната полска нотация винаги слагаме оператът след нещата върху които работи (пример: `1 2 +`).
+Нормално ние представяме математически операции чрез "инфиксен" запис, тоест операторът е по средата, между нещата върху които работи (пример: `[1 + 2]`).
+Обаче, това не е задължително, по обратната полска нотация винаги слагаме оператът след нещата върху които работи (пример: `[1 2 +]`).
Бонусът на това, е че не ни трябва скобуване и ред на операциите.
-В инфиксния израз `(2 + 3) * (2 ^^ 2)`, без скобите, сбора ще се извърши след умножението и степенуването ще се извърши след умножението.
-Обаче, ако искаме да изразим това в обратен полски запис, просто правим `2 3 + 2 2 ^^ *`.
-А ако искаме оригиналното действие, без скоби, записваме `2 3 2 * 2 ^^ +`.
+В инфиксния израз `[(2 + 3) * (2 ^^ 2)]`, без скобите, сбора ще се извърши след умножението и степенуването ще се извърши след умножението.
+Обаче, ако искаме да изразим това в обратен полски запис, просто правим `[2 3 + 2 2 ^^ *]`.
+А ако искаме оригиналното действие, без скоби, записваме `[2 3 2 * 2 ^^ +]`.
Ако изглежда объркващо, идеята е че всеки оператор работи върху предходните две стойности, изчисляваме изразите от ляво надясно и заместваме веднага.
-Тоест, при последния пример, пропускаме първите три числа, стигаме до `*`, умножаваме последните две и заместваме трите неща (`3 2 *`) с резултата, следователно имаме `2 6 2 ^^ +`, пропускаме две, стигаме до `^^` и так.нат.
+Тоест, при последния пример, пропускаме първите три числа, стигаме до `[*]`, умножаваме последните две и заместваме трите неща (`[3 2 *]`) с резултата, следователно имаме `[2 6 2 ^^ +]`, пропускаме две, стигаме до `[^^]` и так.нат.
+
+Направете програма, която чисто рекурсивно изчислиява изрази в обратен полски запис, който поддържа цели числа и операциите събиране, умножение, деление, изваждане и степенуване (за степенуване ще използваме знакът `[^]`).
+
+.important Обаче, за едно извикване на рекурсивната функция, може да пазите само един елемент на израза (число или оператор)!
+
+Изразът винаги завършва на знака `[$]`.
-Направете програма, която чисто рекурсивно изчислиява изрази в обратен полски запис, който поддържа цели числа и операциите събиране, умножение, деление, изваждане и степенуване (за степенуване ще използваме знакът `^`).
+:warn
+Относно вход/изход, понеже няма как да знаем дали i-тата стойност е число или знак (операция), трябва да използваме функцията `[std::cin.fail()]`, която връща булева стойност, която ни казва дали записването на входа е било успешно.\n\n
-&:important Обаче, за едно извикване на рекурсивната функция, може да пазите само един елемент на израза (число или оператор)!
+Тоест, може винаги да запазвате входа в целочислен тип, когато стигнете до знак `[std::cin.fail()]` ще върне `[true]`.
+След това трябва да "забравите" за грешката чрез `[std::cin.clear()]` и може втори път да запазите входа (провалените данни ще се препрочетат) в променлива от знаков тип.\n\n
-Изразът винаги завършва на знака `$`.
+Но това поражда друг проблем, понеже записваме в целочислен тип, когато въведем `[+]` или `[-]`, `[std::cin]` ще очаква това да е водещ знак на число, и ще продължи да чака входа докато не въведем друг знак, тоест `[+]` и `[-]` ще бъдат пропуснати.
+Като компромисен вариант, просто пред тях винаги ще слагаме `[']` и в кода ще го пропускаме.
-&:warn Относно вход/изход, понеже няма как да знаем дали i-тата стойност е число или знак (операция), трябва да използваме функцията `std::cin.fail()`, която връща булева стойност, която ни казва дали записването на входа е било успешно.<br>
- Тоест, може винаги да запазвате входа в целочислен тип, когато стигнете до знак `std::cin.fail()` ще върне `true`.
- След това трябва да "забравите" за грешката чрез `std::cin.clear()` и може втори път да запазите входа (провалените данни ще се препрочетат) в променлива от знаков тип.<br>
- Но това поражда друг проблем, понеже записваме в целочислен тип, когато въведем `+` или `-`, `std::cin` ще очаква това да е водещ знак на число, и ще продължи да чака входа докато не въведем друг знак, тоест `+` и `-` ще бъдат пропуснати.
- Като компромисен вариант, просто пред тях винаги ще слагаме `'` и в кода ще го пропускаме.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|1 2 &apos;+ 3 / $|1|
-|1 4 3 2 ^ * &apos;+ 14 7 / &apos;- $|35|
+.table
+|=Вход=||=Изход=|
+|:1 2 '+ 3 / $:||:1:|
+|:1 4 3 2 ^ * '+ 14 7 / '- $:||:35:|
## Attribution
-- Анимация в [Задача 2](#2) от André Karwath (Aka) на [Уикипедия](https://commons.wikimedia.org/w/index.php?curid=481651) под лиценз CC BY-SA 2.5
-- Изображение на шахматна дъска в [Задача 3](#3) от Encik Tekateki в [Уикипедия](https://commons.wikimedia.org/w/index.php?curid=77832290) под лиценз CC BY-SA 4.0
+.bulleted
+- Анимация в [url #2 Задача 2] от André Karwath (Aka) на [url https://commons.wikimedia.org/w/index.php?curid=481651 Уикипедия] под лиценз CC BY-SA 2.5
+- Изображение на шахматна дъска в [url #3 Задача 3] от Encik Tekateki в [url https://commons.wikimedia.org/w/index.php?curid=77832290 Уикипедия] под лиценз CC BY-SA 4.0
diff --git a/src/teaching/upp-2023/week13/index.md b/src/teaching/upp-2023/week13/index.du
index f0e4b9a..da52d46 100644
--- a/src/teaching/upp-2023/week13/index.md
+++ b/src/teaching/upp-2023/week13/index.du
@@ -1,10 +1,12 @@
# Задачи - УПП, Седмица 13, 12.01.2024
-GitHub classroom: [classroom.github.com/a/bgiFD6SB](https://classroom.github.com/a/bgiFD6SB)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/bgiFD6SB classroom.github.com/a/bgiFD6SB]
## Алтернативни задачи
-Считайте [задачите от семинара](https://github.com/ivanahristova/introduction-to-programming-2023-2024/tree/main/sem13) и [тези от миналия път](../week12/) като част от днешните задачи.
+Считайте [url https://github.com/ivanahristova/introduction-to-programming-2023-2024/tree/main/sem13 задачите от семинара] и [url ../week12/ тези от миналия път] като част от днешните задачи.
Тоест, за хората които се затрудняват повечко, решете ги и след това се върнете тук.
Разбира се, ще помагам и с тях.
@@ -18,12 +20,12 @@ GitHub classroom: [classroom.github.com/a/bgiFD6SB](https://classroom.github.com
Всяка дума е на нов ред и е съставена от малки латински букви.
Ако има няколко думи с еднаква "близкост", изкарайте последната от тях.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|5<br>cate<br>cot<br>dog<br>cote<br>co<br>cat|cot|
-|4<br>nask<br>nmaskl<br>msdal<br>task<br>mask|task|
+.table
+|=Вход=||=Изход=|
+|:5\ncate\ncot\ndog\ncote\nco\ncat:||:cot:|
+|:4\nnask\nnmaskl\nmsdal\ntask\nmask:||:task:|
## 2 задача
@@ -34,21 +36,22 @@ GitHub classroom: [classroom.github.com/a/bgiFD6SB](https://classroom.github.com
Редовете са разбъркани, изкарайте първо име и фамилия на хората с най-много продадени продукти.
Ако има няколко хора, които са продали най-много продукти, изкарайте имената им в азбучен ред, първо по фамилия, после по име.
-Използвайте **само една функция за сортиране!**
+Използвайте =[само една функция за сортиране!]=
Като подсказка, използвайте указатели към функции за да променяте как тя работи.
-&:question Какво свойство трябва да е изпълнено за сортиращата функция?
+.question Какво свойство трябва да е изпълнено за сортиращата функция?
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|Antony Garcia 10<br>John Doe 9<br>Joseph Carmichael 10<br>Steven Wayne 1<br>Bob Carmichael 10<br>Holy Wilson 9|Bob Carmichael<br>Joseph Carmichael<br>Antony Garcia|
+.table
+|=Вход=||=Изход=|
+|:Antony Garcia 10\nJohn Doe 9\nJoseph Carmichael 10\nSteven Wayne 1\nBob Carmichael 10\nHoly Wilson 9:||:Bob Carmichael\nJoseph Carmichael\nAntony Garcia:|
## 3 задача
Ще дефинираме обвито изречение, като редица от букви, за които са изпълнени следните правила:
+:unordered
- първата е главна
- последната е точка
- между тях има само малки букви, цифри и шпации
@@ -56,12 +59,12 @@ GitHub classroom: [classroom.github.com/a/bgiFD6SB](https://classroom.github.com
Тоест за всяко изречение са избрани максимален брой колони, и знаците са обвити, така че да се поберат.
Примерно, ако имахме изречението "Hello world." и бяхме избрали 5 колони, тогава получаваме:
-
+
```
Hello
worl
d.
- ```
+
От входа получавате N и M, те съответстват на матрица от символи с N реда и M колони.
В матрицата имате обвити изречения, подредени по такъв начин, че между съседни има със сигурност поне една шпация (която действа като разделител).
@@ -70,30 +73,28 @@ GitHub classroom: [classroom.github.com/a/bgiFD6SB](https://classroom.github.com
```
A B
. .
-```
тогава двете ни изречения са:
```
B.
A .
-```
Изкарайте на конзолата всички обвити изречения в матрицата (редът им няма значение).
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|<pre>7 13<br>Thi A Someth<br>s i n ing. <br>s c . <br>ool <br>. Good Hel<br> luc lo.<br>Ha. k. <br></pre>|Something.<br>An.<br>This is cool.<br>Hello.<br>Good luck.<br>Ha.<br>|
-|<pre>2 7<br>B A.<br>. </pre>|<pre>A.<br>B .</pre>|
-|<pre>3 7<br> A.<br>B <br>. </pre>|<pre>A.<br>B .</pre>|
-|<pre>4 7<br> A.<br> <br>B <br>. </pre>|<pre>A.<br>B .</pre>|
-|<pre>3 6<br>Big <br>jumper<br>. </pre>|<pre>Big jumper.</pre>|
+.table
+|=Вход=||=Изход=|
+|:<pre>7 13\nThi A Someth\ns i n ing. \ns c . \nool \n. Good Hel\n luc lo.\nHa. k. \n</pre>:||:Something.\nAn.\nThis is cool.\nHello.\nGood luck.\nHa.\n:|
+|:<pre>2 7\nB A.\n. </pre>:||:<pre>A.\nB .</pre>:|
+|:<pre>3 7\n A.\nB \n. </pre>:||:<pre>A.\nB .</pre>:|
+|:<pre>4 7\n A.\n \nB \n. </pre>:||:<pre>A.\nB .</pre>:|
+|:<pre>3 6\nBig \njumper\n. </pre>:||:<pre>Big jumper.</pre>:|
## 4 задача
-В префиксния (или полския) запис слагаме оператора за смятане пред (в ляво от) елементите върху които работи (нормален запис - `1 + 2`, полски запис - `+ 1 2`).
+В префиксния (или полския) запис слагаме оператора за смятане пред (в ляво от) елементите върху които работи (нормален запис - `[1 + 2]`, полски запис - `[+ 1 2]`).
Ще разглеждаме "многоредови" изрази в полски запис, тоест изрази в които има няколко реда от целочислени стойности, така че трябва да се изчислят няколко израза с еднаква "форма", но различни стойности.
Един такъв израз изглежда така:
@@ -102,10 +103,9 @@ A .
+ 1 2
3 4
5 6 .
-```
Точката на края на последния ред задава край на израза.
-В този пример ще изчислим `1 + 2`, `3 + 4` и `5 + 6`, тоест ще "върне" три стойности: 3, 7 и 11.
+В този пример ще изчислим `[1 + 2]`, `[3 + 4]` и `[5 + 6]`, тоест ще "върне" три стойности: 3, 7 и 11.
Всяка колона в израза е от един и същи "тип", тоест в една колона винаги ще има числова стойност или някакъв знак.
С изключение на точката, всеки знак може да се постави на произволен ред (обаче в една колона не може да има повече от един знак).
@@ -115,12 +115,11 @@ A .
1 - 2 2 63
+ 3 4 7 7
5 6 * 8 9 .
-```
-Това ще изчисли `1 + (2 - 2 * 63)`, `3 + (4 - 7 * 7)` и `5 + (6 - 8 * 9)`.
+Това ще изчисли `[1 + (2 - 2 * 63)]`, `[3 + (4 - 7* 7)]` и `[5 + (6 - 8 * 9)]`.
Израза би направил същото нещо ако примерно всички знаци бяха на първия ред или на последния.
-От входа получавате няколко такива израза, докато не получите знака `$`.
+От входа получавате няколко такива израза, докато не получите знака `[$]`.
Може да достъпвате стойност от предходни изрази чрез синтаксиса "ИНДЕКС.ИНДЕКС", където индексите са от 0, първия определя номера на израза, докато втория определя коя стойност искаме.
Примерно:
@@ -130,16 +129,15 @@ A .
+ 3 4
5 6 .
* 0.0 0.2 .
-```
В последния израз умножаваме от нулевия израз, първата и третата стойност, тоест умножаваме 3 и 11.
Накрая трябва да изкарате всички стойности от последния израз.
-&:warn Погледнете пояснението за вход/изход от [последната задача от миналия път](../week12/#4).
+.warn Погледнете пояснението за вход/изход от [url ../week12/#4 последната задача от миналия път].
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|<pre> 1 5<br>+ 2 6<br> 3 7<br> 4 8 .<br>- 0.3 0.2 .<br>* 1.0 0.1 .<br> 1.0 3 0.2 3<br> - 3 0.3 0.1 1.0<br>* 0.0 2.0 / 2.0 0.1 .<br>$<br></pre>|-3 -36 -20|
+.table
+|=Вход=||=Изход=|
+|:<pre> 1 5\n+ 2 6\n 3 7\n 4 8 .\n- 0.3 0.2 .\n* 1.0 0.1 .\n 1.0 3 0.2 3\n - 3 0.3 0.1 1.0\n* 0.0 2.0 / 2.0 0.1 .\n$\n</pre>:||:-3 -36 -20:|
diff --git a/src/teaching/upp-2023/week14/index.md b/src/teaching/upp-2023/week14/index.du
index cf28fe7..a73e18f 100644
--- a/src/teaching/upp-2023/week14/index.md
+++ b/src/teaching/upp-2023/week14/index.du
@@ -1,9 +1,11 @@
# Задачи - УПП, Седмица 14, 19.01.2024
-GitHub classroom: [classroom.github.com/a/B08TtnnW](https://classroom.github.com/a/B08TtnnW)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/B08TtnnW classroom.github.com/a/B08TtnnW]
Това е последния практикум, затова ви давам по-лесни и приятни задачи: имплементации на игри!
-Всичките са взети от [101 BASIC Computer Games](https://en.wikipedia.org/wiki/BASIC_Computer_Games) (книгата е налична в [archive.org](https://archive.org/details/bitsavers_decBooks10Mar75_26006648)).
+Всичките са взети от [url https://en.wikipedia.org/wiki/BASIC_Computer_Games 101 BASIC Computer Games] (книгата е налична в [url https://archive.org/details/bitsavers_decBooks10Mar75_26006648 archive.org]).
Разбира се, който иска, може да решава задачи от предходни практикуми, давал съм достатъчно задачи.
@@ -24,39 +26,33 @@ Y sticks in pile 1
Z sticks in pile 2
[...]
K sticks in pile X
-```
След това се редуват, първия играч, втория играч:
```terminal
Player 1 turn
-```
Избирате купчина с пръчки:
```terminal
Which pile do you want sticks from? _
-```
където _ е мястото на курсора.
След това броя пръчки от купчината:
```terminal
How many sticks? _
-```
Ако някоя стойност е невалидна, питате пак.
След това идва редът на втория играч:
```terminal
Player 2 turn
-```
Накрая, този който вземе последната пръчка печели играта и се пита дали искате наново да почнете играта:
```terminal
Player X won. Do you want to play again? _
-```
## 2 задача - Хамураби
@@ -71,7 +67,6 @@ Player X won. Do you want to play again? _
```terminal
Hamurabi, I beg to report to you
In year X, Y people starved, Z came to the city.
-```
Разбира се, X, Y и Z са положителни целочислени стойности.
По-късно ще определим как се изменят и какви са началните стойности.
@@ -81,7 +76,6 @@ In year X, Y people starved, Z came to the city.
```terminal
A horrible plague struck! Half of the people died.
-```
След това съветника ви дава информация за града:
@@ -91,7 +85,6 @@ The city now owns X acres.
You harvested Z bushels per acre.
Rats ate K bushels.
You now have L bushels in store.
-```
Разбира се, X, Y, Z, K и L са целочислени стойности.
@@ -102,7 +95,6 @@ You now have L bushels in store.
```terminal
Land is trading at X bushels per acre.
How many acres do you wish to buy? _
-```
Където X е произволно цяло число между 17 и 27, долна черта показва мястото на курсора.
Трябва да се въведе цяло число.
@@ -111,7 +103,6 @@ How many acres do you wish to buy? _
```terminal
Hamurabi, I cannot do what you wish, get yourself another steward!!!!!
So long for now.
-```
Последния ред винаги се показва, когато играта свърши.
@@ -119,7 +110,6 @@ So long for now.
```terminal
Hamurabi, think again, you have only X bushels of grian. Now then,
-```
и същото съобщение за "Land is trading at [...] How many acres ..." се изписва и приемате нов вход.
@@ -127,7 +117,6 @@ Hamurabi, think again, you have only X bushels of grian. Now then,
```terminal
How many acres do you wish to sell? _
-```
Ако се въведе отрицателно число, случва се същото като при купуване на земя.
@@ -135,7 +124,6 @@ How many acres do you wish to sell? _
```terminal
Hamurabi think again, you own only X acres. Now then,
-```
и пак пита "How many acres [...]".
@@ -143,27 +131,23 @@ Hamurabi think again, you own only X acres. Now then,
```terminal
How many bushels do you wish to feed your people? _
-```
Ако се въведе твърде голямо число, съветника предупреждава и пита пак:
```terminal
Hamurabi, think again, you have only X bushels of grain. Now then,
How many bushels do you wish to feed your people? _
-```
Остава последния въпрос от съветника за годината:
```terminal
How many acres do you wish to plant with seed? _
-```
Разбира се, ако се въведат повече акри отколкото има, съветника предупреждава и пита пак:
```terminal
Hamurabi, think again, you own only X acres. Now then,
How many acres do you wish to plant with seed? _
-```
Предполагам може да се сетите какво съобщение съветника връща при отрицателни акри.
@@ -172,7 +156,6 @@ How many acres do you wish to plant with seed? _
```terminal
But you have only X people to tend the fields. Now then,
-```
Това са въпросите на съветника, сега остава годината да се изиграе.
Хората жънат (произволно число) между 1 и 6 бушела жито на всеки акър.
@@ -180,7 +163,7 @@ But you have only X people to tend the fields. Now then,
След това избирате друго произволно число между 1 и 6.
Ако числото е по-голямо от 1, тогава плъховете ще изядат по толкова голяма дроб бушели жито от резерва (при числото 5, плъховете изяждат 1/5; тук бушелите жито се смятат преди жътва).
-Сега населението расте, броя хора които са "дошли" в града се определя по формулата `R * (20 * АКРИ ЗЕМЯ + БУШЕЛИ ЖИТО) / БРОЙ ХОРА / 100 + 1`, където R е цяло число между 1 и 6.
+Сега населението расте, броя хора които са "дошли" в града се определя по формулата `[R * (20* АКРИ ЗЕМЯ + БУШЕЛИ ЖИТО) / БРОЙ ХОРА / 100 + 1]`, където R е цяло число между 1 и 6.
Бушелите жито се смятат след жътва.
Предпоследно, определя се колко хора са умрели от глад, като всеки човек консумира 20 бушели жито.
@@ -191,7 +174,6 @@ You starved X people in one year, due to this extreme mismanagement,
you have not only been impeached and thrown out of office but you have
also been declared national fink!
So long for now.
-```
Накрая на годината, трябва да обновите общия брой хора, които са умрели от глад, за цялото ви царуване, заедно със средния процент хора които са умирали на година.
@@ -200,13 +182,11 @@ So long for now.
```terminal
In your 10-year term of office, X percent of the population starved per year on average,
I.E., a total of Y people died.
-```
Сега изчислявате пропорцията между земя и хора, съветника ви казва:
```terminal
You started with 10 acres per person and ended with X acres per person.
-```
Ако средно над 33% от населението е умирало от глад всяка година или съотношението ви е под 7 акъра на човек, тогава се случва същото нещо, като когато над 45% от населението умира от глад.
@@ -216,7 +196,6 @@ You started with 10 acres per person and ended with X acres per person.
Your heavy-handed performance smacks of Nero and Ivan IV.
The people (remaining) find you an unpleasant ruler, and frankly, hate your guts.
So long for now.
-```
Ако средно над 3% (но под 11%) от населението е умирало от глад всяка година или съотношението е между 9 и 10 акъра на човека, тогава оставате със средно впечатление:
@@ -224,7 +203,6 @@ So long for now.
Your performance could have been somewhat better but really wasn't too bad at all.
X people would dearly like to see you assassinated but we all have our trivial problems.
So long for now.
-```
Където х съответства на бройката, между 0 и 80 процента от населението.
@@ -234,6 +212,5 @@ So long for now.
A fantastic performance!!!
Charlemange, Disraeli and Jefferson combined could not have done better.
So long for now.
-```
В началото на играта започвате с 100 човека население, като 5 от тях са дошли в града, 1000 акри земя, жътва от 3 бушела на акър, плъхове са изяли 200 бушела и имате 2800 бушела в хранилището.
diff --git a/src/teaching/upp-2023/week2/index.md b/src/teaching/upp-2023/week2/index.du
index da03945..e951282 100644
--- a/src/teaching/upp-2023/week2/index.md
+++ b/src/teaching/upp-2023/week2/index.du
@@ -1,70 +1,74 @@
# Задачи - УПП, Седмица 2, 13.10.2023
-GitHub classroom: [classroom.github.com/a/Bi5dhwW7](https://classroom.github.com/a/Bi5dhwW7)
+\n
-Решения: [GitHub](https://github.com/Syndamia/upp-2023-solutions/tree/main/week02)
+GitHub classroom: [url https://classroom.github.com/a/Bi5dhwW7 classroom.github.com/a/Bi5dhwW7]
-## **Важни бележки**
+Решения: [url https://github.com/Syndamia/upp-2023-solutions/tree/main/week02 GitHub]
-1. Не е добре да ползвате `using namespace std;`
-2. Единствената библиотека, която (поне за сега) може да ползвате е `iostream`
-3. За хората с текстови редактори и `gcc`, моля да погледнете в Moodle и да използвате предоставените флагове, най-важния от които е `-std=c++17`
-3. Като си качвате решенията в GitHub classroom, за предпочитане е имената на файловете да свършват на `.cpp`.
+## =[Важни бележки]=
+
+.numbered
+1. Не е добре да ползвате `[using namespace std;]`
+2. Единствената библиотека, която (поне за сега) може да ползвате е `[iostream]`
+3. За хората с текстови редактори и `[gcc]`, моля да погледнете в Moodle и да използвате предоставените флагове, най-важния от които е `[-std=c++17]`
+3. Като си качвате решенията в GitHub classroom, за предпочитане е имената на файловете да свършват на `[.cpp]`.
Отново, не е задължително, но ми улеснява живота.
## Тема: конвертиране
-<br>
+\n
### Задача 1 - Конвертирания от int
-Получавате целочислено число (тип `int`), след това, за всеки тип от следния списък, трябва да изкарате на нов ред текст във формата "Със/без загуба тип стойност":
+Получавате целочислено число (тип `[int]`), след това, за всеки тип от следния списък, трябва да изкарате на нов ред текст във формата "Със/без загуба тип стойност":
-- `bool`
-- `long long int`
-- `unsigned int`
-- `char`
-- `short int`
-- `double`
-- `long int`
-- `unsigned char`
+.bulleted
+- `[bool]`
+- `[long long int]`
+- `[unsigned int]`
+- `[char]`
+- `[short int]`
+- `[double]`
+- `[long int]`
+- `[unsigned char]`
Целта е да напишете един низ, който съдържа "Със/без загуба тип", и след това да изкарате (конвертираната) стойност.
Не се иска да правите код, който намира тази информация автоматично, всичко това просто си го напишете ръчно (hardcoded).
-**Пример**
-&emsp; *Нарочно са показани само първите два реда от изхода*
+=[Пример]=
+&emsp; *[Нарочно са показани само първите два реда от изхода]*
-|Вход|Изход|
-|----|-----|
-|5 |Със загуба bool 1<br>Без загуба long long int 5<br>...|
+.table
+|=Вход=||=Изход=|
+|:5 :||:Със загуба bool 1\nБез загуба long long int 5\n...:|
## Тема: Побитови оператори
-<br>
+\n
### Задача 2 - Mask
Получавате положително цяло число, от него трябва да "запазите" само първите (най-десните) 6 бита и да изкарате получилото се число.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|5 |5 |
-|200 |8 |
+.table
+|=Вход=||=Изход=|
+|:5 :||:5 :|
+|:200 :||:8 :|
### Задача 3 - Деление и умножение
-Получавате положително цяло число `а`, трябва да изкарате две числа (разделени с празно пространство):
-`a` (целочислено) разделено на 16 и `а` умножено по 8.
-**Трябва да използвате побитови оператори за това!**
+Получавате положително цяло число `[а]`, трябва да изкарате две числа (разделени с празно пространство):\n
+`[a]` (целочислено) разделено на 16 и `[а]` умножено по 8.
+=[Трябва да използвате побитови оператори за това!]=
-**Пример**
+=[Пример]=
-|Вход|Изход|
-|----|-----|
-|73 |4 584|
+.table
+|=Вход=||=Изход=|
+|:73 :||:4 584:|
### Задача 4 - IP адрес
@@ -76,89 +80,86 @@ GitHub classroom: [classroom.github.com/a/Bi5dhwW7](https://classroom.github.com
```
10000000100000001000000010000000
-```
Разделяйки по осморки битове:
```
10000000 10000000 10000000 10000000
-```
Всяка като я превърнем в десетично число става:
```
128 128 128 128
-```
-И накрая изкарания резултат трябва да бъде `128.128.128.128`
+И накрая изкарания резултат трябва да бъде `[128.128.128.128]`
На входа получавате цяло положително число, трябва да изкарате на екрана как би изглеждало с това представяне, с точките между осморки битове.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|3831791750|228.100.128.134|
-|240|0.0.0.240|
-|948405232|56.135.131.240|
+.table
+|=Вход=||=Изход=|
+|:3831791750:||:228.100.128.134:|
+|:240:||:0.0.0.240:|
+|:948405232:||:56.135.131.240:|
## Тема: Логически оператори
-<br>
+\n
### Задача 5 - Дели ли се
-От входа получавате две числа: `а` и `n`.
-Трябва да върнете 0 ако `a` не се дели на `n` без остатък, и 1 иначе.
+От входа получавате две числа: `[а]` и `[n]`.
+Трябва да върнете 0 ако `[a]` не се дели на `[n]` без остатък, и 1 иначе.
-**Упътване:** Булевата стойност `false` се изкарва като 0, а `true` се изкарва като 1, от `std::cout`
+=[Упътване:]= Булевата стойност `[false]` се изкарва като 0, а `[true]` се изкарва като 1, от `[std::cout]`
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|200 10|1 |
-|91 5 |0 |
+.table
+|=Вход=||=Изход=|
+|:200 10:||:1 :|
+|:91 5 :||:0 :|
### Задача 6 - Цифра ли е
Получавате от входа буква, трябва да върнете 0 ако буквата не е цифра и 1 ако е.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|5 |1 |
-|a |0 |
-|! |0 |
+.table
+|=Вход=||=Изход=|
+|:5 :||:1 :|
+|:a :||:0 :|
+|:! :||:0 :|
## Тема: Условни конструкции
-<br>
+\n
### Задача 7 - Нарастващ ред
На входа получавате три целочислени, трябва да ги изкарате в нарастващ ред.
-**Пример**
+=[Пример]=
-|Вход|Изход|
-|----|-----|
-|5 3 8|3 5 8|
+.table
+|=Вход=||=Изход=|
+|:5 3 8:||:3 5 8:|
### Задача 8 - Календар
От входа получавате число от 1 до 12: номера на месеца.
Трябва да изкарате името на месеца, където 1 съответства на "January", 2 на "February" и так. нат.
-Моля използвате `switch` конструкция.
+Моля използвате `[switch]` конструкция.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|1 |January|
-|10 |October|
+.table
+|=Вход=||=Изход=|
+|:1 :||:January:|
+|:10 :||:October:|
### Задача 9 - Монети
@@ -166,17 +167,17 @@ GitHub classroom: [classroom.github.com/a/Bi5dhwW7](https://classroom.github.com
Искате да платите използвайки само монети, като целта е да използвате възможно най-големите стойности на монети, възможно най-много (тоест ситуацията в която трябва да носите един милион монети по една стотинка не трябва да е възможност).
Изкарайте двойки "монета бройка", като работите с монети от по 50 стотинки, 20 стотинки, 10 стотинки, 5 стотинки, 1 стотинка.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|12.0|0.5 24 0.2 0 0.1 0 0.05 0 0.01 0|
-|3.37|0.5 6 0.2 1 0.1 1 0.05 1 0.01 2|
+.table
+|=Вход=||=Изход=|
+|:12.0:||:0.5 24 0.2 0 0.1 0 0.05 0 0.01 0:|
+|:3.37:||:0.5 6 0.2 1 0.1 1 0.05 1 0.01 2:|
### Задача 10 - ILS
При кацане, един самолет се нужда от информация дали е точно приравнен със средата на пистата, особено когато видимостта е занижена.
-Една система за тази цел се нарича [ILS](https://www.pilotscafe.com/Understanding-ILS/), но ние ще разгледаме нейния компонент, [the localizer](https://en.wikipedia.org/wiki/Instrument_landing_system_localizer): в края на пистата големи предаватели излъчват различни радио сигнали в двете половини на пистата.
+Една система за тази цел се нарича [url https://www.pilotscafe.com/Understanding-ILS/ ILS], но ние ще разгледаме нейния компонент, [url https://en.wikipedia.org/wiki/Instrument_landing_system_localizer the localizer]: в края на пистата големи предаватели излъчват различни радио сигнали в двете половини на пистата.
Ефектът е като на стерео тон колони, когато самолетът е в ляво от пистата, той приема сигнала от лявата част на пистата по-силно от този за дясната, както ако си доближиш ухото до лявата тон колона, ти ще чуваш нейния звук по-силно от дясната.
@@ -185,22 +186,22 @@ GitHub classroom: [classroom.github.com/a/Bi5dhwW7](https://classroom.github.com
Спрямо техните стойности, трябва да върнете "Turn right" ако самолетът е в ляво от пистата (ако XXX е по-голямо от YYY) и "Turn left" ако самолетът е в дясно.
Допълнително, понеже не е нужно самолетът да се намира перфектно в средата на пистата, зачитаме че ако разликата между двата интензитета е по-малка от 4, тогава самолетът е правилно подравнен и връщаме "Follow heading".
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|045093|Turn left|
-|100090|Turn right|
-|050053|Follow heading|
+.table
+|=Вход=||=Изход=|
+|:045093:||:Turn left:|
+|:100090:||:Turn right:|
+|:050053:||:Follow heading:|
### Задача 11 - GPS
-*В тази задача има много "теория", иначе самия код е малък и лесен.*
+*[В тази задача има много "теория", иначе самия код е малък и лесен.]*
Кондензирайки възможно най-много, ще обясня как работи GPS.
На земята имаме специални методи, чрез които можем да определим позицията на всеки сателит, обаче обратното, определянето на позицията чрез сателит, става с помощта на супер прецизни часовници и малко математика.
-Понеже радио комуникацията е със скоростта на светлината, можем лесно да определим разстояния между сателит и дадена точка, считайки колко време е отнело на сателита да върне отговор (припомням формулата `s = v * t`, или `разстояние = скорост * време`).
+Понеже радио комуникацията е със скоростта на светлината, можем лесно да определим разстояния между сателит и дадена точка, считайки колко време е отнело на сателита да върне отговор (припомням формулата `[s = v * t]`, или `[разстояние = скорост * време]`).
Обаче, така получаваме само разстоянието, това не е достатъчно за да определим точната позиция, понеже има много възможни точки на земята, които да са на това разстояние.
Решението на проблема, е че просто вземаш разстоянието от няколко сателита, твоята позиция се намира в общата точка между всички възможни области.
@@ -213,9 +214,9 @@ GitHub classroom: [classroom.github.com/a/Bi5dhwW7](https://classroom.github.com
От математика, ако знаем разстоянието на нашия приятел към трети различен човек, трите кръга върху картата ще се пресичат в само една точка, а именно позицията на нашия приятел.
В три измерения, правим същото, обаче със сфери, и ни трябват четири сателита.
-Понеже математиката в две и три измерения е малко множко, ще разгледаме всичко едноизмерно, в [Lineland](https://en.wikipedia.org/wiki/Flatland).
+Понеже математиката в две и три измерения е малко множко, ще разгледаме всичко едноизмерно, в [url https://en.wikipedia.org/wiki/Flatland Lineland].
-<br>
+\n
Разработваме (сериозно опростена) GPS система, като работим с едноизмерни координати, тоест позицията на всичко се определя с по едно число.
Изпращаме съобщение към два сателита по едно и също време, и получаваме отговор (какво е съобщението и отговор не е важно, интересува ни само времето).
@@ -226,8 +227,8 @@ GitHub classroom: [classroom.github.com/a/Bi5dhwW7](https://classroom.github.com
Накрая получавате още две числа, пак координата и време, но за втория сателит.
Изкарайте къде се намираме ние, като нека скоростта на светлината да бъде 29 метра в милисекунда.
-**Пример**
+=[Пример]=
-|Вход|Изход|
-|----|-----|
-|18 -100 22 132 30|-42|
+.table
+|=Вход=||=Изход=|
+|:18 -100 22 132 30:||:-42:|
diff --git a/src/teaching/upp-2023/week2/revision.md b/src/teaching/upp-2023/week2/revision.du
index 73e897f..be27064 100644
--- a/src/teaching/upp-2023/week2/revision.md
+++ b/src/teaching/upp-2023/week2/revision.du
@@ -1,142 +1,124 @@
# Преговор - УПП, Седмица 2, 13.10.2023
-&.presentation
+\n
-&[title
+[$presentation-controller]
-# Конвертиране на данни, побитови оператори, условни оператори
-
-&]
+:title_slide
+# Конвертиране на данни, побитови оператори, условни оператори
-&[slide
+:slide
## Конвертиране на данни
-&.br3
+[$br3]
+:unordered
- Неявно (скрито, експлицитно): компилаторът сам се досеща да промени типа
```cpp
int a = 5;
double b = a;
- ```
- Явно (изрично, експлицитно): казваме как типът да се конвертира
```cpp
double a = 5.7, b = 3.42;
int m = (int)a + (int)b;
- ```
-
-&]
-&[slide
+:slide
-&.br5
+[$br5]
+:unordered
- Със загуба на информация (от по-голям тип в по-малък)
-
+
```cpp
double a = 5.8371;
int b = a;
- ```
- Без загуба на информация (от по-малък тип в по-голям)
```cpp
int a = 1000;
long b = a;
- ```
-
-&]
-&[slide
+:slide
## Побитови оператори
-Първо ще ги погледнем чисто теоретично.
+.p Първо ще ги погледнем чисто теоретично.
-**Внимавайте, те са различни от логическите оператори!**
+.p =[Внимавайте, те са различни от логическите оператори!]=
-**Означавам побитовите числа с водеща буква "b"!**
-Тоест, числото `b1001` е двоичното число `1001`, което е десетичното число `9`.
+.p =[Означавам побитовите числа с водеща буква "b"!]=
+Тоест, числото `[b1001]` е двоичното число `[1001]`, което е десетичното число `[9]`.
-&.br3
+[$br3]
+
+:unordered
+- Отрицание/негация, `[~]`: обръща 0 в 1 и 1 в 0
-- Отрицание/негация, `~`: обръща 0 в 1 и 1 в 0
-
```
~ b0010 = b1101
- ```
-&]
+:slide
+:unordered
+- Побитово "и", `[&]`: за два бита, ако и двете са 1, връща 1, иначе връща 0
-&[slide
-
-- Побитово "и", `&`: за два бита, ако и двете са 1, връща 1, иначе връща 0
-
```
3 & 5 = 1
b0011 & b0101 = b0001
- ```
-- Побитово "или", `|`: за два бита, ако и двете са 0, връща 0, иначе връща 1
+- Побитово "или", `[|]`: за два бита, ако и двете са 0, връща 0, иначе връща 1
```
3 | 5 = 7
b0011 | b0101 = b0111
- ```
-- Изключващо "или", `^`: ако само един от двата бита е 1, връща 1, иначе връща 0
+- Изключващо "или", `[^]`: ако само един от двата бита е 1, връща 1, иначе връща 0
```
3 ^ 5 = 6
b0011 ^ b0101 = b0110
- ```
-
-&]
-&[middle27
-
-- Побитово отместване на ляво, `<<`: отмества всеки бит с n позиции на ляво
+:middle_slide27
+:unordered
+- Побитово отместване на ляво, `[<<]`: отмества всеки бит с n позиции на ляво\n
Винаги "запълва" с нули (няма разлика между логическо и аритметично ляво отместване)
```
b1010 << 1 = b0100
b0001 << 3 = b1000
- ```
-
+
(приемаме, че типа данни съхранява само 4 бита данни)
-- Побитово отместване на дясно, `>>`: отмества всеки бит с n позиции на дясно
- При аритметичното отместване, дупките се запълват с предходната стойност на старшия бит
- При логическото отместване, винаги запълваме с 0
+- Побитово отместване на дясно, `[>>]`: отмества всеки бит с n позиции на дясно\n
+ При аритметичното отместване, дупките се запълват с предходната стойност на старшия бит\n
+ При логическото отместване, винаги запълваме с 0\n
В C++ има един оператор, дали е аритметическо или логическо се определя от типа
```
b1000 >> 1 = b0100 или пък b1100
b1010 >> 3 = b0001 или пък b1111
- ```
-
-&]
-&[middle
+:middle_slide
Примери с код:
-```cpp
+:code_cpp
int a = 3, b = 5;
int n1 = ~ a; // -4
@@ -154,85 +136,72 @@ int r2 = b >> 2; // 1
int r3 = -b >> 1; // -3
int r4 = (unsigned int)b >> 1; // 2
int r5 = (unsigned int)-b >> 1; // 2147483645
-```
-
-&]
-
-&[slide
+:slide
## Логически оператори
+.p
Много приличат на побитовите, обаче побитовите работят върху битове, докато логическите работят върху bool.
+[$br4]
-&.br4
-
-- `!`: обръща `true` във `false` и обратно
+:unordered
+- `[!]`: обръща `[true]` във `[false]` и обратно
```cpp
! true // false
! false // true
- ```
-&]
-
-&[middle
-
-- `&&`: "логическо и", ако и двете стойности са `true`, тогава и резултатът е `true`
+:middle_slide
+:unordered
+- `[&&]`: "логическо и", ако и двете стойности са `[true]`, тогава и резултатът е `[true]`
```cpp
true && true // true
false && true // false
false && false // false
- ```
-- `||`: "логическо или", само ако и двете са `false`, тогава е `false`
+- `[||]`: "логическо или", само ако и двете са `[false]`, тогава е `[false]`
```cpp
true || true // true
false || true // true
false || false // false
- ```
-
-&]
-&[slide
+:slide
## Условни конструкции
-- `if`: приема булева стойност, ако е `true`, изпълнява кода в къдравите скоби, ако е `false` ги пропуска
+:unordered
+- `[if]`: приема булева стойност, ако е `[true]`, изпълнява кода в къдравите скоби, ако е `[false]` ги пропуска
```cpp
if (expression) {
dosomething;
}
dootherthing;
- ```
- `expression` се конвертира към типа `bool`
+ `[expression]` се конвертира към типа `[bool]`\n
- Ако в къдравите скоби имаме един израз (тоест е само един ред код, завършващ на `;`) можем да ги пропуснем.
+ Ако в къдравите скоби имаме един израз (тоест е само един ред код, завършващ на `[;]`) можем да ги пропуснем.
```cpp
if (expression) dosomething;
dootherthing;
- ```
-
-&]
-&[middle25
+:middle_slide25
+:unordered
+- `[if-else]`: работи като `[if]`, обаче след къдравите скоби добавяме `[else { ... }]`.
-- `if-else`: работи като `if`, обаче след къдравите скоби добавяме `else { ... }`.
-
```cpp
if (expression) {
dothing1;
@@ -241,12 +210,12 @@ int r5 = (unsigned int)-b >> 1; // 2147483645
dothing2;
}
dootherthing;
- ```
-
- Ако `expression` е истина, `dothing1` се изпълнява и `dothing2` се пропуска изцяло.
- Аналогично, ако `expression` е лъжа, `dothing1` се изпуска и `dothing2` се изпълнява.
- Както с `if`, ако `dothing2` е само един израз, можем да пропуснем къдравите скоби
+ .p
+ Ако `[expression]` е истина, `[dothing1]` се изпълнява и `[dothing2]` се пропуска изцяло.
+ Аналогично, ако `[expression]` е лъжа, `[dothing1]` се изпуска и `[dothing2]` се изпълнява.
+
+ .p Както с `[if]`, ако `[dothing2]` е само един израз, можем да пропуснем къдравите скоби
```cpp
if (expression) {
@@ -254,14 +223,11 @@ int r5 = (unsigned int)-b >> 1; // 2147483645
}
else dothing2;
dootherthing;
- ```
-
-&]
-&[slide25
-
+:slide25
+:unordered
- благодарение на изпускането на къдрави скоби, можем да пишем
```cpp
@@ -275,10 +241,9 @@ int r5 = (unsigned int)-b >> 1; // 2147483645
else {
doSomethingN;
}
- ```
Това е еквивалентно на:
-
+
```cpp
if (expression1) doSomething1;
else {
@@ -288,57 +253,47 @@ int r5 = (unsigned int)-b >> 1; // 2147483645
else doSomethingN;
}
}
- ```
-&]
-
-&[slide
-
-- `expression` винаги се конвертира до тип `bool` (ако е нужно)
- **Никога не правете такива неща:**
+:slide
+:unordered
+- `[expression]` винаги се конвертира до тип `[bool]` (ако е нужно)\n
+ =[Никога не правете такива неща:]=
```cpp
bool a;
if (expression) a = true;
else a = false;
- ```
```cpp
bool a = false;
if (expression) a = true;
- ```
- Просто правите `bool a = expression;`
+ Просто правите `[bool a = expression;]`
```cpp
bool a;
if (expression) a = false;
else a = true;
- ```
-
- Просто правите `bool a = ! expression;`
-
-&]
+ Просто правите `[bool a = ! expression;]`
-&[slide
+:slide
+:unordered
- Тернарен оператор: ако искате да имате такава условна конструкция като част от израз (който взема стойност) използвате
```cpp
(expression) ? valueA : valueB
- ```
- Ако `expression` е истина, връща се `valueA`, иначе се връща `valueB`
+ Ако `[expression]` е истина, връща се `[valueA]`, иначе се връща `[valueB]`
```cpp
int grade;
std::cin >> grade;
double a = (grade < 300) ? 2.0 : grade / 100.0;
- ```
Има много нисък приоритет, в повечето случаи ще ви се наложи да го оградите в скоби.
@@ -346,15 +301,12 @@ int r5 = (unsigned int)-b >> 1; // 2147483645
int grade;
std::cin >> grade;
std::cout << ((grade < 300) ? 2.0 : grade / 100.0);
- ```
-&]
-
-&[middle27
-
-- `switch`: приема стойност и изпълнява случая, при който стойността съвпада с определената
+:middle_slide27
+:unordered
+- `[switch]`: приема стойност и изпълнява случая, при който стойността съвпада с определената
```cpp
switch (value) {
@@ -362,7 +314,6 @@ int r5 = (unsigned int)-b >> 1; // 2147483645
case valueB: doSomething2; break;
case valueC: doSomething3; break;
}
- ```
Служи като улеснение на синтаксиса:
@@ -370,19 +321,16 @@ int r5 = (unsigned int)-b >> 1; // 2147483645
if (value == valueA) doSomething1;
else if (value == valueB) doSomething2;
else if (value == valueC) doSomething3;
- ```
-
- `otherwise` е като `else`, това е случая когато не съвпада с никоя стойност.
- Може да бъде изпуснат.
-
- Без `break` изпълнението продължава към следващия `case`
-&]
+ .p
+ `[otherwise]` е като `[else]`, това е случая когато не съвпада с никоя стойност.
+ Може да бъде изпуснат.
+ .p Без `[break]` изпълнението продължава към следващия `[case]`
-&[middle
+:middle_slide
```cpp
char characterInput;
@@ -393,6 +341,3 @@ switch(characterInput) {
case 'w': std::cout << "Hello World"; break;
default: std::cout << "Error"; break;
}
-```
-
-&]
diff --git a/src/teaching/upp-2023/week3/index.md b/src/teaching/upp-2023/week3/index.du
index 1e71de4..b2a7f65 100644
--- a/src/teaching/upp-2023/week3/index.md
+++ b/src/teaching/upp-2023/week3/index.du
@@ -1,78 +1,80 @@
# Задачи - УПП, Седмица 3, 20.10.2023
-GitHub classroom: [classroom.github.com/a/JgMSXuCf](https://classroom.github.com/a/JgMSXuCf)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/JgMSXuCf classroom.github.com/a/JgMSXuCf]
## Тема: цикли
-<br>
+\n
### Задача 1 - Степенуване
-Получавате цяло число `x` и цяло положително число `n`, трябва да върнете `x` на степен `n`-та.
+Получавате цяло число `[x]` и цяло положително число `[n]`, трябва да върнете `[x]` на степен `[n]`-та.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|0 0 |1 |
-|-2 3|-8 |
-|4 1 |4 |
+.table
+|=Вход=||=Изход=|
+|:0 0 :||:1 :|
+|:-2 3:||:-8 :|
+|:4 1 :||:4 :|
### Задача 2 - Progress bar
-Получавате цяло число `x`, което е по-голямо или равно на 1, и на всеки ред трябва да изкарате един "progress bar", чиято дължина се увеличава с всеки изминал ред.
-На практика, този "progress bar" трябва да бъде една права, съставена от знакът `#`, която трябва с всеки изминал ред да се удължава с един знак.
-В началото прогресът е 1 и продължава до `x` включително.
+Получавате цяло число `[x]`, което е по-голямо или равно на 1, и на всеки ред трябва да изкарате един "progress bar", чиято дължина се увеличава с всеки изминал ред.
+На практика, този "progress bar" трябва да бъде една права, съставена от знакът `[#]`, която трябва с всеки изминал ред да се удължава с един знак.
+В началото прогресът е 1 и продължава до `[x]` включително.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|3 |#<br>##<br>###
-|5 |#<br>##<br>###<br>####<br>#####
+.table
+|=Вход=||=Изход=|
+|:3 :||:#\n##\n###:|
+|:5 :||:#\n##\n###\n####\n#####:|
#### Бонус
-Направете дължината на този progress bar фиксирана на 10 знака, и въведеното `x` да определя след колко реда трябва да запълним progress bar-а.
+Направете дължината на този progress bar фиксирана на 10 знака, и въведеното `[x]` да определя след колко реда трябва да запълним progress bar-а.
Този път, прогресът започва от 0.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|1 |##########|
-|2 |#####<br>##########|
-|3 |###<br>######<br>##########|
-|10 |#<br>##<br>###<br>...|
-|20 |<br>#<br>#<br>##<br>##<br>###<br>...|
+.table
+|=Вход=||=Изход=|
+|:1 :||:##########:|
+|:2 :||:#####\n##########:|
+|:3 :||:###\n######\n##########:|
+|:10 :||:#\n##\n###\n...:|
+|:20 :||:\n#\n#\n##\n##\n###\n...:|
### Задача 3 - Endless program with an end
От входа получавате букви, не се знае колко.
На нов ред, за всяка буква, трябва да върнете "letter" ако е латинска буква, "digit" ако е цифра и "other" ако не е нито едно от двете.
-Обаче, буквата `^` има специално значение, когато я получим трябва програмата да свърши изпълнение.
+Обаче, буквата `[^]` има специално значение, когато я получим трябва програмата да свърши изпълнение.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|a 8 ) b ^|letter<br>digit<br>other<br>letter|
+.table
+|=Вход=||=Изход=|
+|:a 8 ) b ^:||:letter\ndigit\nother\nletter:|
### Задача 4 - Premature end
-Ще получите максимум 10 цели числа, трябва (целочислено) да разделите числото `65536` на всяко от въведените числа.
+Ще получите максимум 10 цели числа, трябва (целочислено) да разделите числото `[65536]` на всяко от въведените числа.
Но, когато получите числото 0, веднага трябва да спрете вземане на числа от входа.
Финално, изкарайте резултата от всички тези деления.
-**Упътване:** Използвайте `break`.
+=[Упътване:]= Използвайте `[break]`.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|65536 0|1|
-|2 4 3 0|2730|
-|199 2 2 1 -1 1 3 1 10 1|-2|
+.table
+|=Вход=||=Изход=|
+|:65536 0:||:1:|
+|:2 4 3 0:||:2730:|
+|:199 2 2 1 -1 1 3 1 10 1:||:-2:|
### Задача 5 - Stop test
@@ -80,48 +82,48 @@ GitHub classroom: [classroom.github.com/a/JgMSXuCf](https://classroom.github.com
Получавате букви, незнайно колко.
Трябва да броите колко от тях са малки букви, колко са главни и колко са цифри.
-В момента в който получите `$` трябва да спрете приемане на букви и да изкарате
+В момента в който получите `[$]` трябва да спрете приемане на букви и да изкарате
```
Lowercase: X Uppercase: Y Digit: Z
-```
където X, Y и Z са съответните бройки.
-Обаче, ако получите буква, която не е малка, главна, цифра или `$`, трябва моментално да спрете изпълнението на програмата, без да отпечатвате нищо.
+Обаче, ако получите буква, която не е малка, главна, цифра или `[$]`, трябва моментално да спрете изпълнението на програмата, без да отпечатвате нищо.
-**Упътване:** Използвайте `return`.
+=[Упътване:]= Използвайте `[return]`.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|a b A 9 n 3 $|Lowercase: 3 Uppercase: 1 Digit: 2|
-|J h 8 8 @||
+.table
+|=Вход=||=Изход=|
+|:a b A 9 n 3 $:||:Lowercase: 3 Uppercase: 1 Digit: 2:|
+|:J h 8 8 @:||::|
### Задача 6 - Глупави сметки
От входа получавате букви, това ще са "команди", като при всяка буква трябва да направите различно действие:
-- `s`: след като я получите, трябва да вземете цяло число от входа и да го запазите (първоначалната стойност на числото е 15)
-- `l`: трябва побитово да отместите наляво запазеното число с един бит
-- `r`: трябва побитово да отместите надясно запазеното число с един бит
-- `q`: трябва да запазите сегашното число на втора степен
-- `c`: трябва да запазите сегашното число на трета степен
-- `m`: трябва да запазите сегашното число минус 351
-- `p`: трябва да запазите сегашното число плюс 94
-- `&`: прекратявате програмата
+.bulleted
+- `[s]`: след като я получите, трябва да вземете цяло число от входа и да го запазите (първоначалната стойност на числото е 15)
+- `[l]`: трябва побитово да отместите наляво запазеното число с един бит
+- `[r]`: трябва побитово да отместите надясно запазеното число с един бит
+- `[q]`: трябва да запазите сегашното число на втора степен
+- `[c]`: трябва да запазите сегашното число на трета степен
+- `[m]`: трябва да запазите сегашното число минус 351
+- `[p]`: трябва да запазите сегашното число плюс 94
+- `[&]`: прекратявате програмата
След всяка операция трябва да изкарате сегашната стойност на числото.
-Обаче, ако се въведе буква, за която няма дефинирана операция (не е команда) трябва да изкарате "Invalid command!" и да **не** изкарвате сегашната стойност на числото.
+Обаче, ако се въведе буква, за която няма дефинирана операция (не е команда) трябва да изкарате "Invalid command!" и да =[не]= изкарвате сегашната стойност на числото.
-**Упътване:** Използвайте `switch`, `default` и `continue`.
+=[Упътване:]= Използвайте `[switch]`, `[default]` и `[continue]`.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|l l m q r &|30<br>60<br>-291<br>84681<br>42340|
-|s 34 c p s 2 ^ r &|34<br>39304<br>39398<br>2<br>Invalid command!<br>1|
+.table
+|=Вход=||=Изход=|
+|:l l m q r &:||:30\n60\n-291\n84681\n42340:|
+|:s 34 c p s 2 ^ r &:||:34\n39304\n39398\n2\nInvalid command!\n1:|
### Задача 7 - Безсмислена "тивност"
@@ -131,13 +133,13 @@ Lowercase: X Uppercase: Y Digit: Z
Първоначалната стойност на числото е 3.14159 и трябва в началото да изкарате "Positive".
-**Упътване:** Използвайте `do-while`.
+=[Упътване:]= Използвайте `[do-while]`.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|9.1 -22.0 0|Positive<br>Positive<br>Negative|
+.table
+|=Вход=||=Изход=|
+|:9.1 -22.0 0:||:Positive\nPositive\nNegative:|
### Задача 8 - Дигитален часовник
@@ -145,21 +147,26 @@ Lowercase: X Uppercase: Y Digit: Z
Работите върху софтуер на един дигитален часовник, като ще трябва да запазите сегашния час и минути (които първоначално са "00:00").
Получавате букви (команди), като на всяка трябва да извършите някакво действие:
-- `t` - увеличавате минутите с единица (не забравяйте, че ако времето е било "0:59", трябва да стане "1:00") и изкарвате сегашното време
-- `c` - в зависимост от предишни натискания, прави различни неща:
+:bulleted
+- `[t]` - увеличавате минутите с единица (не забравяйте, че ако времето е било "0:59", трябва да стане "1:00") и изкарвате сегашното време
+- `[c]` - в зависимост от предишни натискания, прави различни неща:
+ .bulleted
- ако преди не е натиснат, влизаме в режим на промяна на часовете, от входа приемаме число което ще бъде новия час и изкарваме сегашното време
- ако вече е натиснат, влизаме в режим на минутите, от входа приемаме число, което ще бъде новата стойност на минутите и изкарваме сегашното време
- ако вече два пъти е бил натиснат, излизаме от режима
- - ако сме в някой от първите два режима и получим `t` преди да излезем, не увеличаваме минутите
-- `f` - променяме изкараното време от 12 часов формат на 24 часов и обратно, като първоначално започваме с 24 часов, и изкарваме сегашното време
- - При 24 часов формат изкарваме "XX:YY", където `XX` е часа и `YY` са минутите
+ - ако сме в някой от първите два режима и получим `[t]` преди да излезем, не увеличаваме минутите
+
+- `[f]` - променяме изкараното време от 12 часов формат на 24 часов и обратно, като първоначално започваме с 24 часов, и изкарваме сегашното време
+ .bulleted
+ - При 24 часов формат изкарваме "XX:YY", където `[XX]` е часа и `[YY]` са минутите
- При 12 часов формат е почти същото "XX:YY ZM" където ZM е PM или AM
-**Примери**
-|Вход|Изход|
-|----|-----|
-|t c 19 t c 3 t c f f f|0:1<br>19:1<br>19:3<br>7:3 PM<br>19:3<br>7:3 PM|
+=[Примери]=
+
+.table
+|=Вход=||=Изход=|
+|:t c 19 t c 3 t c f f f:||:0:1\n19:1\n19:3\n7:3 PM\n19:3\n7:3 PM:|
### Задача 9 - BASIC maze
@@ -167,55 +174,51 @@ Lowercase: X Uppercase: Y Digit: Z
```
10 PRINT CHR$(205.5+RND(1));:GOTO 10
-```
-Задачата е да я пресъздадем, тоест на 20 реда трябва да има по 20 букви, като всяка буква е, на случаен принцип, `/` или `\` .
+Задачата е да я пресъздадем, тоест на 20 реда трябва да има по 20 букви, като всяка буква е, на случаен принцип, `[/]` или `[\\]` .
-**Упътване:** Формално никога не се преподават или изискват случайни стойности, затова ги показвам сега:
+=[Упътване:]= Формално никога не се преподават или изискват случайни стойности, затова ги показвам сега:
Най-отгоре на сорс-файла добавете нужната библиотека:
```cpp
#include <stdlib.h>
#include <ctime>
-```
-След това, в `main`, преди да използвате случайни стойности, трябва да "инициализираме системата":
+След това, в `[main]`, преди да използвате случайни стойности, трябва да "инициализираме системата":
```cpp
srand(time(NULL));
-```
-С функцията `rand()` получавате случайна положителна стойност, може да я ограничите до две стойности с модулно деление, `rand() % 2`.
+С функцията `[rand()]` получавате случайна положителна стойност, може да я ограничите до две стойности с модулно деление, `[rand() % 2]`.
-**Примерен изход** *Нямаме вход, вашия изход няма да изглежда напълно еднакъв*
+=[Примерен изход]= *[Нямаме вход, вашия изход няма да изглежда напълно еднакъв]*
```
-////\/\\////\\/////\
-\\/\\\\\\\/\////\///
-\\\///\\\//\\\/\//\/
-/\/\////\\\//\\\/\\\
-//\/\////\\\\\///\\/
-/\\\\\\/\\/\\\/\///\
-/////\\\\\\/\\/\////
-\//\//\\\///\\\\\\\\
-\\\\//\\////\///\/\\
-\//\//\////////\//\\
-\\///\\//\///\/\/\/\
-///\\\///////\\\\///
-/\\/\\//\///\\/\\\\/
-\///\/\\\/\\\\/\\\\\
-////\/\\/\\/////\/\/
-\\/\\\//\//\\//\\///
-////\\\\/\//\\\/\/\/
-\//\\\/\\\\///\////\
-///\///\\//\\\//\\/\
-\/\/\\\/////\//\\\\/
-```
+////\/\\\\////\\\\/////\
+\\\\/\\\\\\\\\\\\\/\////\///
+\\\\\///\\\\\//\\\\\/\//\/
+/\/\////\\\\\//\\\\\/\\\\\
+//\/\////\\\\\\\\\///\\\\/
+/\\\\\\\\\\\\/\\\\/\\\\\/\///\
+/////\\\\\\\\\\\\/\\\\/\////
+\//\//\\\\\///\\\\\\\\\\\\\\\\
+\\\\\\\\//\\\\////\///\/\\\\
+\//\//\////////\//\\\\
+\\\\///\\\\//\///\/\/\/\
+///\\\\\///////\\\\\\\\///
+/\\\\/\\\\//\///\\\\/\\\\\\\\/
+\///\/\\\\\/\\\\\\\\/\\\\\\\\\
+////\/\\\\/\\\\/////\/\/
+\\\\/\\\\\//\//\\\\//\\\\///
+////\\\\\\\\/\//\\\\\/\/\/
+\//\\\\\/\\\\\\\\///\////\
+///\///\\\\//\\\\\//\\\\/\
+\/\/\\\\\/////\//\\\\\\\\/
### Задача 10 - Елка
-*Решението на тази задача е по-дълго!*
+*[Решението на тази задача е по-дълго!]*
Сега имплементирате кода на една елка.
Елката запазва две числа, първото е "сегашното" число с което правим нормалните операции и "виждаме" на екрана, и второто е отделна памет, в която можем да добавяме и изваждаме числа.
@@ -225,22 +228,23 @@ srand(time(NULL));
Първото въведено число директно става новата стойност на сегашното число.
Буквата е команда, като може да бъде +,-,\*,/, които са обикновените операции с които променяме сегашното число, докато:
-- `a` - добавя сегашното число в отделната памет
-- `s` - изважда сегашното число от тази памет
-- `c` - занулява сегашното число
-- `m` - занулява числото в отделната памет
+.bulleted
+- `[a]` - добавя сегашното число в отделната памет
+- `[s]` - изважда сегашното число от тази памет
+- `[c]` - занулява сегашното число
+- `[m]` - занулява числото в отделната памет
-След `a`, `s` и `m` трябва да изкарате числото в отделната памет, докато след всички други команди трябва да изкарате сегашното число.
+След `[a]`, `[s]` и `[m]` трябва да изкарате числото в отделната памет, докато след всички други команди трябва да изкарате сегашното число.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|5 + 5 * 2 a a - 6 c|10<br>20<br>20<br>40<br>14<br>0|
+.table
+|=Вход=||=Изход=|
+|:5 + 5 * 2 a a - 6 c:||:10\n20\n20\n40\n14\n0:|
## Тема: assert
-<br>
+\n
### Задача 11 - Термостат
@@ -248,12 +252,12 @@ srand(time(NULL));
```
int parseSensor(int s) { return ((((s=(s>>1)&(~0xF617A100))<0x54)?s|0xF01:s&0xCBFF)>>2)-21; }
-```
-Все още не сме учили функции, затова просто пльоснете горното нещо във вашия сорс код, *над* `int main()` и *в* `main` може да я използвате чрез `parseSensor(inputValue)`.
+Все още не сме учили функции, затова просто пльоснете горното нещо във вашия сорс код, *[над]* `[int main()]` и *[в]* `[main]` може да я използвате чрез `[parseSensor(inputValue)]`.
Вашата задача е при определени градуси да връщате съобщение на екрана:
+.bulleted
- между 30 и 40 връщате "Hot"
- между 20 и 29 връщате "Warm"
- между 11 и 19 връщате "Temperate"
@@ -262,7 +266,7 @@ int parseSensor(int s) { return ((((s=(s>>1)&(~0xF617A100))<0x54)?s|0xF01:s&0xCB
Обаче, това не е всичко.
Поглеждате функцията на вашия колега и не сте уверени в нея, обаче нямате документацията за обработка на входа.
-Единственото нещо, което знаете, е че стойностите от функцията не трябва да са извън обхвата -20 и 40, затова използвайте `assert` и проверете/тествайте дали това винаги е вярно.
+Единственото нещо, което знаете, е че стойностите от функцията не трябва да са извън обхвата -20 и 40, затова използвайте `[assert]` и проверете/тествайте дали това винаги е вярно.
Ето стойности с които може да тествате:
@@ -274,13 +278,12 @@ int parseSensor(int s) { return ((((s=(s>>1)&(~0xF617A100))<0x54)?s|0xF01:s&0xCB
-332447576
-332447496
-332447736
-```
На кои стойности функцията на колегата не работи?
-**Примери** *Входът е различен от горепосочените стойности (и при него функцията работи коректно)*
+=[Примери]= *[Входът е различен от горепосочените стойности (и при него функцията работи коректно)]*
-|Вход|Изход|
-|----|-----|
-|-332447376|Warm|
-|-332447536|Cold|
+.table
+|=Вход=||=Изход=|
+|:-332447376:||:Warm:|
+|:-332447536:||:Cold:|
diff --git a/src/teaching/upp-2023/week3/revision.md b/src/teaching/upp-2023/week3/revision.du
index b1dab08..876ed77 100644
--- a/src/teaching/upp-2023/week3/revision.md
+++ b/src/teaching/upp-2023/week3/revision.du
@@ -1,101 +1,94 @@
# Преговор - УПП, Седмица 3, 20.10.2023
-&.presentation
+\n
-&[title35
-
-# Цикли, assert
-
-&]
+[$presentation-controller]
+:title_slide35
+# Цикли, assert
-&[slide25
+:slide25
## Бележки от миналия път
+:unordered
- Видях две груби грешки в предадените решения, първо:
```cpp
bool b;
if (condition) b = true;
- ```
-
- Грешно е, понеже `condition` сам по себе си е от тип bool, с този `if` буквално не правите нищо.
+
+ Грешно е, понеже `[condition]` сам по себе си е от тип bool, с този `[if]` буквално не правите нищо.
Правилния вариант е:
```cpp
bool b = condition;
- ```
Аналогично за:
```cpp
bool b;
if (!condition) b = true;
- ```
правилното е:
```cpp
bool b = !condition;
- ```
-
-&]
-&[middle
-
+:middle_slide
+:unordered
- второ:
```cpp
a >= 48 && a <= 57
- ```
+ .p
Всяка буква действително съответства на определено число, дефинирано от ASCII стандарта.
- Наистина '0' е 48 и '9' е 57, обаче от вас **не** се очаква да помните ASCII таблицата!
+ Наистина '0' е 48 и '9' е 57, обаче от вас =[не]= се очаква да помните ASCII таблицата!
Също, ако не знаеш наизуст кои буква са тези числа, този израз е много неясен.
+ .p
Правилния вариант е просто да направите сравнения с буквите, все пак C++ ги "конвертира" (много грубо казано) към съответните ASCII стойности:
```cpp
a >= '0' && a <= '9'
- ```
-
-&]
-&[slide
+:slide
## С/без загуба на данни
-&.br3
+[$br3]
+.p
Получи се малко разногласие между това, което Ивана ви е казала и това което аз ви казах.
-В края на деня, **конвертиране от int към unsigned int не губи информация!**
+В края на деня, =[конвертиране от int към unsigned int не губи информация!]=
+.p
Цитирайки 4то издание на "The C++ Programming Language" глава 10.5:
-> A conversion is value-preserving if you can convert a value and then convert the result back to it's original type and get the original value
+.quote
+A conversion is value-preserving if you can convert a value and then convert the result back to it's original type and get the original value
Тоест, конвертирания при които не губиш битове, нямаш загуба на данни.
-&]
-
-
-&[slide
+:slide
## 2s compliment
+.p
Интуитивно обяснение на 2s compliment.
Да приемем, че работим с тип данни, при който имаме само 3 бита.
+.p
Как бихме ги използвали, за да представим отрицателните числа?
-Най-лесния начин е да погледнем най-левия (старшия) бит, ако е 0 значи е положително, ако е 1 значи е отрицателно, тоест `010` е 2, докато `110` е -2.
+Най-лесния начин е да погледнем най-левия (старшия) бит, ако е 0 значи е положително, ако е 1 значи е отрицателно, тоест `[010]` е 2, докато `[110]` е -2.
Ако разпишем всичките ни числа:
```
@@ -107,37 +100,32 @@
010 2
001 1
000 0
-```
-
-&]
+:middle_slide
-&[middle
-
+.p
Това работи, обаче имаме един гигантски проблем: събирането не работи!
От математика знаем, че "2 - 1 = 2 + (-1)", тоест би трябвало да можем да съберем побитово 2 и -1 и да получим 1.
Ама,
```
2 + -1 = 010 + 101 = 111 = -3
-```
+.p
Също, знаем, че "(-1) + (-1) = -2", обаче
```
-1 + -1 = 101 + 101 = 1010 имаме overflow, това се съкращава на 010 = 2
-```
+.p
Излиза, че с тази схема не можем да събираме отрицателни числа както събираме положителни (или както събираме побитово).
+.p
Да не говорим, че ние имаме -0, което не ни трябва много.
-&]
-
-
-&[middle
+:middle_slide
Нека да помислим пак, да вземем само положителните:
@@ -145,28 +133,23 @@
011 3
010 2
001 1
-```
Сега, искаме -1 да бъде такова число, различно от досега дефинираните (тоест което има единица в старшия си бит) така че "1 + -1 = 0".
Лесно се досещаме, че ако добавим към "001" числото "111", тогава тяхната сума ще предизвика overflow и резултата ще бъде 0:
```
001 + 111 = 1000 overflow, става 000
-```
Нека тогава "-1 = 111".
-&]
-
-
-&[slide
+:slide
+.p
Правейки същото за "2 + -2", намираме че
```
010 + 110 = 1000 overflow, става 000
-```
Нека тогава "-2 = 110".
За "3 + -3" се досещаме, че "-3 = 101".
@@ -181,66 +164,58 @@
010 2
001 1
000 0
-```
100 не сме го използвали, обаче намерихме отрицателното число за всяко положително.
Да видим как работим с него, побитово "100 + 001 = 101", тоест "x + 1 = -3", следователно x ще бъде -4.
-&]
+:middle_slide
-
-&[middle
-
+.p
Това е идеята на "complements", дефинираме отрицателни числа, така че да използваме едно и също събиране между положителни и отрицателни.
-Още от много старите "калкулатори" ([сумиращи машини](https://en.wikipedia.org/wiki/Adding_machine)), изваждането се е свеждало до събиране на положително и отрицателно число.
+.p
+Още от много старите "калкулатори" ([url https://en.wikipedia.org/wiki/Adding_machine сумиращи машини]), изваждането се е свеждало до събиране на положително и отрицателно число.
-И това е причината защо `~ 2` връща `-3`:
+.p
+И това е причината защо `[~ 2]` връща `[-3]`:
```
~ 00000000000000000000000000000010
──────────────────────────────────
11111111111111111111111111111101
-```
-И затова при `>>` със знаков тип имаме аритметическо отместване:
+И затова при `[>>]` със знаков тип имаме аритметическо отместване:
```
11111111111111111111111111111101 >> 1
─────────────────────────────────────
11111111111111111111111111111110
-```
-
-&]
-
-&[slide
+:slide
## Цикли
-&.br4
+[$br4]
-- `while` цикъл
+:unordered
+- `[while]` цикъл
```cpp
while (условие) {
тяло
}
- ```
- "условие" е булева стойност, като ако е `false` цикъла спира, докато ако е `true` "тяло" се изпълнява и после пак се проверява условие
+ "условие" е булева стойност, като ако е `[false]` цикъла спира, докато ако е `[true]` "тяло" се изпълнява и после пак се проверява условие
-&]
-
-&[middle
+:middle_slide
- Може да си го представите като
- ```cpp
+ :code_cpp
if (условие) {
тяло
}
@@ -248,7 +223,6 @@
спри
}
-
if (условие) {
тяло
}
@@ -256,27 +230,24 @@
спри
}
...
- ```
-&]
-&[slide
-
-- `do-while` цикъл, като `while`, но "тяло" се изпълнява поне един път
+:slide
+:unordered
+- `[do-while]` цикъл, като `[while]`, но "тяло" се изпълнява поне един път
```cpp
do {
тяло
} while (условие);
- ```
Нашият аналог е:
- ```cpp
+ :code_cpp
тяло
-
+
if (условие) {
тяло
}
@@ -284,38 +255,32 @@
спри
}
-
if (условие) {
...
- ```
-
-&]
-&[middle
-- `for` цикъл
+:middle_slide
+:unordered
+- `[for]` цикъл
```cpp
for (инициализация; условие; инкрементация) {
тяло
}
- ```
- "инициализация" се изпълнява само веднъж, преди всичко останало в цикъла
- "условие" се изпълнява преди всяка итерация, като ако е `false` цикъла спира, докато ако е `true` продължава
+ "инициализация" се изпълнява само веднъж, преди всичко останало в цикъла\n
+ "условие" се изпълнява преди всяка итерация, като ако е `[false]` цикъла спира, докато ако е `[true]` продължава\n
"инкрементация" се изпълнява след края на всяка итерация
-&]
-
-&[slide
-
+:slide
+:unordered
- Може да си представяте, че това на практика извършва:
- ```cpp
+ :code_cpp
инициализация
if (условие) {
@@ -334,15 +299,13 @@
спри
}
...
- ```
-
-&]
-&[middle
-- или използвайки `while` цикъл:
+:middle_slide
+:unordered
+- или използвайки `[while]` цикъл:
```cpp
инициализация
@@ -350,48 +313,43 @@
тяло
инкрементация
}
- ```
-&]
-
-&[slide
+:slide
### Ключови думи
-&.br3
-
-- `break`: моментално прекратява изпълнението на цикъла
+[$br3]
- При `for` цикли инкрементацията не се изпълнява след `break`
+:unordered
+- `[break]`: моментално прекратява изпълнението на цикъла
-&.br2
+ .p При `[for]` цикли инкрементацията не се изпълнява след `[break]`
-- `continue`: продължи след края на сегашната итерация; тоест изпълнението на тяло се прекратява и започваме нова итерация
+[$br2]
- При `for` цикли директно отива на инкрементация
+- `[continue]`: продължи след края на сегашната итерация; тоест изпълнението на тяло се прекратява и започваме нова итерация
-&]
+ .p При `[for]` цикли директно отива на инкрементация
-&[slide
+:slide
## Assert
+[$br3]
-&.br3
-
+.p
Понякога е полезно да тестваме нашия код вътре в самия код.
Тоест, искаме на конкретно място в кода да проверим нещо.
```cpp
assert(condition);
-```
-
-Ако `condition` е `true`, нищо не се случва, обаче ако е `false` програмата моментално прекратява изпълнение.
-Използва се повече като програмистки уред, тоест ако програмата спре заради `assert`, това е защото има някаква програмистка грешка.
+.p
+Ако `[condition]` е `[true]`, нищо не се случва, обаче ако е `[false]` програмата моментално прекратява изпълнение.
-&]
+.p
+Използва се повече като програмистки уред, тоест ако програмата спре заради `[assert]`, това е защото има някаква програмистка грешка.
diff --git a/src/teaching/upp-2023/week4/index.md b/src/teaching/upp-2023/week4/index.du
index 0d8093b..0981e84 100644
--- a/src/teaching/upp-2023/week4/index.md
+++ b/src/teaching/upp-2023/week4/index.du
@@ -1,10 +1,12 @@
# Задачи - УПП, Седмица 4, 27.10.2023
-GitHub classroom: [classroom.github.com/a/jqKaO1ny](https://classroom.github.com/a/jqKaO1ny)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/jqKaO1ny classroom.github.com/a/jqKaO1ny]
## Задача 1 - Числен редактор
-Получавате число `N`, което ще е в обхвата от 1 до 10000000000000000000.
+Получавате число `[N]`, което ще е в обхвата от 1 до 10000000000000000000.
Вашата програма трябва да поддържа няколко операции върху това число, включително копиране на редица от цифри в него и поставянето им в друга част на числото.
Подробните операции ще получите по-късно, и не е нужно да валидирате вход или дали след дадена операция числото се побира в типа данни.
@@ -14,7 +16,7 @@ GitHub classroom: [classroom.github.com/a/jqKaO1ny](https://classroom.github.com
Всичките операции трябва да бъдат отделени във функции.
Затова, и за улеснение, задачата е разделена на стъпки:
-**ВАЖНО:** В решението **НЕ** може да изполвате масиви, вектори, ..., както и каквито и да е функции, които не сте написали вие!
+=[ВАЖНО:]= В решението =[НЕ]= може да изполвате масиви, вектори, ..., както и каквито и да е функции, които не сте написали вие!
### Подточка а) Примитивните функции
@@ -22,71 +24,75 @@ GitHub classroom: [classroom.github.com/a/jqKaO1ny](https://classroom.github.com
Имплементирайте функциите:
-- `get`, която приема число, начален индекс и краен индекс (в този ред)
+:unordered
+- `[get]`, която приема число, начален индекс и краен индекс (в този ред)\n
Тя връща подчислото, което започва от началния и завършва в крайния индекс.
- Пример: `get(481395, 2, 4)` връща `813`
+ .p Пример: `[get(481395, 2, 4)]` връща `[813]`
-- `remove`, която приема число, начален индекс и дължина (в този ред)
+- `[remove]`, която приема число, начален индекс и дължина (в този ред)\n
Връща числото, без "дължина" на брой цифри от началния индекс
- Пример: `remove(481395, 3, 3)` връща `485`
+ .p Пример: `[remove(481395, 3, 3)]` връща `[485]`
-- `insert`, която приема число, начален индекс, дължина и число за вмъкване
- Връща числото, като на началния индекс намираме началото на вмъкнатото число с дължина "дължина"
+- `[insert]`, която приема число, начален индекс, дължина и число за вмъкване\n
+ Връща числото, като на началния индекс намираме началото на вмъкнатото число с дължина "дължина"\n
Ефектът, е че числото се вмъква на дадения индекс, обаче избутва цифрите в ляво от него, вместо тези от дясно.
- Пример: `insert(495, 2, 4, 1001)` връща `4100195`
+ .p Пример: `[insert(495, 2, 4, 1001)]` връща `[4100195]`
+
### Подточка б) Композитните функции
Сега е време да имплементираме съществената логика в задачата.
-Използвайки **само** примитивните функции, имплементирайте функциите:
+Използвайки =[само]= примитивните функции, имплементирайте функциите:
-- `copy`, която приема число, начален индекс, дължина и втори начален индекс
+:unordered
+- `[copy]`, която приема число, начален индекс, дължина и втори начален индекс\n
Връща числото, като от втория начален индекс, следващите "дължина" на брой цифри съвпадат с "дължина" на брой цифри от първия начален индекс
- Пример: `copy(481395, 3, 4, 2)` връща `4139581395`
+ .p Пример: `[copy(481395, 3, 4, 2)]` връща `[4139581395]`
-- `cut`, която приема число, начален индекс, дължина и втори начален индекс
+- `[cut]`, която приема число, начален индекс, дължина и втори начален индекс\n
Връща числото, като "дължина" на брой цифри от (стария) начален индекс са преместени във втория начален индекс
- Пример: `cut(481395, 3, 4, 2)` връща `413958`
+ .p Пример: `[cut(481395, 3, 4, 2)]` връща `[413958]`
-- `replace`, която приема число, начален индекс, дължина и число за замяна
- Връща числото, като "дължина" на брой цифри от начален индекс са заменени с числото за замяна
- Заменените цифри и числото за замяна **може да имат различни дължини**!
+- `[replace]`, която приема число, начален индекс, дължина и число за замяна\n
+ Връща числото, като "дължина" на брой цифри от начален индекс са заменени с числото за замяна\n
+ Заменените цифри и числото за замяна =[може да имат различни дължини]=!
- Пример: `replace(481395, 4, 2, 705)` връща `4817055`
+ .p Пример: `[replace(481395, 4, 2, 705)]` връща `[4817055]`
-- `prepend`, която приема две числа
+- `[prepend]`, която приема две числа\n
Връща долепени второто и първото число
- Пример: `prepend(395, 81)` връща `81395`
+ .p Пример: `[prepend(395, 81)]` връща `[81395]`
-- `append`, която приема две числа
+- `[append]`, която приема две числа\n
Връща долепени първото и второто число
- Пример: `append(395, 81)` връща `39581`
+ .p Пример: `[append(395, 81)]` връща `[39581]`
+
### Подточка в) Вход и изход
Последно, време е да имплементираме интерфейса на програмата.
-Както вече казахме, първия вход е числото `N` с което ще извършим операция.
+Както вече казахме, първия вход е числото `[N]` с което ще извършим операция.
-След това приемаме буква, която определя нашата (композитна) функция, като за всички функции използваме първата буква в името им, освен за `cut`, за която използваме `x`.
-Тоест, `c` означава, че ще "copy"-ваме, `p` че ще "prepend"-ваме, `x` че ще "cut"-ваме и так. нат.
+След това приемаме буква, която определя нашата (композитна) функция, като за всички функции използваме първата буква в името им, освен за `[cut]`, за която използваме `[x]`.
+Тоест, `[c]` означава, че ще "copy"-ваме, `[p]` че ще "prepend"-ваме, `[x]` че ще "cut"-ваме и так. нат.
След като въведем буква, трябва да приемем съответния за дадената функция брой аргументи и да изкараме на екрана резултата от функцията.
-**Примери**
+=[Примери]=
-|Вход|Изход|
-|----|-----|
-|x 8504830028402847111 9 6 7|8504832840280047111|
-|p 8 968824945839039458|9688249458390394588|
-|a 968824945839039458 1|9688249458390394581|
-|r 9938175002843839 1 10 86998385021|86998385021843839|
+.table
+|=Вход=||=Изход=|
+|:x 8504830028402847111 9 6 7:||:8504832840280047111:|
+|:p 8 968824945839039458:||:9688249458390394588:|
+|:a 968824945839039458 1:||:9688249458390394581:|
+|:r 9938175002843839 1 10 86998385021:||:86998385021843839:|
## Задача 2 - Умножение на полиноми
@@ -95,27 +101,25 @@ GitHub classroom: [classroom.github.com/a/jqKaO1ny](https://classroom.github.com
Числото с коефициенти е между 1 и 10000000000000000000.
Пример: първото число е 13, a второто е 3052.
-Побитово `13 = 1101`, тоест ще имаме
+Побитово `[13 = 1101]`, тоест ще имаме
```
x³ * 1 + x² * 1 + x¹ * 0 + x⁰ * 1
-```
След това, от второто получаваме всеки коефициент, става
```
-3 * x³ * 1 + 0 * x² * 1 + 5 * x¹ * 0 + 2 * x⁰ * 1
-```
+3 * x³* 1 + 0 * x² * 1 + 5 * x¹ * 0 + 2 * x⁰ * 1
-Финално, нашия полином, кодиран от числата 13 и 3052 е `3x³ + 2`.
+Финално, нашия полином, кодиран от числата 13 и 3052 е `[3x³ + 2]`.
От входа получавате два полинома, трябва да ги умножите и да изкарате получилия се полином (пак във формата с две числа).
-**ВАЖНО:** В решението **НЕ** може да изполвате масиви, вектори, ..., както и каквито и да е функции, които не сте написали вие!
+=[ВАЖНО:]= В решението =[НЕ]= може да изполвате масиви, вектори, ..., както и каквито и да е функции, които не сте написали вие!
## Задача 3 - Дъската на Зар
-*Името си го измислих, няма връзка с нещо :)*
+*[Името си го измислих, няма връзка с нещо :)]*
Дъската на Зар е една много проста игра.
Имаме два играча, които играят върху квадратна дъска, като на всяка "клетка" има цифра (0 до 9).
@@ -129,7 +133,7 @@ x³ * 1 + x² * 1 + x¹ * 0 + x⁰ * 1
Пример: ако играем с дъска 5х5, намираме се на реда "25486" и позицията на първия играч е първата, тогава ходът му изглежда така (с "V" показваме къде се намира):
-```
+:code
V
25486
Прочита цифрата 2, значи трябва да се премести с две клетки на дясно
@@ -142,7 +146,7 @@ V
25486
Прочита цифрата 8, трябва да се премести с осем клетки на дясно
Обаче редът е твърде къс, премества се с една клетка и на следващия си ход ще се премести със 7 клетки надясно
-```
+
Обаче, правилата между първия и втория играч са малко по-различни.
Първия играч започва от първата клетка на първия ред, докато втория започва от първата клетка, до която първия играч не е бил.
@@ -157,11 +161,11 @@ V
Накрая на играта, трябва да сравните точките на първия и втория играч и да изкарате кой е победил (или дали никой не е).
Един ред може да се представи като цяло число и обработваме ред по ред, без да се връщаме назад.
-Тоест, първо от входа получавате число `N`, което е размера на дъската.
-След това ще получавате `N` числа, всяко с `N` цифри в десетичния си запис, като след получаване на едно число изпълнявате ходовете на всички играчи.
+Тоест, първо от входа получавате число `[N]`, което е размера на дъската.
+След това ще получавате `[N]` числа, всяко с `[N]` цифри в десетичния си запис, като след получаване на едно число изпълнявате ходовете на всички играчи.
-**ВАЖНО:** В решението **НЕ** може да изполвате масиви, вектори, ..., както и каквито и да е функции, които не сте написали вие!
+=[ВАЖНО:]= В решението =[НЕ]= може да изполвате масиви, вектори, ..., както и каквито и да е функции, които не сте написали вие!
-**Упътване:**
+=[Упътване:]=
Лесно се получава, ако занулим цифрите които първия играч е посетил.
Още по-лесно става ако използвате функции от първата задача.
diff --git a/src/teaching/upp-2023/week4/revision.md b/src/teaching/upp-2023/week4/revision.du
index 3650875..c99fbb4 100644
--- a/src/teaching/upp-2023/week4/revision.md
+++ b/src/teaching/upp-2023/week4/revision.du
@@ -1,48 +1,48 @@
# Преговор - УПП, Седмица 4, 27.10.2023
-&.presentation
+[$presentation-controller]
-&[title35
+:title_slide35
# Функции и алгоритмични задачи
-&]
-
-
-&[slide27
+:slide27
## От сега нататък ще направим няколко промени
+:unordered
- Вместо много и лесни задачи ще давам малко и трудни задачи
+ .bulleted
- Контролното наближава, а резултата от задачата на семинара не е добър
- Моето впечатление е, че повечето които имат опит с програмиране нямат много опит с алгоритмични задачи и обратно
- Задачите ще са повече алгоритмични, лесните задачи ще виждате на семинар
+
- Ще изисквам добър стил при писане на код
- - Това означава добре подравнен код, празни символи около оператори **и** свестни имена на променливи
+ .bulleted
+ - Това означава добре подравнен код, празни символи около оператори =[и]= свестни имена на променливи
- Името на променлива не трябва да бъде 150 знака, но трябва да е разбираемо какво съдържа
- - **Без шльокавица!**
+ - =[Без шльокавица!]=
+
- Преговорът ще бъде за вас да си го четете (освен ако не трябва да преподам нещо ново)
-- Ще може да предавате задания след срока!
+- Ще може да предавате задания след срока!\n
Искам да решите колкото се може повече вкъщи.
-&]
-
-*Нещата за 2s compliment се намират и в [преговора на миналата седмица](../week3/revision.html?a), ама го написах след като свърши часа, затова го копирам и тук.*
+*[Нещата за 2s compliment се намират и в [url ../week3/revision.html?a преговора на миналата седмица], ама го написах след като свърши часа, затова го копирам и тук.]*
-
-
-&[slide
+:slide
## 2s compliment
+.p
Интуитивно обяснение на 2s compliment.
Да приемем, че работим с тип данни, при който имаме само 3 бита.
+.p
Как бихме ги използвали, за да представим отрицателните числа?
-Най-лесния начин е да погледнем най-левия (старшия) бит, ако е 0 значи е положително, ако е 1 значи е отрицателно, тоест `010` е 2, докато `110` е -2.
+Най-лесния начин е да погледнем най-левия (старшия) бит, ако е 0 значи е положително, ако е 1 значи е отрицателно, тоест `[010]` е 2, докато `[110]` е -2.
Ако разпишем всичките ни числа:
```
@@ -54,67 +54,61 @@
010 2
001 1
000 0
-```
-
-&]
+:middle_slide
-&[middle
-
+.p
Това работи, обаче имаме един гигантски проблем: събирането не работи!
От математика знаем, че "2 - 1 = 2 + (-1)", тоест би трябвало да можем да съберем побитово 2 и -1 и да получим 1.
Ама,
```
2 + -1 = 010 + 101 = 111 = -3
-```
+.p
Също, знаем, че "(-1) + (-1) = -2", обаче
```
-1 + -1 = 101 + 101 = 1010 имаме overflow, това се съкращава на 010 = 2
-```
+.p
Излиза, че с тази схема не можем да събираме отрицателни числа както събираме положителни (или както събираме побитово).
+.p
Да не говорим, че ние имаме -0, което не ни трябва много.
-&]
-
+:middle_slide
-&[middle
-
+.p
Нека да помислим пак, да вземем само положителните:
```
011 3
010 2
001 1
-```
+.p
Сега, искаме -1 да бъде такова число, различно от досега дефинираните (тоест което има единица в старшия си бит) така че "1 + -1 = 0".
Лесно се досещаме, че ако добавим към "001" числото "111", тогава тяхната сума ще предизвика overflow и резултата ще бъде 0:
```
001 + 111 = 1000 overflow, става 000
-```
+.p
Нека тогава "-1 = 111".
-&]
-
+:slide
-&[slide
-
+.p
Правейки същото за "2 + -2", намираме че
```
010 + 110 = 1000 overflow, става 000
-```
+.p
Нека тогава "-2 = 110".
За "3 + -3" се досещаме, че "-3 = 101".
За сега имаме:
@@ -128,39 +122,34 @@
010 2
001 1
000 0
-```
+.p
100 не сме го използвали, обаче намерихме отрицателното число за всяко положително.
Да видим как работим с него, побитово "100 + 001 = 101", тоест "x + 1 = -3", следователно x ще бъде -4.
-&]
-
+:middle_slide
-&[middle
-
+.p
Това е идеята на "complements", дефинираме отрицателни числа, така че да използваме едно и също събиране между положителни и отрицателни.
-Още от много старите "калкулатори" ([сумиращи машини](https://en.wikipedia.org/wiki/Adding_machine)), изваждането се е свеждало до събиране на положително и отрицателно число.
+.p
+Още от много старите "калкулатори" ([url https://en.wikipedia.org/wiki/Adding_machine сумиращи машини]), изваждането се е свеждало до събиране на положително и отрицателно число.
-И това е причината защо `~ 2` връща `-3`:
+.p
+И това е причината защо `[~ 2]` връща `[-3]`:
```
~ 00000000000000000000000000000010
──────────────────────────────────
11111111111111111111111111111101
-```
-И затова при `>>` със знаков тип имаме аритметическо отместване:
+И затова при `[>>]` със знаков тип имаме аритметическо отместване:
```
11111111111111111111111111111101 >> 1
─────────────────────────────────────
11111111111111111111111111111110
-```
-
-&]
-
## Функции
@@ -172,20 +161,19 @@
<ВЪРНАТ ТИП> име(<АРГУМЕНТИ>) {
тяло
}
-```
-Като `<АРГУМЕНТИ>` са двойки от типа `ТИП ИМЕ`, разделени със запетаи.
-Един вид, аргументите са променливи към `тяло`, които задаваме извън функцията.
+Като `[<АРГУМЕНТИ>]` са двойки от типа `[ТИП ИМЕ]`, разделени със запетаи.
+Един вид, аргументите са променливи към `[тяло]`, които задаваме извън функцията.
-Извикваме функция чрез `име(<СТОЙНОСТИ>)`, като `<СТОЙНОСТИ>` са разделени със запетая и всяка съответства на поредния тип в аргументите на функцията.
-Там, където пишем `име(<СТОЙНОСТИ>)` се "замества" с върнатата стойност от функцията.
+Извикваме функция чрез `[име(<СТОЙНОСТИ>)]`, като `[<СТОЙНОСТИ>]` са разделени със запетая и всяка съответства на поредния тип в аргументите на функцията.
+Там, където пишем `[име(<СТОЙНОСТИ>)]` се "замества" с върнатата стойност от функцията.
-Връщаме стойност като напишем във функцията `return СТОЙНОСТ;`.
+Връщаме стойност като напишем във функцията `[return СТОЙНОСТ;]`.
Една функция трябва да бъде декларирана преди да бъде използвана, тоест кода
-```cpp
-#include <iostream>
+:code_cpp
+#include \<iostream>
int main() {
std::cout << doSomething();
@@ -194,19 +182,18 @@ int main() {
int doSomething() {
...
}
-```
+
Няма да се компилира.
Можем само да декларираме функция, без да я дефинираме (тоест без да и дадем тяло) чрез синтаксиса:
```cpp
<ВЪРНАТ ТИП> име(<АРГУМЕНТИ>);
-```
Тоест горния пример ще работи ако имаме:
-```cpp
-#include <iostream>
+:code_cpp
+#include \<iostream>
int doSomething();
@@ -217,4 +204,3 @@ int main() {
int doSomething() {
...
}
-```
diff --git a/src/teaching/upp-2023/week5/index.md b/src/teaching/upp-2023/week5/index.du
index 57f9239..0695f17 100644
--- a/src/teaching/upp-2023/week5/index.md
+++ b/src/teaching/upp-2023/week5/index.du
@@ -1,6 +1,8 @@
# Задачи - УПП, Седмица 5, 03.11.2023
-GitHub classroom: [classroom.github.com/a/3KoIQ71H](https://classroom.github.com/a/3KoIQ71H)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/3KoIQ71H classroom.github.com/a/3KoIQ71H]
## Задача 1
@@ -8,13 +10,13 @@ GitHub classroom: [classroom.github.com/a/3KoIQ71H](https://classroom.github.com
Направете функция, която получава два двуизмерни координата, покомпонентно ги сумира и връща резултатните координати.
Няма как функцията да върне две стойности, затова добаваете оше два аргумента, които да са указатели към променливи в които да запазим сумираните координати.
-От входа получавате два координата, след това връщате тяхната покомпонентна сума **използвайки функцията**.
+От входа получавате два координата, след това връщате тяхната покомпонентна сума =[използвайки функцията]=.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|8.0 1.5 -1.9 -100.741|6.1 -99.241|
+.table
+|=Вход=||=Изход=|
+|:8.0 1.5 -1.9 -100.741:||:6.1 -99.241:|
## Задача 2
@@ -22,62 +24,62 @@ GitHub classroom: [classroom.github.com/a/3KoIQ71H](https://classroom.github.com
Трябва да поддържате операциите събиране и изваждане между две такива числа.
Първо ще получите 30 цифри, които отговарят на първото числа, после още 30 цифри, които отговарят на втрото число и накрая ще получите знак.
-Ако знака е `+`, трябва да ги съберете и да изкарате резултата на екрана.
-Ако знака е `-`, трябва да ги извадите и да изкарате резултата на екрана.
+Ако знака е `[+]`, трябва да ги съберете и да изкарате резултата на екрана.
+Ако знака е `[-]`, трябва да ги извадите и да изкарате резултата на екрана.
При изкарване трябва да следвате "нормалните" правила: цифрите са долепени и водещите нули не се пишат.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|0 0 0 0 0 0 4 6 9 2 7 5 2 2 3 3 4 2 9 5 7 4 2 3 3 7 1 9 2 6<br>0 0 0 0 0 0 0 0 0 9 3 4 2 1 6 0 3 3 5 5 1 0 1 3 0 0 0 6 3 2<br>+|470209439376508436372558|
-|0 0 0 0 0 0 4 6 9 2 7 5 2 2 3 3 4 2 9 5 7 4 2 3 3 7 1 9 2 6<br>0 0 0 0 0 0 0 0 0 9 3 4 2 1 6 0 3 3 5 5 1 0 1 3 0 0 0 6 3 2<br>-|468341007309406410371294|
-|9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9<br>0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1<br>+|0|
-|0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0<br>0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1<br>-|999999999999999999999999999999|
+.table
+|=Вход=||=Изход=|
+|:0 0 0 0 0 0 4 6 9 2 7 5 2 2 3 3 4 2 9 5 7 4 2 3 3 7 1 9 2 6\n0 0 0 0 0 0 0 0 0 9 3 4 2 1 6 0 3 3 5 5 1 0 1 3 0 0 0 6 3 2\n+:||:470209439376508436372558:|
+|:0 0 0 0 0 0 4 6 9 2 7 5 2 2 3 3 4 2 9 5 7 4 2 3 3 7 1 9 2 6\n0 0 0 0 0 0 0 0 0 9 3 4 2 1 6 0 3 3 5 5 1 0 1 3 0 0 0 6 3 2\n-:||:468341007309406410371294:|
+|:9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9 9\n0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1\n+:||:0:|
+|:0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1\n-:||:999999999999999999999999999999:|
## Задача 3
Получавате редица цифри.
Ако имаме поне 3 повтарящи се цифри една след друга, можем да ги премахнем.
-Тоест редицата `0 3 1 2 2 2 4 7` може да стане `0 3 1 4 7`.
+Тоест редицата `[0 3 1 2 2 2 4 7]` може да стане `[0 3 1 4 7]`.
След едно премахване, трябва да можем после да премахнем новопоявило се премахване.
-Тоест редицата `5 1 3 3 3 3 1 1 1 9 2` първо става `5 1 1 1 1 9 2` и след това `5 9 2`.
+Тоест редицата `[5 1 3 3 3 3 1 1 1 9 2]` първо става `[5 1 1 1 1 9 2]` и след това `[5 9 2]`.
Не е нужно да гледате напред за възможно най-много премахване.
-Тоест в случая `8 1 3 4 4 4 5 5 5 5 4 4` не се очаква да предвидите, че ако първо премахнете 5-те, после ще може да премахнете всички 4ки.
+Тоест в случая `[8 1 3 4 4 4 5 5 5 5 4 4]` не се очаква да предвидите, че ако първо премахнете 5-те, после ще може да премахнете всички 4ки.
Премахвате първата валидна повтаряща се редица, връщате се малко назад, поглеждате дали някоя нова редица не се е появила, премахвате нея или отивате на следващата.
-От входа първо получавате броя `N` на цифрите в редицата, като `N` е между 1 и 40.
-След това получавате `N` на брой цифри и накрая връщате редицата с премахнати повтаряния.
+От входа първо получавате броя `[N]` на цифрите в редицата, като `[N]` е между 1 и 40.
+След това получавате `[N]` на брой цифри и накрая връщате редицата с премахнати повтаряния.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|16<br>1 3 8 8 7 5 5 5 5 7 7 8 8 8 8 6|1 3 6|
-|40<br>7 1 5 2 1 7 2 1 2 1 7 2 6 1 6 7 6 9 7 3 8 6 6 5 1 2 7 4 6 8 3 8 2 2 6 9 4 2 6 5|7 1 5 2 1 7 2 1 2 1 7 2 6 1 6 7 6 9 7 3 8 6 6 5 1 2 7 4 6 8 3 8 2 2 6 9 4 2 6 5|
+.table
+|=Вход=||=Изход=|
+|:16\n1 3 8 8 7 5 5 5 5 7 7 8 8 8 8 6:||:1 3 6:|
+|:40\n7 1 5 2 1 7 2 1 2 1 7 2 6 1 6 7 6 9 7 3 8 6 6 5 1 2 7 4 6 8 3 8 2 2 6 9 4 2 6 5:||:7 1 5 2 1 7 2 1 2 1 7 2 6 1 6 7 6 9 7 3 8 6 6 5 1 2 7 4 6 8 3 8 2 2 6 9 4 2 6 5:|
## Задача 4
Получавате редица числа.
Всяко число е индекс към друго число в редицата (индексите започва от 0).
-Започвайки от всяка цифра, проследяваме всички "скоци", тоест ако имаме `1 3 0 2` и започваме от индекс 0, тогава от него скачаме на индекс 1, от него на индекс 3, от него на индекс 2 и от него се връщаме в индекс 0.
-Докато прескачаме не може да посетим вече посетен индекс, тоест ако имаме `1 3 0 1`, от 0 отиваме в 1, от 1 в 3 и от 3 в 1, обаче вече сме посетили индекс 1, така че спираме да скачаме.
+Започвайки от всяка цифра, проследяваме всички "скоци", тоест ако имаме `[1 3 0 2]` и започваме от индекс 0, тогава от него скачаме на индекс 1, от него на индекс 3, от него на индекс 2 и от него се връщаме в индекс 0.
+Докато прескачаме не може да посетим вече посетен индекс, тоест ако имаме `[1 3 0 1]`, от 0 отиваме в 1, от 1 в 3 и от 3 в 1, обаче вече сме посетили индекс 1, така че спираме да скачаме.
Търси се колко най-много скока можем да направим, започайки от който и да е индекс.
Ако има няколко индекса с максималния брой скоци, връщаме само първия.
-Получавате от входа брой `N` на числата (индексите), като `N` е между 1 и 30, след това получавате толкова на брой числа (между 0 и N-1) и накрая връщате при кой начален индекс имаме най-много скока и колко са тези скоци.
+Получавате от входа брой `[N]` на числата (индексите), като `[N]` е между 1 и 30, след това получавате толкова на брой числа (между 0 и N-1) и накрая връщате при кой начален индекс имаме най-много скока и колко са тези скоци.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|9<br>4 6 2 1 5 0 0 3 8|7 7|
-|20<br>16 10 6 11 1 1 9 12 15 17 0 0 9 15 8 16 7 0 16 18|4 9|
-|30<br>0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29|0 1|
-|30<br>29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0|0 2|
+.table
+|=Вход=||=Изход=|
+|:9\n4 6 2 1 5 0 0 3 8:||:7 7:|
+|:20\n16 10 6 11 1 1 9 12 15 17 0 0 9 15 8 16 7 0 16 18:||:4 9:|
+|:30\n0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29:||:0 1:|
+|:30\n29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0:||:0 2:|
## Задача 5
@@ -89,12 +91,13 @@ sim картите са типове smart-card, това означава че
### а) валидационни функции
-- `isUnblockCode`, приема буква и връща дали е отблокиращ код
+.bulleted
+- `[isUnblockCode]`, приема буква и връща дали е отблокиращ код\n
Само главни, малки и цифри са валидни отблокиращи кодове
-- `isPhoneNumber`, приема число (10 цифрено) и поглежда най-левите 3 цифри
+- `[isPhoneNumber]`, приема число (10 цифрено) и поглежда най-левите 3 цифри\n
Те трябва да са валиден код на държава.
Нужно е да приемате поне кодовете за България (359) и за Франция (033).
- Ако искате може и други да приемате, пълен списък има [тук](https://en.wikipedia.org/wiki/List_of_country_calling_codes#Alphabetical_order).
+ Ако искате може и други да приемате, пълен списък има [url https://en.wikipedia.org/wiki/List_of_country_calling_codes#Alphabetical_order тук].
### б) вход и команди
@@ -102,19 +105,20 @@ sim картите са типове smart-card, това означава че
Ако отблокиращия е в невалиден формат, връщате съответно съобщение за грешка и спирате програмата.
След това получавате команди, всяка команда се определя с букви и още някакви стойности.
-**Всяка команда трябва да бъде изкарана в отделна функция!**
+=[Всяка команда трябва да бъде изкарана в отделна функция!]=
-- `v` - пробвате се да се "логнете" в сим картата.
+.bulleted
+- `[v]` - пробвате се да се "логнете" в сим картата.
След буквата получавате и едно число, което е въведения ПИН код.
Ако е правилен, следващите 5 команди, които изискват упълномощение могат да се изпълнят.
След 5те команди, упълномощението се "премахва" и трябва пак да се въведе ПИН код при упълномощени команди.
Ако е грешен, общо има 3 опита, и след тях картата се блокира.
-- `u` - отпблокиране на блокирана карта.
+- `[u]` - отпблокиране на блокирана карта.
След буквата получавате отблокиращ код и нов ПИН код.
Ако отблокиращия код е в грешен формат или е грешната стойност, премахваме един опит.
При 10 неуспешни опита, изкарвате съобщение, че картата е перманентно блокирана и спирате програмата.
Ако е успешно отблокирана, тогава променяте ПИН кода и сте се "логнали" автоматично.
-- `i` - връща информация за СИМ картата, това са общо броя команди които са изпълнявани до сега
+- `[i]` - връща информация за СИМ картата, това са общо броя команди които са изпълнявани до сега
### в) команди с упълномощение
@@ -123,15 +127,16 @@ sim картите са типове smart-card, това означава че
Ако някоя търсена стойност е невалидна или не съществува, връщате съответната грешка.
-- `c` - променя ПИН код.
+.bulleted
+- `[c]` - променя ПИН код.
Получавате нов ПИН код и го променяте.
-- `a` - добавя контакт в паметта, общо може да имаме 10 контакта.
+- `[a]` - добавя контакт в паметта, общо може да имаме 10 контакта.
Всеки контакт се определя с буква, неговото "име", и 10-цифрен мобилен номер.
Приема допълнително неговото име и тел. номер.
Добавяме контакта в първото незаето място, а ако всички са заети, връщаме съобщение с грешка.
-- `r` - приема и още една буква (име), връща телефонния номер на съответния контакт.
+- `[r]` - приема и още една буква (име), връща телефонния номер на съответния контакт.
Ако той не съществува или телефонния номер е невалиден, връщаме съответно съобщение с грешка.
-- `d` - приема и още една буква (име), изтрива съответния контакт.
+- `[d]` - приема и още една буква (име), изтрива съответния контакт.
Ако той не съществува, връщаме съответно съобщение с грешка.
-- `o` - променя контакт, приема допълнително две имена на контакти и телефонен номер.
+- `[o]` - променя контакт, приема допълнително две имена на контакти и телефонен номер.
Променя контакта с първото име, като второто име и тел. номер стават новите му стойности.
diff --git a/src/teaching/upp-2023/week5/revision.md b/src/teaching/upp-2023/week5/revision.du
index 4356848..017b2a1 100644
--- a/src/teaching/upp-2023/week5/revision.md
+++ b/src/teaching/upp-2023/week5/revision.du
@@ -6,45 +6,40 @@
За да можем да определим къде дадено нещо е запазено, всяка клетка в паметта си има "адрес".
Адресът е едно цяло положително число.
-Можем да вземем адреса на дадена променлива с оператора `&`:
+Можем да вземем адреса на дадена променлива с оператора `[&]`:
```cpp
double a = 3.14159;
std::cout << (&a) << std::endl;
-```
-Tази програма ще върне адресът на променлива `a`.
+Tази програма ще върне адресът на променлива `[a]`.
След като имаме адрес, бихме искали да работим със стойността на този адрес.
-Това го правим с дерефериращия оператор `*`:
+Това го правим с дерефериращия оператор `[*]`:
```cpp
double a = 3.14159;
std::cout << (*(&a)) << std::endl;
-```
-Тази програма връща стойността на адреса на променлива `a`.
+Тази програма връща стойността на адреса на променлива `[a]`.
Променливи, които съдържат адреси се наричат указатели.
Синтаксисът на един указател е:
```cpp
<ТИП НА СТОЙНОСТТА> * <ИМЕ> = <АДРЕС>;
-```
Тоест примерно:
```cpp
double a = 3.14159;
double * pointer = &a;
-```
Звездата може да бъде долепена до типа или името на указателя:
```cpp
double* pointer1 = &a;
double *pointer2 = &a;
-```
## Масиви
@@ -59,25 +54,22 @@ double *pointer2 = &a;
<ТИП> <ИМЕ>[N]; // само ги дефинираме, обаче не ги инициализираме
<ТИП> <ИМЕ>[N] = { <СТОЙНОСТ> }; // дефинира всички N елементи със <СТОЙНОСТ>
<ТИП> <ИМЕ>[N] = { <СТОЙНОСТ 1>, <СТОЙНОСТ 2>, ..., <СТОЙНОСТ M> }; // където M <= N
-```
-Самото `<ИМЕ>` е указател, така че може да достъпваме стойности чрез указателна аритметика:
+Самото `[<ИМЕ>]` е указател, така че може да достъпваме стойности чрез указателна аритметика:
```cpp
int arr[2] = { 83, 18 };
std::cout << (*(arr + 1)) << std::endl;
-```
-Връща втория елемент, `18`.
+Връща втория елемент, `[18]`.
Или чрез по-приятния синтаксис с квадратни скоби:
```cpp
int arr[2] = { 83, 18 };
std::cout << (arr[1]) << std::endl;
-```
-Двете неща са еквивалентни, тоест `name[x]` е еквивалентно на `*(name + x)`.
+Двете неща са еквивалентни, тоест `[name[x]]` е еквивалентно на `[*(name + x)]`.
Когато един масив съдържа букви, наричаме го "низ" (string).
-За да не трябва да следим дължината на един низ в друга променлива и да трябва да я подаваме, винаги завършваме нашия низ на "терминаращата нула" - `'\0'`.
+За да не трябва да следим дължината на един низ в друга променлива и да трябва да я подаваме, винаги завършваме нашия низ на "терминаращата нула" - `['\0']`.
diff --git a/src/teaching/upp-2023/week6/index.md b/src/teaching/upp-2023/week6/index.du
index 34c3f53..4daa76b 100644
--- a/src/teaching/upp-2023/week6/index.md
+++ b/src/teaching/upp-2023/week6/index.du
@@ -1,6 +1,8 @@
# Задачи - УПП, Седмица 6, 10.11.2023
-GitHub classroom: [classroom.github.com/a/BBLlWMOy](https://classroom.github.com/a/BBLlWMOy)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/BBLlWMOy classroom.github.com/a/BBLlWMOy]
## Задача 1
@@ -10,31 +12,31 @@ GitHub classroom: [classroom.github.com/a/BBLlWMOy](https://classroom.github.com
N и M са между 1 и 60.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|4 3<br>8 1 9<br>0 3 0<br>4 7 5<br>6 9 0<br>9 5 7 3<br>6 7 2 0<br>1 3 3 7<br>| 87 74 85 87<br>18 21 6 0<br>83 84 57 47<br>108 93 60 18<br>|
+.table
+|=Вход=||=Изход=|
+|:4 3\n8 1 9\n0 3 0\n4 7 5\n6 9 0\n9 5 7 3\n6 7 2 0\n1 3 3 7\n:||: 87 74 85 87\n18 21 6 0\n83 84 57 47\n108 93 60 18\n:|
## Задача 2
Разглеждаме числатата от 0 до N.
За всяко число знаем колко интервала го включват (покриват).
-Тоест в `0 1 1 0` означава, че 0 интервала "покриват" числото 0, един интервал покрива числото 1, един интервал покрива числото 2 и 0 покриват числото 3.
+Тоест в `[0 1 1 0]` означава, че 0 интервала "покриват" числото 0, един интервал покрива числото 1, един интервал покрива числото 2 и 0 покриват числото 3.
Търси се колко различни интервала имаме.
Не различаваме между два долепени интервала и един дълъг интервал.
От входа получаввате N (от 1 до 30), и след това N на брой числа: броя покриващи интервали за всички числа от 0 до N-1.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|5<br>1 1 0 1 1|2|
-|5<br>1 2 1 2 1|3|
-|5<br>9 5 2 9 0|16|
-|11<br>1 1 2 3 2 2 4 2 1 1 1|5|
+.table
+|=Вход=||=Изход=|
+|:5\n1 1 0 1 1:||:2:|
+|:5\n1 2 1 2 1:||:3:|
+|:5\n9 5 2 9 0:||:16:|
+|:11\n1 1 2 3 2 2 4 2 1 1 1:||:5:|
## Задача 3
@@ -47,19 +49,19 @@ N и M са между 1 и 60.
В случай, че игралното поле се запълни и никой не е спечелил, след последното му изкарване трябва да върнете "Draw!" и да спрете програмата.
-**Пример:**
-*Смесен вход/изход, вход е означен с "$ " преди него*
+=[Пример:]=
+*[Смесен вход/изход, вход е означен с "$ " преди него]*
```
-
-
-
+\n
+\n
+\n
$ 5
-
+\n
X
-
+\n
$ 9
-
+\n
X
O
$ 3
@@ -79,13 +81,12 @@ X X
X
OOO
O wins!
-```
-**Бонус:** направете го да работи с NxN брой клетки, като N е число между 1 и 50.
+=[Бонус:]= направете го да работи с NxN брой клетки, като N е число между 1 и 50.
## Задача 4
-Имплементирайте играта [chomp](https://en.wikipedia.org/wiki/Chomp): представете си, че имаме един шоколад, разделен на NxM квадратчета.
+Имплементирайте играта [url https://en.wikipedia.org/wiki/Chomp chomp]: представете си, че имаме един шоколад, разделен на NxM квадратчета.
Всеки играч избира квадратче (координати), след това изяжда всички парчета, които са в дясно или надолу от квадратчето.
Играчът, който изяде квадратчето в горния ляв ъгъл губи играта.
@@ -94,8 +95,8 @@ O wins!
Редуват се първия и втория играч, като всеки въвежда две числа - координати в шоколада (между 1 и N за реда и 1 и M за колоната).
Когато някой изяде парчето в горния ляв ъгъл, програмата изкарва "PLAYER wins!" (PLAYER е 1 или 2) и спира изпълнение.
-**Пример**
-*Смесен вход/изход, вход е означен с "$ " преди него*
+=[Пример]=
+*[Смесен вход/изход, вход е означен с "$ " преди него]*
```
4 5
@@ -112,28 +113,27 @@ $ 4 2
#####
#####
####
-#
+# \n
$ 1 2
-#
-#
-#
-#
+# \n
+# \n
+# \n
+# \n
$ 2 1
-#
-
-
-
+# \n
+ \n
+ \n
+ \n
$ 1 1
-
-
-
-
+ \n
+ \n
+ \n
+ \n
2 wins!
-```
## Задача 5
-**Тази задача е много трудна, proceed with caution!**
+=[Тази задача е много трудна, proceed with caution!]=
Ще имплементираме програма, която "симулира" един елементарен компютър.
Компютъра ни, като всеки друг, работи само и единствено с цели неотрицателни числа.
@@ -144,33 +144,35 @@ $ 1 1
Започваме изпълнение от началото на паметта, след като изпълним една инструкция, изпълняваме тази директно до нея, и така докато не стигнем инструкцията "EXT".
В такъв случай, изкарваме стойността в регистър B и спираме програмата.
-Това са командите, описани във формата "D - `A B C`", като D е число, съответстващо на инструкцията с име `A` (името го използваме за нас, в кода то не присъства) и аргументи след името `B` и `C`.
-`MEMORY` е число, съответстващо на индекс (адрес) в паметта на компютъра (между 0 и 127), а `VALUE` е произволна числова стойност.
+Това са командите, описани във формата "D - `[A B C]`", като D е число, съответстващо на инструкцията с име `[A]` (името го използваме за нас, в кода то не присъства) и аргументи след името `[B]` и `[C]`.
+`[MEMORY]` е число, съответстващо на индекс (адрес) в паметта на компютъра (между 0 и 127), а `[VALUE]` е произволна числова стойност.
+
+:unordered
+- 0 - `[EXT]` - край на изпълнението на програмата в симулирания компютър
-- 0 - `EXT` - край на изпълнението на програмата в симулирания компютър
+- 1 - `[INC MEMORY]` - инкрементира стойността на индекс `[MEMORY]`\n
+ Пример: `[0 2]` - инкрементира стойността на индекс 2
-- 1 - `INC MEMORY` - инкрементира стойността на индекс `MEMORY`
- Пример: `0 2` - инкрементира стойността на индекс 2
+- 2 - `[RIN VALUE MEMORY]` - инкрементира стойността на индекс `[VALUE + MEMORY]`\n
+ Пример: `[1 3 6]` - инкрементира стойността на адрес `[3 + 6 = 9]`
-- 2 - `RIN VALUE MEMORY` - инкрементира стойността на индекс `VALUE + MEMORY`
- Пример: `1 3 6` - инкрементира стойността на адрес `3 + 6 = 9`
+- 3 - `[DEC MEMORY]` - декрементира стойността на индекс `[MEMORY]`
-- 3 - `DEC MEMORY` - декрементира стойността на индекс `MEMORY`
+- 4 - `[RDE VALUE MEMORY]` - декрементира стойността на индекс `[VALUE + MEMORY]`
-- 4 - `RDE VALUE MEMORY` - декрементира стойността на индекс `VALUE + MEMORY`
+- 5 - `[STA MEMORY]` - запазва стойността на индекс `[MEMORY]` в регистъра А\n
+ Пример: `[4 19]` - запазва стойността на индекс 19 в регистъра А
-- 5 - `STA MEMORY` - запазва стойността на индекс `MEMORY` в регистъра А
- Пример: `4 19` - запазва стойността на индекс 19 в регистъра А
+- 6 - `[RST VALUE MEMORY]` - запазва стойността на адрес `[VALUE + MEMORY]` в регистър А\n
+ Пример: `[5 2 14]` - запазва стойността на индекс `[2 + 14 = 16]` в регистър А
-- 6 - `RST VALUE MEMORY` - запазва стойността на адрес `VALUE + MEMORY` в регистър А
- Пример: `5 2 14` - запазва стойността на индекс `2 + 14 = 16` в регистър А
+- 7 - `[STB MEMORY]` - запазва стойността на индекс `[MEMORY]` в регистъра B
-- 7 - `STB MEMORY` - запазва стойността на индекс `MEMORY` в регистъра B
+- 8 - `[BEQ MEMORY]` - продължава изпълнение от индекс `[MEMORY]`, ако стойността в регистъра А е нула\n
+ Пример: `[7 8]` - продължава изпълнение от индекс 8, ако стойността в регистър А е нула
-- 8 - `BEQ MEMORY` - продължава изпълнение от индекс `MEMORY`, ако стойността в регистъра А е нула
- Пример: `7 8` - продължава изпълнение от индекс 8, ако стойността в регистър А е нула
+- 9 - `[BNE MEMORY]` - продължава изпълнение от индекс `[MEMORY]`, ако стойността в регистъра А не е нула
-- 9 - `BNE MEMORY` - продължава изпълнение от индекс `MEMORY`, ако стойността в регистъра А не е нула
В началото получавате N, това са броя числа, които съставят цялата програма.
След това се въвеждат N числа, които са цялата програма.
@@ -178,20 +180,21 @@ $ 1 1
Ако по време на изпълнение стигнете до инструкция, която не е дефинирана, изкарвате "Error: undefined instruction!" и спирате програмата.
Ако някой аргумент е индекс в паметта, обаче стойността му е извън обхвата на паметта, изкарвате "Error: invalid memory address!" и спирате програмата.
-Ако няма грешка и програмата успешно стигне до `EXT` инструкция, както беше казано, изкарваме на екрана стойността в регистъра B.
+Ако няма грешка и програмата успешно стигне до `[EXT]` инструкция, както беше казано, изкарваме на екрана стойността в регистъра B.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|3 10 8 0|Error: undefined instruction!|
-|3 5 8000 0|Error: invalid memory address!|
-|6 1 3 7 3 0 958|959|
-|17 5 9 8 6 1 8 3 9 5 9 9 2 7 8 0 91461 772000|863461|
+.table
+|=Вход=||=Изход=|
+|:3 10 8 0:||:Error: undefined instruction!:|
+|:3 5 8000 0:||:Error: invalid memory address!:|
+|:6 1 3 7 3 0 958:||:959:|
+|:17 5 9 8 6 1 8 3 9 5 9 9 2 7 8 0 91461 772000:||:863461:|
-&:question Какво прави последната програма?
+.question Какво прави последната програма?
-**Бонус:** направете програми за симулаторния компютър, които
+=[Бонус:]= направете програми за симулаторния компютър, които\n
+.numbered
1. умножават числата 87401 и 37
2. намира сумата на числата 87, 305, 2, 612, 222
diff --git a/src/teaching/upp-2023/week7/index.md b/src/teaching/upp-2023/week7/index.du
index b216992..5e571aa 100644
--- a/src/teaching/upp-2023/week7/index.md
+++ b/src/teaching/upp-2023/week7/index.du
@@ -1,68 +1,69 @@
# Задачи - УПП, Седмица 7, 17.11.2023
-GitHub classroom: [classroom.github.com/a/m5M2_CWD](https://classroom.github.com/a/m5M2_CWD)
+\n
+
+GitHub classroom: [url https://classroom.github.com/a/m5M2_CWD classroom.github.com/a/m5M2_CWD]
## Задача 1
-*Това е почти същата задача като през [седмица 5](../week5/#1)*
+*[url ../week5/#1 Това е почти същата задача като през [седмица 5]]*
Дефинираме двуизмерен координат като две числа с плаваща запетая.
Направете функция, която получава два двуизмерни координата, покомпонентно ги сумира и връща резултатните координати.
Няма как функцията да върне две стойности, затова добаваете още два аргумента, които да са указатели към променливи в които да запазим сумираните координати.
-&:warn **Трябва** да използвате референции вместо указатели!
-
-От входа получавате два координата, след това връщате тяхната покомпонентна сума **използвайки функцията**.
+.warn =[Трябва]= да използвате референции вместо указатели!
-**Пример:**
+От входа получавате два координата, след това връщате тяхната покомпонентна сума =[използвайки функцията]=.
-|Вход|Изход|
-|----|-----|
-|8.0 1.5 -1.9 -100.741|6.1 -99.241|
+=[Пример:]=
+.table
+|=Вход=||=Изход=|
+|:8.0 1.5 -1.9 -100.741:||:6.1 -99.241:|
## Задача 2
-Един магазин продава три продукта, които ще бележим с `a`, `b` и `c`.
+Един магазин продава три продукта, които ще бележим с `[a]`, `[b]` и `[c]`.
Правим инвентарна система за тези продукти, като за всеки от тях пазим неговата бройка в склада.
В началото имаме 0 от всеки продукт.
-Получавате букви, докато не стигнете до буквата `$`.
-Ако буквата е `a`, `b` или `c`, тогава този продукт става "сегашния" продукт.
-Ако буквата е `S`, тогава намаляте бройката на сегашния продукт с 1, а ако е `R` - увеличаваме с 10.
+Получавате букви, докато не стигнете до буквата `[$]`.
+Ако буквата е `[a]`, `[b]` или `[c]`, тогава този продукт става "сегашния" продукт.
+Ако буквата е `[S]`, тогава намаляте бройката на сегашния продукт с 1, а ако е `[R]` - увеличаваме с 10.
-&:warn **НЕ** може да използвате масиви! **Трябва** действията на `S` и `R` да се изкарат във функции!
+.warn =[НЕ]= може да използвате масиви! =[Трябва]= действията на `[S]` и `[R]` да се изкарат във функции!
-Когато получите `$`, изкарвате броя на всеки продукт и спирате програмата.
+Когато получите `[$]`, изкарвате броя на всеки продукт и спирате програмата.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|a R R S S S S S S b R c b b R c R a S c S b S S S a R $|а: 23 b: 17 c: 9|
+.table
+|=Вход=||=Изход=|
+|:a R R S S S S S S b R c b b R c R a S c S b S S S a R $:||:а: 23 b: 17 c: 9:|
## Задача 3
-В началото получавате буква - тя съответства на дадена **функция**, след това получавате 5 числа с плаваща запетая.
+В началото получавате буква - тя съответства на дадена =[функция]=, след това получавате 5 числа с плаваща запетая.
След всяко въведено трябва да изкарате резултата от съответната функция при подадено входното число.
-&:warn **Трябва** да използвате указател към функция!
+.warn =[Трябва]= да използвате указател към функция!
Буквите съответстват на следните функции:
+.bulleted
+- `[a]` - модул на стойност
+- `[s]` - стойност на втора степен
+- `[h]` - занулена частта след запетаята
+- `[f]` - занулена частта преди (в ляво от) запетаята
-- `a` - модул на стойност
-- `s` - стойност на втора степен
-- `h` - занулена частта след запетаята
-- `f` - занулена частта преди (в ляво от) запетаята
-
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|a 0.5 -18.3 192.994 0 -0.003|0.5 18.3 192.994 0 0.003|
-|s 0.5 -18.3 192.994 0 -0.003|0.25 334.89 37246.67404 0 0.000009|
-|h 0.5 -18.3 192.994 0 -0.003|0 -18 192 0 0|
-|f 0.5 -18.3 192.994 0 -0.003|0.5 -0.3 0.994 0 -0.003|
+.table
+|=Вход=||=Изход=|
+|:a 0.5 -18.3 192.994 0 -0.003:||:0.5 18.3 192.994 0 0.003:|
+|:s 0.5 -18.3 192.994 0 -0.003:||:0.25 334.89 37246.67404 0 0.000009:|
+|:h 0.5 -18.3 192.994 0 -0.003:||:0 -18 192 0 0:|
+|:f 0.5 -18.3 192.994 0 -0.003:||:0.5 -0.3 0.994 0 -0.003:|
## Задача 4
@@ -75,48 +76,46 @@ GitHub classroom: [classroom.github.com/a/m5M2_CWD](https://classroom.github.com
```
N. [C] TASK
-```
-Където `N` е нейния номер (индекс), `C` е шпация или буквата "x" (шпация когато не е изпълнена, и "х" когато е), `TASK` е самия низ на задачата.
+Където `[N]` е нейния номер (индекс), `[C]` е шпация или буквата "x" (шпация когато не е изпълнена, и "х" когато е), `[TASK]` е самия низ на задачата.
-Програмата получава букви, докато не получи буквата `$`.
+Програмата получава букви, докато не получи буквата `[$]`.
Всяка буква определя някакво действие:
-
-- при `p` изкарваме на екрана всички задачи
-- при `d` изкарваме на екрана всички завършени задачи
-- при `t` изкарваме на екрана всички незавършени задачи
-- след `a` въвеждаме нова (незавършена) задача на последния свободен индекс
+.bulleted
+- при `[p]` изкарваме на екрана всички задачи
+- при `[d]` изкарваме на екрана всички завършени задачи
+- при `[t]` изкарваме на екрана всички незавършени задачи
+- след `[a]` въвеждаме нова (незавършена) задача на последния свободен индекс\n
Ако вече пазим 64 задачи, трябва да изкараме грешка на екрана и да продължим с програмата.
-- след `c` въвеждаме номер на задача и обръщаме нейната изпълненост: ако е изпълнена, става неизпълнена, и ако е неизпълнена, става изпълнена
+- след `[c]` въвеждаме номер на задача и обръщаме нейната изпълненост: ако е изпълнена, става неизпълнена, и ако е неизпълнена, става изпълнена
В началото на програмата нямаме никакви задачи.
-**Пример:**
-*Смесен вход/изход, изход е отбелязан с "> ". Забележете, че има шпации в края на низове за задачи.*
+=[Пример:]=
+*[Смесен вход/изход, изход е отбелязан с "> ". Забележете, че има шпации в края на низове за задачи.]*
```
a
-Do exercise 4
+Do exercise 4 \n
a
-Solve homework
+Solve homework\n
a
-Clean room
+Clean room \n
p
-> 1. [ ] Do exercise 4
-> 2. [ ] Solve homework
-> 3. [ ] Clean room
+> 1. [ Do exercise 4 \n
+> 2. [ Solve homework\n
+> 3. [ Clean room \n
c 2
p
-> 1. [ ] Do exercise 4
-> 2. [x] Solve homework
-> 3. [ ] Clean room
+> 1. [ Do exercise 4 \n
+> 2. [x] Solve homework\n
+> 3. [ Clean room \n
d
-> 2. [x] Solve homework
+> 2. [x] Solve homework\n
t
-> 1. [ ] Do exercise 4
-> 3. [ ] Clean room
+> 1. [ Do exercise 4 \n
+> 3. [ Clean room \n
$
-```
## Задача 5
@@ -126,18 +125,18 @@ $
В началото на програмата получавате едно изображение.
След това получавате произволен брой команди - букви с възможна последователност от стойности.
Трябва да имплементирате следните команди:
-
-- `s` - изкарвате изображението на екрана
-- `r` - завъртате изображението по часовниковата стрелка с 90 градуса
-- `l` - завъртате изображението обратно на часовниковата стрелка с 90 градуса
-- `h` - обръщате изображението по хоризонтала (първи и последен ред се разменят, след това втори и предпоследен и так. нат.)
-- `v` - обръщате изображението по вертикалата (първа и последна колона се разменят, след това втора и предпоследна и так. нат.)
-- `f` - след този знак получавате още 4 стойности - това са два координата върху изображението, и трябва да запълните с бяло правоъгълна област с горен ляв ъгъл в първата точка и с долен десен ъгъл във втората точка.
+.bulleted
+- `[s]` - изкарвате изображението на екрана
+- `[r]` - завъртате изображението по часовниковата стрелка с 90 градуса
+- `[l]` - завъртате изображението обратно на часовниковата стрелка с 90 градуса
+- `[h]` - обръщате изображението по хоризонтала (първи и последен ред се разменят, след това втори и предпоследен и так. нат.)
+- `[v]` - обръщате изображението по вертикалата (първа и последна колона се разменят, след това втора и предпоследна и так. нат.)
+- `[f]` - след този знак получавате още 4 стойности - това са два координата върху изображението, и трябва да запълните с бяло правоъгълна област с горен ляв ъгъл в първата точка и с долен десен ъгъл във втората точка.
В един координат първо посочваме реда и след това колоната, като координатите започват от 0, от горния ляв ъгъл.
-- `c` - почти същото като `f`, обаче запълвате с черно, не с бяло
+- `[c]` - почти същото като `[f]`, обаче запълвате с черно, не с бяло
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
@@ -188,28 +187,27 @@ X XXXXXXXXXXXXXXXXX X
X X
X X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-```
## Задача 6
-Ще имплементираме програма, която намира състоянието на един [елементарен едноклетъчен автомат](https://en.wikipedia.org/wiki/Elementary_cellular_automaton) след даден брой генерации и определено правило.
+Ще имплементираме програма, която намира състоянието на един [url https://en.wikipedia.org/wiki/Elementary_cellular_automaton елементарен едноклетъчен автомат] след даден брой генерации и определено правило.
Задачата изглежда сложна, но не е толкова зле.
За нашите цели, един "елементарен едноклетъчен автомат" е просто един голям булев масив.
-Ще наричаме стойност `true` жива и стойност `false` мъртва.
+Ще наричаме стойност `[true]` жива и стойност `[false]` мъртва.
За всяка клетка в масива имаме правила, в зависимост от стойностите на клетката в ляво и в дясно променяме сегашната клетка.
Направили сме една "генерация" след като обиколим всички клетки един път (от ляво на дясно) и обновим техните стойности.
-Би трябвало това да ви напомня на [играта "Живот"](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life) от [John Conway](https://en.wikipedia.org/wiki/John_Horton_Conway).
+Би трябвало това да ви напомня на [url https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life играта "Живот"] от [url https://en.wikipedia.org/wiki/John_Horton_Conway John Conway].
-Конкретните правила са тези при ["правило 30"](https://en.wikipedia.org/wiki/Rule_30).
+Конкретните правила са тези при [url https://en.wikipedia.org/wiki/Rule_30 "правило 30"].\n
Ако сегашната клетка е жива:
-
+.bulleted
- става мъртва, ако тази в ляво е жива
- остава жива иначе
Ако сегашната клетка е мъртва:
-
+.bulleted
- става жива, ако тази в ляво ИЛИ тази в дясно е жива (но не и двете едновременно)
- иначе остава мъртва
diff --git a/src/teaching/upp-2023/week8/index.md b/src/teaching/upp-2023/week8/index.du
index 561dc71..fd1ebf8 100644
--- a/src/teaching/upp-2023/week8/index.md
+++ b/src/teaching/upp-2023/week8/index.du
@@ -1,8 +1,10 @@
# Задачи - УПП, Седмица 8, 24.11.2023
-GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com/a/Big7FRUG)
+\n
-&:warn **Трябва** да използвате възможно най-малко памет във всички задачи!
+GitHub classroom: [url https://classroom.github.com/a/Big7FRUG classroom.github.com/a/Big7FRUG]
+
+.warn =[Трябва]= да използвате възможно най-малко памет във всички задачи!
## Задача 1
@@ -13,11 +15,11 @@ GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com
Броим позициите на числата от 1, тоест в "8 5 9 7", 8 е на позиция 1, 5 е на позиция 2, 9 е на позиция 3 и 7 е на позиция 4.
"Всяко второ число" са числата 5 и 7, докато "всяко трето" е само числото 9.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|8<br>19 6 2 100 96 54 56 39|6 100 54 39<br>2 54|
+.table
+|=Вход=||=Изход=|
+|:8\n19 6 2 100 96 54 56 39:||:6 100 54 39\n2 54:|
## Задача 2
@@ -30,25 +32,25 @@ GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com
След ротацията трябва да изкарате числата на екрана.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|9 1 3 5 0 1|5 9 1 3|
-|1 2 2 2 1 0 -3|2 1 1 2 2|
-|983 473 103 1 4 0 0|983 473 103 1 4|
+.table
+|=Вход=||=Изход=|
+|:9 1 3 5 0 1:||:5 9 1 3:|
+|:1 2 2 2 1 0 -3:||:2 1 1 2 2:|
+|:983 473 103 1 4 0 0:||:983 473 103 1 4:|
## Задача 3
Получавате цяло положително число N и след това получавате всички коефициенти в матрица NxN.
Трябва да изкарате редицата числа, получена чрез умножаване на първия ред по всяка колона от същата матрица.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|3<br>78 97 21<br>67 9 37<br>67 11 89|13990 8670 7096|
-|4<br>46 34 26 61<br>30 58 81 27<br>50 69 26 83<br>100 2 25 63|10536 5452 6151 9725|
+.table
+|=Вход=||=Изход=|
+|:3\n78 97 21\n67 9 37\n67 11 89:||:13990 8670 7096:|
+|:4\n46 34 26 61\n30 58 81 27\n50 69 26 83\n100 2 25 63:||:10536 5452 6151 9725:|
## Задача 4
@@ -60,38 +62,38 @@ GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com
Накрая трябва да изкарате получената редица стойности.
При изкарване трябва да пропуснете незапълнени клетки.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|82 25 23 32 72 19 0|82 23 25 32 72 19|
-|82 25 23 32 72 19 61 0|82 23 25 32 72 61 19|
-|96 96 56 90 33 43 15 73 17 0|96 56 96 90 33 15 43 73 17|
+.table
+|=Вход=||=Изход=|
+|:82 25 23 32 72 19 0:||:82 23 25 32 72 19:|
+|:82 25 23 32 72 19 61 0:||:82 23 25 32 72 61 19:|
+|:96 96 56 90 33 43 15 73 17 0:||:96 56 96 90 33 15 43 73 17:|
## Задача 5
Получавате цели числа от входа, докато не получите числото 0.
Представете си една права "по средата" на масива, вмъквате първото число в ляво от правата, второто в дясно, после пак в ляво и четвъртото в дясно и так. нат.
-Пример: ако са въведени числата "1 2 3 4", и си представяме правата `|`, при първото число правим `1|`, при второто `1|2`, при третото `1 3|2` и при четвъртото `1 3|4 2`, тоест финалната редица е "1 3 4 2".
+Пример: ако са въведени числата "1 2 3 4", и си представяме правата `[|]`, при първото число правим `[1|]`, при второто `[1|2]`, при третото `[1 3|2]` и при четвъртото `[1 3|4 2]`, тоест финалната редица е "1 3 4 2".
Друг начин по който да го разберем, е че първото число е на първа позиция, второто число е на последната, третото число е на втора позиция, четвъртото е на предпоследна и так. нат.
Обаче ние не знаем финалния размер на масива, затова се нуждаем от логиката с чертата.
-&:important Моля не правете решенето със запазване на входа и разместване на елементите
+.important Моля не правете решенето със запазване на входа и разместване на елементите
Напомням, че тази права само си я представяте.
В началото масива е с размер 2.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|90 13 85 42 92 0|90 85 92 42 13|
-|85 43 26 38 45 41 48 18 11 78 56 0|85 26 45 48 11 56 78 18 41 38 43|
+.table
+|=Вход=||=Изход=|
+|:90 13 85 42 92 0:||:90 85 92 42 13:|
+|:85 43 26 38 45 41 48 18 11 78 56 0:||:85 26 45 48 11 56 78 18 41 38 43:|
## Задача 6
-Трябва да направите интерпретатор за програмния език [brainfuck](https://en.wikipedia.org/wiki/Brainfuck).
+Трябва да направите интерпретатор за програмния език [url https://en.wikipedia.org/wiki/Brainfuck brainfuck].
В него имате 8 команди/инструкции, всяка от които се изразява с един знак.
Запазвате в паметта няколко неща: вашата brainfuck програма, паметта на "машината", къде се намирате в програмата и къде се намирате в паметта на "машината".
@@ -100,24 +102,24 @@ GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com
За предпочитане е, типа данни в паметта на "машината" да запазва само един байт информация.
Самите команди (знаци), които съставят една brainfuck програма са:
+.bulleted
+- `[>]`: сегашната клетка (къде се намирате в паметта на "машината") става тази в дясно
+- `[<]`: сегашната клетка става тази в ляво
+- `[+]`: инкрементира стойността в сегашната клетка с едно
+- `[-]`: декрементира стойността в сегашната клетка с едно
+- `[.]`: изкарва стойността в сегашната клетка (като число)
+- `[,]`: приема от входа едно число и го записва в сегашната клетка
+- `[[]`: ако стойността в сегашната клетка е 0, тогава програмата "скача" напред към знака след съответната `[]]`
+- `[]]`: ако стойността в сегашната клетка не е 0, тогава програмата "скача" назад към знака след съответната `[[]`
-- `>`: сегашната клетка (къде се намирате в паметта на "машината") става тази в дясно
-- `<`: сегашната клетка става тази в ляво
-- `+`: инкрементира стойността в сегашната клетка с едно
-- `-`: декрементира стойността в сегашната клетка с едно
-- `.`: изкарва стойността в сегашната клетка (като число)
-- `,`: приема от входа едно число и го записва в сегашната клетка
-- `[`: ако стойността в сегашната клетка е 0, тогава програмата "скача" напред към знака след съответната `]`
-- `]`: ако стойността в сегашната клетка не е 0, тогава програмата "скача" назад към знака след съответната `[`
-
-От входа ще получавате редица знаци, които ще съставят вашата brainfuck програма, като при знака `$` входът спира и трябва да започнете изпълнение на brainfuck кода.
+От входа ще получавате редица знаци, които ще съставят вашата brainfuck програма, като при знака `[$]` входът спира и трябва да започнете изпълнение на brainfuck кода.
Не знаете колко памет на "машината" ще ви трябва, затова бъдете готови да я разширявате при нужда.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|+ + > + + + + + [ < + > - ] < . $|7|
+.table
+|=Вход=||=Изход=|
+|:+ + > + + + + + [ < + > - < . $:||:7:|
## Задача 7
@@ -130,6 +132,7 @@ GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com
Играчът започва с 10 точки живот и с меч, който взема 2 точки живот, когато използван.
На всеки ход играчът има няколко възможни действия:
+:unordered
- да отиде в следващата или предходната стая
- ако има коридор, да отиде в другия край на коридора
@@ -146,13 +149,14 @@ GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com
Няма как да знаете колко точки живот отнема една атака на чудовището, преди да ви е ударило.
Ако изберете да отидете в друга стая, никой няма да атакува никой.
- На всеки ход, всяко живо чудовище избира на случаен принцип дали да остане в своята стая, дали да отиде в лявата или в дясната (шансът за всяка опция е еднакъв).
+ .p На всеки ход, всяко живо чудовище избира на случаен принцип дали да остане в своята стая, дали да отиде в лявата или в дясната (шансът за всяка опция е еднакъв).\n
След като убиете едно чудовище, имате 25% шанс да получите телепортер, с него може да излезете от коридорния dungeon и да свършите играта.
- Ако чудовище влезе в стая със съкровище, то го плячкосва и се губи.
+ .p Ако чудовище влезе в стая със съкровище, то го плячкосва и се губи.
- ако притежавате телепортер, може да спрете играта
+
Има 20% шанс една стая да има съкровище, 20% шанс да има чудовище, 10% шанс да има коридор и 50% шанс да бъде празна.
При "създаване" на едно чудовище, то ще има между 20 и 30 точки живот, и оръжието му ще взема между 5 и 20 точки живот.
Шанса за всяка от тези стойности е еднакъв.
@@ -164,4 +168,4 @@ GitHub classroom: [classroom.github.com/a/Big7FRUG](https://classroom.github.com
Всеки допълнителен телепортер, извън първоначалния с който спирате играта, ви носи още 50 точки.
На всеки ход трябва да изкарате броя точки живот на играча, броя точки живот които меча му отнема, сегашната стая в която се намира, левите 5 стаи и десните 5 стаи.
-Една стая е изобразена със знака `?` ако не е посетена, ` ` ако е празна, `c` ако има съкровище, `m` ако има чудовище и `t` ако има тунел.
+Една стая е изобразена със знака `[?]` ако не е посетена, `[ ]` ако е празна, `[c]` ако има съкровище, `[m]` ако има чудовище и `[t]` ако има тунел.
diff --git a/src/teaching/upp-2023/week9/index.md b/src/teaching/upp-2023/week9/index.du
index 557b89a..af2f853 100644
--- a/src/teaching/upp-2023/week9/index.md
+++ b/src/teaching/upp-2023/week9/index.du
@@ -1,19 +1,21 @@
# Задачи - УПП, Седмица 9, 01.12.2023
-GitHub classroom: [classroom.github.com/a/lGXxCRZO](https://classroom.github.com/a/lGXxCRZO)
+\n
-&:warn Освен ако не е казано друго, може да зачитате, че максималната дължина на един низ е 1024 знака.
+GitHub classroom: [url https://classroom.github.com/a/lGXxCRZO classroom.github.com/a/lGXxCRZO]
+
+.warn Освен ако не е казано друго, може да зачитате, че максималната дължина на един низ е 1024 знака.
## Задача 1
Получавате от входа два низа.
Трябва да изкарате на екрана низ, при който има знакът "\_" на индексите, където буквите между двата низа се различават, и съответната буква, когато не се различават.
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|ABCDE<br>AKDDCP|A\_\_D\_\_|
+.table
+|=Вход=||=Изход=|
+|:ABCDE\nAKDDCP:||:A\_\_D\_\_:|
## Задача 2
@@ -21,27 +23,27 @@ GitHub classroom: [classroom.github.com/a/lGXxCRZO](https://classroom.github.com
Изкарайте на екрана втората половина от низа и след това директно долепена първата половина.
Ако низа е с нечетна дължина, зачитаме средния елемент като част от втората половина.
-&:important Трябва да използвате динамична памет
+.important Трябва да използвате динамична памет
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|6<br>A CM N|M NA C|
-|7<br>ABCKLMN|KLMNABC|
+.table
+|=Вход=||=Изход=|
+|:6\nA CM N:||:M NA C:|
+|:7\nABCKLMN:||:KLMNABC:|
## Задача 3
От входа получаввате един низ, трябва да изкарате броя думи в него.
Думите се разделят с една или повече шпации, като знаци (точка, запетая, удивителна, ...) не са думи.
-**Примери:**
+=[Примери:]=
-|Вход|Изход|
-|----|-----|
-|abc|1|
-|abc def|2|
-|<pre>This , is , a , sentence .!</pre>|4|
+.table
+|=Вход=||=Изход=|
+|:abc:||:1:|
+|:abc def:||:2:|
+|:<pre>This , is , a , sentence .!</pre>:||:4:|
## Задача 4
@@ -49,22 +51,23 @@ GitHub classroom: [classroom.github.com/a/lGXxCRZO](https://classroom.github.com
Тя позволява да погледнеш стойностите в клетки от паметта, да запишеш стойности и да стартираш програми.
Игнорирайки последната му възможност, нека да го имплементираме.
-За нашите цели, паметта на компютъра е просто един масив, които ще расте **когато е нужно**.
+За нашите цели, паметта на компютъра е просто един масив, които ще расте =[когато е нужно]=.
Ще адресираме (индексираме) стойностите от масива с числа от 16-тична бройна система.
Когато въведем низ във формата:
+:unordered
- "адрес", без нищо друго на реда, изкарваме "X: V", където X е конкретния адрес (пак в 16-тична бройна система) и V е стойността на клетката в този адрес.
- "адрес.адрес", връщаме стойностите между тези адреси (включително) във формата "X: V ...", където X е начален адрес и "V ..." са стойностите на всяка клетка.
+ .p
Допълнително, ако изкарваме повече от 8 адреса, трябва да продължим на нов ред, като изкараме в същия формат.
Пример: вход: "0.А", изход:
```
0: 0 0 0 0 0 0 0 0
8: 0 0 0
- ```
- "адрес: стойност", записваме "стойност" на дадения адрес.
Стойноста също е 16-тично число.
@@ -72,40 +75,42 @@ GitHub classroom: [classroom.github.com/a/lGXxCRZO](https://classroom.github.com
- "адрес: стойност ...", като предходното, обаче може да определим стойностите на сегашната и на следващите клетки (пак изкарваме във формата "X: V ...")
-**Примери:**
-|Вход|Изход|
-|----|-----|
-|0 |0: 0 |
-|2.8 |2: 0 0 0 0 0 0 0|
-|2: FF<br>2|2: 0<br>2: FF|
-|2: FF 0 A 5<br>2.5|2: 0 0 0 0<br>2: FF 0 A 5|
-|1: FA 0 9 3 5 6 1 2 ABB 8A 99<br>1.12|1: 0 0 0 0 0 0 0 0<br>9: 0 0 0<br>1: FA 0 9 3 5 6 1 2<br>9: ABB 8A 99 0|
+=[Примери:]=
+
+.table
+|=Вход=||=Изход=|
+|:0 :||:0: 0 :|
+|:2.8 :||:2: 0 0 0 0 0 0 0:|
+|:2: FF\n2:||:2: 0\n2: FF:|
+|:2: FF 0 A 5\n2.5:||:2: 0 0 0 0\n2: FF 0 A 5:|
+|:1: FA 0 9 3 5 6 1 2 ABB 8A 99\n1.12:||:1: 0 0 0 0 0 0 0 0\n9: 0 0 0\n1: FA 0 9 3 5 6 1 2\n9: ABB 8A 99 0:|
## Задача 5
Перфокартите са стар формат за съхраняване на текст (код) върху хартиен носител, който е четим от машини.
Разделени са на някакъв брой редове и колони, всяка колона определя една буква, и всеки ред определя битовите стойности на всяка буква, като дупката означава бит 1, а липсата и бит 0.
-![](https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Blue-punch-card-front-horiz.png/1024px-Blue-punch-card-front-horiz.png)
+[image https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Blue-punch-card-front-horiz.png/1024px-Blue-punch-card-front-horiz.png
За удобство на програмиста, почти винаги най-отгоре на колоната се изписва с мастило каква е буквата на съответната колона.
Трябва да имплементирате програма, която получава перфо карти в стандартния IBM формат: 12 реда и 80 колони и изкарва съответния ред, който е закодиран.
-Тоест, от входа получавате 12 низа, всеки низ е с дължина 80, и са съставени от 0 и 1.
-Стойностите **по колони**:
+Тоест, от входа получавате 12 низа, всеки низ е с дължина 80, и са съставени от 0 и 1.\n
+Стойностите =[по колони]=:
+.bulleted
- от "100000000000" до "000000000001" (със само една 1ца) съответстват на знаците "&", "-", "0", "1", ... "9".
- от "100100000000" до "100000000001" (с две 1ци, едната която е винаги първата) съответстват на знаците от "A" до "I".
- от "010100000000" до "010000000001" (с две 1ци, едната която е винаги втората) съответстват на знаците от "J" до "R".
- от "001100000000" до "001000000001" (с две 1ци, едната която е винаги третата) съответстват на знаците "/", "S", ... "Z".
-**Пример:**
+=[Пример:]=
-|Вход|Изход|
-|----|-----|
-|100000000000111111111000000000000000000<br>010000000000000000000111111111000000000<br>001000000000000000000000000000111111111<br>000100000000100000000100000000100000000<br>000010000000010000000010000000010000000<br>000001000000001000000001000000001000000<br>000000100000000100000000100000000100000<br>000000010000000010000000010000000010000<br>000000001000000001000000001000000001000<br>000000000100000000100000000100000000100<br>000000000010000000010000000010000000010<br>000000000001000000001000000001000000001<br>|&-0123456789ABCDEFGHIJKLMNOPQR/STUVWXYZ|
+.table
+|=Вход=||=Изход=|
+|:100000000000111111111000000000000000000\n010000000000000000000111111111000000000\n001000000000000000000000000000111111111\n000100000000100000000100000000100000000\n000010000000010000000010000000010000000\n000001000000001000000001000000001000000\n000000100000000100000000100000000100000\n000000010000000010000000010000000010000\n000000001000000001000000001000000001000\n000000000100000000100000000100000000100\n000000000010000000010000000010000000010\n000000000001000000001000000001000000001\n:||:&-0123456789ABCDEFGHIJKLMNOPQR/STUVWXYZ:|
## Задача 6
@@ -113,25 +118,30 @@ GitHub classroom: [classroom.github.com/a/lGXxCRZO](https://classroom.github.com
Вие ще ги изучавате много подробно в "Езици, автомати и изчислимост", но за нашите цели ще се абстрахираме от детайлите.
Правилата за регулярни изрази са следните:
-
+.bulleted
- ако е буквата "\*", значи предходната буква може да се повтаря 0 или повече пъти
- ако е буквата "?", значи предходната буква може да се повтаря 0 или 1 пъти
- ако не е някой от горните знаци, тогава искаме сегашната буква да бъде равна на тази в израза
-1. Какво описва регулярният израз `aa*bcd`?
+:unordered
+1. Какво описва регулярният израз `[aa*bcd]`?
- Първата буква от нашия низ трябва да бъде `а`.
- След това имаме `a*`, след тази първа буква може да имаме 0 или повече `a`-та.
- Тоест втората буква може да бъде `a` или `b`, ако е `a`, третата буква може да бъде `a` или `b`, обаче ако втората буква е `b`, тогава продължаваме напред и останалите букви трябва да са `bcd`.
+ .p
+ Първата буква от нашия низ трябва да бъде `[а]`.
+ След това имаме `[a*]`, след тази първа буква може да имаме 0 или повече `[a]`-та.
+ Тоест втората буква може да бъде `[a]` или `[b]`, ако е `[a]`, третата буква може да бъде `[a]` или `[b]`, обаче ако втората буква е `[b]`, тогава продължаваме напред и останалите букви трябва да са `[bcd]`.
- Тоест, този регулярен израз приема низове, които започват с `a`, след това имат 0 или повече `a`-та и завършват на `bcd`.
+ .p
+ Тоест, този регулярен израз приема низове, които започват с `[a]`, след това имат 0 или повече `[a]`-та и завършват на `[bcd]`.
Следните низове ще бъдат приети: "abcd", "aabcd", "aaabcd", "aaaabcd" и так. нат.
-2. Какво описва регулярният израз `b*cd?`?
+2. Какво описва регулярният израз `[b*cd?]`?
- В началото имаме `b` нула или повече пъти, след това имаме `c` и накрая имаме нула или едно `d`.
+ .p
+ В началото имаме `[b]` нула или повече пъти, след това имаме `[c]` и накрая имаме нула или едно `[d]`.
Следните низове ще бъдат приети: "c", "bc", "bbc", "bbbc", ..., "cd", "bcd", "bbcd", ...
+
От входа получавате число N и след това ще получите 2N на брой редове.
Един ред ще бъде регулярен израз, следващия ще бъде низ за проверка, след това пак регулярен израз, след това пак низ за проверка и така се редуват.
@@ -139,8 +149,8 @@ GitHub classroom: [classroom.github.com/a/lGXxCRZO](https://classroom.github.com
В противен случай изкарвате "No match".
Ако регулярния израз е в грешен формат (срещнете "?" или "\*" като първи знак), трябва да изкарате "Bad regex".
-**Пример:**
-*Смесен вход/изход*
+=[Пример:]=
+*[Смесен вход/изход]*
```
9
@@ -171,4 +181,3 @@ No match
*abc
ops
Bad regex
-```
diff --git a/src/tutorials.du b/src/tutorials.du
new file mode 100644
index 0000000..ec064e2
--- /dev/null
+++ b/src/tutorials.du
@@ -0,0 +1,68 @@
+# Tutorials
+
+Educational articles with the sole goal of explaining technologies, processes or anything in between.
+
+\n
+
+#### *[2023]*
+
+:defs
+; [$gb] 16 Dec &emsp; [url /tutorials/fix-qc-timeout Fix "qc timeout" kernel log error]
+: `[Linux]` | `[kernel]` | `[libata]` `[qc]` `[logs]` `[DMA]`
+
+; [$gb] 28 Jun &emsp; [url /tutorials/fix-network-brother-printers Fix networked Brother printers not working in Linux]
+: `[Linux]` | `[CUPS]` | `[Printers]` `[Brother]` `[Network]` `[avahi]`
+
+; [$gb] 14 Jun &emsp; [url /tutorials/gns3-initsh-no-such-file Fix "exec /gns3/init.sh: no such file or directory"]
+: `[Linux]` | `[GNS3]` | `[Docker]` `[busybox]`
+
+; [$gb] 26 Apr &emsp; [url /tutorials/install-drivers-for-epson-scanners Install drivers for Epson scanners]
+: `[Linux]` | `[SANE]` | `[Scanners]` `[Epson]` `[epkowa]` `[iscan]`
+
+; [$gb] 25 Apr &emsp; [url /tutorials/managing-apps-with-adb-without-root Managing Android apps with ADB (and without root)]
+: `[Android]` | `[ADB]` | `[Apps]` `[Linux]` `[Windows]`
+
+; [$gb] 01 Jan &emsp; [url /tutorials/virt-manager-freeze-on-browse virt-manager freezing up when clicking Browse in any window]
+: `[Linux]` | `[virt-manager]` | `[QEMU/KVM]` `[libvirt]` `[Linux]` `[GTK]`
+
+
+#### *[2022]*
+
+:defs
+; [$gb] 16 Sep &emsp; [url /tutorials/how-to-encrypt-email How to encrypt email]
+: `[All]` | `[Email]` | `[PGP]` `[S/MIME]` `[Email Client]` `[Gmail]` `[Outlook]` `[Protonmail]`
+
+; [$gb] 30 Jul &emsp; [url /tutorials/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 /tutorials/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]`
+
+
+#### *[2021]*
+
+:defs
+; [$gb] 01 Nov &emsp; [url /tutorials/turn-off-notifications-windows How to turn off notifications on Windows]
+: `[Windows 10]` | `[Settings]` | `[Notifications]`
+
+; [$gb] 01 Nov &emsp; [url /tutorials/disable-sticky-keys-popup How to disable Sticky Keys prompt]
+: `[Windows]` | `[Settings]` | `[Sticky Keys]`
+
+; [$gb] 26 Oct &emsp; [url /tutorials/remove-weather-widget How to remove Windows Weather Widget]
+: `[Windows 10]` | `[Settings]` | `[Taskbar]` `[Weather Widget]`
+
+; [$gb] 04 Oct &emsp; [url /tutorials/windows-run-dialog Windows Run dialog]
+: `[Windows]` | `[Commands]` | `[Run]` `[Settings]`
+
+; [$gb] 03 Oct &emsp; [url /tutorials/export-skype How to export Skype data]
+: `[Skype]` | `[Export]` | `[Archive]` `[skype-parser]`
+
+
+#### *[2020]*
+
+:defs
+; [$gb] 24 Jul &emsp; [url /tutorials/how-to-use-jira How to use Jira]
+: `[Project Management]` | `[Jira]` | `[Agile]` `[Issue tracking]` `[Bug tracking]` `[Kanban]` `[Atlassian]`
+
+; [$gb] 21 May &emsp; [url /tutorials/connect-to-mysql-in-dotnet-ef Connect to Mysql in .NET and Entity Framework]
+: `[ASP.Net]` | `[MySQL]` | `[Entity Framework]` `[Pomelo]`
diff --git a/src/tutorials.md b/src/tutorials.md
deleted file mode 100644
index bfd957d..0000000
--- a/src/tutorials.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Tutorials
-
-Educational articles with the sole goal of explaining technologies, processes or anything in between.
-
-<br>
-
-#### *2023*
-
-&.gb 16 Dec &emsp; [Fix "qc timeout" kernel log error](/tutorials/fix-qc-timeout)
-: `Linux` | `kernel` | `libata` `qc` `logs` `DMA`
-
-
-&.gb 28 Jun &emsp; [Fix networked Brother printers not working in Linux](/tutorials/fix-network-brother-printers)
-: `Linux` | `CUPS` | `Printers` `Brother` `Network` `avahi`
-
-&.gb 14 Jun &emsp; [Fix "exec /gns3/init.sh: no such file or directory"](/tutorials/gns3-initsh-no-such-file)
-: `Linux` | `GNS3` | `Docker` `busybox`
-
-&.gb 26 Apr &emsp; [Install drivers for Epson scanners](/tutorials/install-drivers-for-epson-scanners)
-: `Linux` | `SANE` | `Scanners` `Epson` `epkowa` `iscan`
-
-&.gb 25 Apr &emsp; [Managing Android apps with ADB (and without root)](/tutorials/managing-apps-with-adb-without-root)
-: `Android` | `ADB` | `Apps` `Linux` `Windows`
-
-&.gb 01 Jan &emsp; [virt-manager freezing up when clicking Browse in any window](/tutorials/virt-manager-freeze-on-browse)
-: `Linux` | `virt-manager` | `QEMU/KVM` `libvirt` `Linux` `GTK`
-
-#### *2022*
-
-&.gb 16 Sep &emsp; [How to encrypt email](/tutorials/how-to-encrypt-email)
-: `All` | `Email` | `PGP` `S/MIME` `Email Client` `Gmail` `Outlook` `Protonmail`
-
-&.gb 30 Jul &emsp; [Fix "No frame buffer" error in <span class="no-wrap">Plan 9</span>](/tutorials/fix-no-frame-buffer-plan9)
-: `Plan 9` | `Configuration` | `QEMU/KVM` `Linux` `monitor`
-
-&.gb 30 Jul &emsp; [Install <span class="no-wrap">Plan 9</span> with virt-manager](/tutorials/install-plan9-with-virt-manager)
-: `Plan 9` | `Installation` | `Setup` `QEMU/KVM` `virt-manager` `Linux`
-
-#### *2021*
-
-&.gb 01 Nov &emsp; [How to turn off notifications on Windows](/tutorials/turn-off-notifications-windows)
-: `Windows 10` | `Settings` | `Notifications`
-
-&.gb 01 Nov &emsp; [How to disable Sticky Keys prompt](/tutorials/disable-sticky-keys-popup)
-: `Windows` | `Settings` | `Sticky Keys`
-
-&.gb 26 Oct &emsp; [How to remove Windows Weather Widget](/tutorials/remove-weather-widget)
-: `Windows 10` | `Settings` | `Taskbar` `Weather Widget`
-
-&.gb 04 Oct &emsp; [Windows Run dialog](/tutorials/windows-run-dialog)
-: `Windows` | `Commands` | `Run` `Settings`
-
-&.gb 03 Oct &emsp; [How to export Skype data](/tutorials/export-skype)
-: `Skype` | `Export` | `Archive` `skype-parser`
-
-#### *2020*
-
-&.gb 24 Jul &emsp; [How to use Jira](/tutorials/how-to-use-jira)
-: `Project Management` | `Jira` | `Agile` `Issue tracking` `Bug tracking` `Kanban` `Atlassian`
-
-&.gb 21 May &emsp; [Connect to Mysql in .NET and Entity Framework](/tutorials/connect-to-mysql-in-dotnet-ef)
-: `ASP.Net` | `MySQL` | `Entity Framework` `Pomelo`
-
diff --git a/src/tutorials/connect-to-mysql-in-dotnet-ef/index.du b/src/tutorials/connect-to-mysql-in-dotnet-ef/index.du
new file mode 100644
index 0000000..b720264
--- /dev/null
+++ b/src/tutorials/connect-to-mysql-in-dotnet-ef/index.du
@@ -0,0 +1,78 @@
+# Connect to MySql in .NET and Entity Framework
+
+'define expected-reading 3 min
+'define created 21 May 2020
+'define edited 19 June 2021
+[$pagenav]
+
+:contents
+.numbered
+1. [url #nuget-packages NuGet packages]
+2. [url #connection-string Connection string]
+3. [url #connecting Connecting]
+ .numbered
+ 1. [url #asp.net-startup ASP.NET Startup]
+ 2. [url #dbcontext-child-class 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.
+
+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/tutorials/connect-to-mysql-in-csharp-ef/article.md this].
+
+## 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.
+
+## 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:
+
+```
+"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.
+
+[image ./img/connections.png MyServer root 127.0.0.1:3306] 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].
+
+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]
+
+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#
+.UseMySql(CONNECTION_STRING, new MySqlServerVersion(new System.Version(8, 0, 21)))
+
+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.
+
+The result should look something along the lines of:
+
+```c#
+// 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(...);
+ });
+}
+
+### 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.
+
+```c#
+protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+{
+ optionsBuilder.UseMySql(...);
+}
diff --git a/src/tutorials/connect-to-mysql-in-dotnet-ef/index.md b/src/tutorials/connect-to-mysql-in-dotnet-ef/index.md
deleted file mode 100644
index c5f0e9d..0000000
--- a/src/tutorials/connect-to-mysql-in-dotnet-ef/index.md
+++ /dev/null
@@ -1,75 +0,0 @@
-# Connect to MySql in .NET and Entity Framework
-
-## Contents
-
-1. [NuGet packages](#nuget-packages)
-2. [Connection string](#connection-string)
-3. [Connecting](#connecting)
- 1. [ASP.NET Startup](#asp.net-startup)
- 2. [DBContext child class](#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.
-
-Also, [MySql.Data.EntityFrameworkCore](https://www.nuget.org/packages/MySql.Data.EntityFrameworkCore/) has been **depricated** since *October 2020*. If you need setup instructions with it, read [this](https://gitlab.com/Syndamia/syndamiadotcom/-/blob/0510e29526c6d7681587fff4c98a339e8c69e9b5/src/tutorials/connect-to-mysql-in-csharp-ef/article.md).
-
-## NuGet packages
-
-You'll need to install [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 [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.
-
-![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 [ASP.NET Startup](#asp.net-startup) or in a [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`.
-
-![](./img/about-workbench.png)
-![](./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:
-
-```csharp
-.UseMySql(CONNECTION_STRING, new MySqlServerVersion(new System.Version(8, 0, 21)))
-```
-
-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.
-
-The result should look something along the lines of:
-
-```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(...);
- });
-}
-```
-
-### 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.
-
-```csharp
-protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
-{
- optionsBuilder.UseMySql(...);
-}
-```
diff --git a/src/tutorials/disable-sticky-keys-popup/index.du b/src/tutorials/disable-sticky-keys-popup/index.du
new file mode 100644
index 0000000..4826ea7
--- /dev/null
+++ b/src/tutorials/disable-sticky-keys-popup/index.du
@@ -0,0 +1,31 @@
+# How to disable Sticky Keys prompt
+
+'define expected-reading 1 min
+'define created 01 November 2021
+'define edited 01 November 2021
+[$pagenav]
+
+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:
+
+[image ./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]=
+
+ [image ./img/windows-run-control-access.png]
+
+2. Inside the opened up window, press =[Make the keyboard easier to use]=
+
+ [image ./img/windows-make-keyboard-highlighted.png]
+
+3. After that, press =[Set up Sticky Keys]=
+
+ [image ./img/windows-sticky-keys-highlighted.png]
+
+4. Uncheck the =[Turn on Sticky Keys when SHIFT is pressed five times]=
+
+ [image ./img/windows-sticky-keys-disable.png]
+
+5. Finally, press =[OK]= and close the window
diff --git a/src/tutorials/disable-sticky-keys-popup/index.md b/src/tutorials/disable-sticky-keys-popup/index.md
deleted file mode 100644
index d9c00f4..0000000
--- a/src/tutorials/disable-sticky-keys-popup/index.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# How to disable Sticky Keys prompt
-
-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/windows-sticky-keys-prompt.png)
-
-This is how to stop the popup from showing up ever again:
-
-1. Press **Windows key + R**, type in `control access.cpl`, and then press **OK**
-
- ![](./img/windows-run-control-access.png)
-2. Inside the opened up window, press **Make the keyboard easier to use**
-
- ![](./img/windows-make-keyboard-highlighted.png)
-3. After that, press **Set up Sticky Keys**
-
- ![](./img/windows-sticky-keys-highlighted.png)
-4. Uncheck the **Turn on Sticky Keys when SHIFT is pressed five times**
-
- ![](./img/windows-sticky-keys-disable.png)
-5. Finally, press **OK** and close the window
diff --git a/src/tutorials/export-skype/index.du b/src/tutorials/export-skype/index.du
new file mode 100644
index 0000000..b9046b2
--- /dev/null
+++ b/src/tutorials/export-skype/index.du
@@ -0,0 +1,88 @@
+# How to export Skype data
+
+'define expected-reading 3 min
+'define created 03 October 2021
+'define edited 03 October 2021
+[$pagenav]
+
+: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]
+
+
+Skype has always allowed to export your chat history (and files), but it's not as straight forward as it should.
+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]
+
+ .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.
+
+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)]*.
+
+ [image ./img/initial-screen.png]
+
+3. Press =[Submit request]=.
+ After being greeted by this screen, press =[Continue]=.
+
+ [image ./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]
+
+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.
+
+ [image ./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)]*.
+
+## 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]`
+
+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]
+
+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]
+
+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]
+
+
+There is only one issue with this method - the official tool is somewhat broken.
+Images and links are shown as formatting codes, but you can't actually look at them as you would in Skype itself.
+
+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].
+
+: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]`
+
+ [image ./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.
+
+3. Continue from step 5 onward of the [url #viewing-your-export-official-tool Viewing your export - Official Tool] section
diff --git a/src/tutorials/export-skype/index.md b/src/tutorials/export-skype/index.md
deleted file mode 100644
index 1957a9c..0000000
--- a/src/tutorials/export-skype/index.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# How to export Skype data
-
-## Contents
-
-1. [Downloading files](#downloading-files)
-2. [Viewing your export - Official Tool](#viewing-your-export---official-tool)
-3. [Viewing your export - ArtemVeremienko Fork](#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. Continue reading for the required steps on doing it.
-
-## Downloading files
-
-1. Open [secure.skype.com/en/data-export](https://secure.skype.com/en/data-export)
- - 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.
-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)*.
-
- ![](./img/initial-screen.png)
-3. Press **Submit request**. After being greeted by this screen, press **Continue**.
-
- ![](./img/export-prepared.png)
-
- - You should now see an **Available exports** section near the top of the page. The status will be **Pending**.
-
- ![](./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.
-
- ![](./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 [WinRAR](https://www.rarlab.com/download.htm) or [7-Zip](https://www.7-zip.org/) *(I personally recommend 7-Zip, it is completely free (no need to worry about your [infinite trial](https://youtu.be/fTgZRVVr3_Y)) and works faster)*.
-
-## Viewing your export - Official Tool
-
-1. Extract your archive
-2. Open the [Skype Parser Download](https://go.skype.com/skype-parser), which will prompt you to save `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:
-
- ![](./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.
-
- ![](./img/choose-file.png)
-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)
-
- ![](./img/archived-conversations-skype-default.png)
-
-There is only one issue with this method - the official tool is somewhat broken. Images and links are shown as formatting codes, but you can't actually look at them as you would in Skype itself.
-
-The fix is using an alternative to the official tool.
-
-## Viewing your export - ArtemVeremienko Fork
-
-[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 [github.com/ArtemVeremienko/skype-parser](https://github.com/ArtemVeremienko/skype-parser).
-
-1. Go to the [latest release of his skype-parser](https://github.com/ArtemVeremienko/skype-parser/releases/latest) and download `skype-parser.zip`
-
- ![](./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.
-3. Continue from step 5 onward of the [Viewing your export - Official Tool](#viewing-your-export---official-tool) section
diff --git a/src/tutorials/fix-network-brother-printers/index.md b/src/tutorials/fix-network-brother-printers/index.du
index 3265377..c6ac699 100644
--- a/src/tutorials/fix-network-brother-printers/index.md
+++ b/src/tutorials/fix-network-brother-printers/index.du
@@ -1,55 +1,58 @@
# Fix networked Brother printers not working in Linux
+'define expected-reading 4 min
+'define created 28 June 2023
+'define edited 28 June 2023
+[$pagenav]
+
Before we start, make sure you have CUPS and avahi installed and running.
## Make sure CUPS recognises it
-Go to [localhost:631/printers](https://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 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.
-Otherwise [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 =[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 *[like]*:
```
= enp0s25 IPv4 Brother HL-L2350DW series _pdl-datastream._tcp local
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
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 =[may]= or =[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.
-Make sure the printer is properly connected to the network.
+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.
+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 [www.openprinting.org/printers](https://www.openprinting.org/printers) and enter your model.
+Go to [url https://www.openprinting.org/printers 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 [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 **is** supported, then:
+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:
### Check if there are drivers available
@@ -57,10 +60,9 @@ 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 [www.openprinting.org](https://www.openprinting.org/printers) 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 https://www.openprinting.org/printers www.openprinting.org] page.
## Try to print a test page
@@ -71,13 +73,13 @@ 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:
```
hosts: files dns mdns_minimal
-```
After saving your changes, your printer should pretty quickly start printing the test page, no need to restart anything.
-- 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.
+.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.
diff --git a/src/tutorials/fix-no-frame-buffer-plan9/index.du b/src/tutorials/fix-no-frame-buffer-plan9/index.du
new file mode 100644
index 0000000..4e9c877
--- /dev/null
+++ b/src/tutorials/fix-no-frame-buffer-plan9/index.du
@@ -0,0 +1,90 @@
+# Fix "No frame buffer" error in Plan 9
+
+'define expected-reading 3 min
+'define created 30 July 2022
+'define edited 30 July 2022
+[$pagenav]
+
+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:
+
+```
+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]
+
+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
+
+ ```
+aux/vga -m vesa -l
+
+ You should get a cursor and a cleared prompt.
+
+ [image ./img/manual-prompt.png]
+
+2. In this "new" shell prompt, enter
+
+ ```
+rio
+
+ You should now get a grey background with the cursor in it.
+
+ [image ./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.
+
+3. Create a new window (refer to the bullet point for instructions). Enter
+
+ ```
+9fat:
+
+ and afterwards
+
+ ```
+sam /n/9fat/plan9.ini
+
+ this is the configuration file we will be changing.
+
+ [image ./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.
+
+4. Now we will be editing the config file with sam, a line editor. Click the green-backgrounded box, the cursor should appear.
+ First select our file:
+
+ ```
+b /n/9fat/plan9.ini
+
+ and click the green-backgrounded box.
+ 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]`.
+
+ :unordered
+ - If you want to check whether the file was properly saved, feel free to run
+
+ ```
+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]
+
+ - 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.
+
+
+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.
+
+
+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]
diff --git a/src/tutorials/fix-no-frame-buffer-plan9/index.md b/src/tutorials/fix-no-frame-buffer-plan9/index.md
deleted file mode 100644
index 57a2a21..0000000
--- a/src/tutorials/fix-no-frame-buffer-plan9/index.md
+++ /dev/null
@@ -1,87 +0,0 @@
-# Fix "No frame buffer" error in Plan 9
-
-Let's say you installed [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
-```
-
-![](./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`:
-
-1. In the shell prompt enter
-
- ```
- aux/vga -m vesa -l
- ```
-
- You should get a cursor and a cleared prompt.
-
- ![](./img/manual-prompt.png)
-
-2. In this "new" shell prompt, enter
-
- ```
- rio
- ```
-
- You should now get a grey background with the cursor in it.
-
- ![](./img/manual-rio.png)
-
- - 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.
-
-3. Create a new window (refer to the bullet point for instructions). Enter
-
- ```
- 9fat:
- ```
-
- and afterwards
-
- ```
- sam /n/9fat/plan9.ini
- ```
-
- this is the configuration file we will be changing.
-
- ![](./img/rio-9fat-commands.png)
-
- - 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.
-
-4. Now we will be editing the config file with sam, a line editor. Click the green-backgrounded box, the cursor should appear.
- First select our file:
-
- ```
- b /n/9fat/plan9.ini
- ```
-
- and click the green-backgrounded box.
- 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`.
-
- - If you want to check whether the file was properly saved, feel free to run
-
- ```
- 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).
-
- ![](./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 [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 [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!
-
-![](./img/rio-default-login.png)
diff --git a/src/tutorials/fix-qc-timeout/index.md b/src/tutorials/fix-qc-timeout/index.du
index 9b02a48..d36383d 100644
--- a/src/tutorials/fix-qc-timeout/index.md
+++ b/src/tutorials/fix-qc-timeout/index.du
@@ -1,7 +1,12 @@
# Fix "qc timeout" kernel log error
+'define expected-reading 4 min
+'define created 16 December 2023
+'define edited 16 December 2023
+[$pagenav]
+
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)
@@ -9,38 +14,35 @@ kernel: ata1.00: Read log 0x00 page 0x00 failed, Emask 0x40
kernel: ata1.00: NCQ Send/Recv Log not supported
kernel: ata1.00: Read log 0x00 page 0x00 failed, Emask 0x40
kernel: ata1.00: ATA Identify Device Log not supported
-```
## Solution
-Add a kernel parameter which tells Linux that the drive doesn't support DMA logs.
+Add a kernel parameter which tells Linux that the drive doesn't support DMA logs.\n
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:
```
libata.force=3.01:nodmalog
-```
## Explanation
-&:important The following is how I understand the issue, but I did not find definitive proof thats exactly what happens.
- Take this section with a grain of salt.
+.important
+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 [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.
+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.
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).
@@ -54,7 +56,7 @@ The simplest definition would be for the drive to return an error singal, but in
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.
-That's what the error is saying: `qc` is short for ["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).
+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).
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/tutorials/gns3-initsh-no-such-file/index.du b/src/tutorials/gns3-initsh-no-such-file/index.du
new file mode 100644
index 0000000..2b6f908
--- /dev/null
+++ b/src/tutorials/gns3-initsh-no-such-file/index.du
@@ -0,0 +1,27 @@
+# Fix "exec /gns3/init.sh: no such file or directory"
+
+'define expected-reading 1 min
+'define created 14 June 2023
+'define edited 14 June 2023
+[$pagenav]
+
+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:
+
+:ordered
+0. Get into a temporary folder
+
+ ```bash
+cd /tmp
+
+1. Get and extract the Debian binary
+
+ ```bash
+wget -q http://launchpadlibrarian.net/471755664/busybox-static_1.30.1-4ubuntu6_amd64.deb
+ar x busybox-static_1.30.1-4ubuntu6_amd64.deb
+tar -xf data.tar.xz
+
+2. Move it to the proper location, your path may differ slightly
+
+ ```bash
+sudo mv ./bin/busybox /usr/lib/python3.11/site-packages/gns3server/compute/docker/resources/bin/busybox
diff --git a/src/tutorials/gns3-initsh-no-such-file/index.md b/src/tutorials/gns3-initsh-no-such-file/index.md
deleted file mode 100644
index a56c587..0000000
--- a/src/tutorials/gns3-initsh-no-such-file/index.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Fix "exec /gns3/init.sh: no such file or directory"
-
-This problem can easily occur on new installations and can be hard to figure out.
-In a [GitHub issue](https://github.com/GNS3/gns3-server/issues/2069#issuecomment-1296741195), the solution that fixed it for me was using Debian's busybox:
-
-0. Get into a temporary folder
-
- ```bash
- cd /tmp
- ```
-
-1. Get and extract the Debian binary
-
- ```bash
- wget -q http://launchpadlibrarian.net/471755664/busybox-static_1.30.1-4ubuntu6_amd64.deb
- ar x busybox-static_1.30.1-4ubuntu6_amd64.deb
- tar -xf data.tar.xz
- ```
-
-2. Move it to the proper location, your path may differ slightly
-
- ```bash
- sudo mv ./bin/busybox /usr/lib/python3.11/site-packages/gns3server/compute/docker/resources/bin/busybox
- ```
diff --git a/src/tutorials/how-to-encrypt-email/index.du b/src/tutorials/how-to-encrypt-email/index.du
new file mode 100644
index 0000000..403bde9
--- /dev/null
+++ b/src/tutorials/how-to-encrypt-email/index.du
@@ -0,0 +1,263 @@
+# How to encrypt email
+
+'define expected-reading 5 min
+'define created 16 September 2022
+'define edited 16 November 2022
+[$pagenav]
+
+:contents
+:numbered
+1. [url #getting-keys Getting keys]
+ :numbered
+ 1. [url #pgp PGP]
+ .numbered
+ 1. [url #pgptool.org pgptool.org]
+ 2. [url #gnu-privacy-guard GNU Privacy Guard]
+
+ 2. [url #smime S/MIME]
+
+
+2. [url #exchanging-keys Exchanging keys]
+3. [url #configuring-clients 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.
+
+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
+
+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.
+
+#### 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.
+
+#### 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].
+
+The *[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]`
+
+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
+
+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.
+
+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]`.
+
+
+On *[Linux]* and *[MacOS]*, you can use the command line:
+
+:ordered
+1. Enter this command in your favorite terminal
+
+ ```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])
+
+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)
+
+ ```bash
+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.
+
+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).
+
+## 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!
+
+## Configuring clients
+
+Now we need to configure your email application to automatically encrypt and decrypt messages. There are a lot of email clients, so I have compiled the most used ones and linked resources on how to set them up.
+
+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.]*
+
+:table
+|= Client =||= Type =||= Platform =||= PGP/Inline =||= PGP/MIME =||= S/MIME =|
+
+|= Web =||::||::||::||::||::|
+
+|:Gmail:|
+ |:Freemium:|
+ |:Web:|
+ |:[url https://flowcrypt.com/ Yes]^[[url #1 1]]^:|
+ |:[url https://flowcrypt.com/ Yes]^[[url #1 1]]^:|
+ |:[url https://support.google.com/a/answer/6374496?hl=en&ref_topic=9061730 Yes]^[[url #2 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]^[[url #2 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]:|
+
+|:Yahoo!:|
+ |:Freemium:|
+ |:Web:|
+ |:No:|
+ |:No:|
+ |:No:|
+
+|:Protonmail:|
+ |:Freemium:|
+ |:Web:|
+ |:[url https://proton.me/support/how-to-use-pgp Yes]:|
+ |:[url https://proton.me/support/how-to-use-pgp Yes]:|
+ |:No:|
+
+|:Roundcube:|
+ |:Self-hosted:|
+ |:Web:|
+ |:[url https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma Yes]^[[url #1 1]]^:|
+ |:[url https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma Yes]^[[url #1 1]]^:|
+ |:[url https://github.com/roundcube/roundcubemail/issues/4977 No]:|
+
+|:Rainloop:|
+ |:Self-hosted:|
+ |:Web:|
+ |:Yes:|
+ |:[url https://github.com/RainLoop/rainloop-webmail/issues/1798 No]:|
+ |:No:|
+
+|= Desktop =||::||::||::||::||::|
+
+|: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]:|
+
+|: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]:|
+
+|: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]:|
+
+|: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]:|
+
+|: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]:|
+
+|:Claws-mail:|
+ |:FOSS:|
+ |:Windows, Linux:|
+ |:[url https://claws-mail.org/plugin.:php?plugin=gpg Yes]^[[url #1 1]]^:|
+ |:[url https://claws-mail.org/plugin.php?plugin=gpg Yes]^[[url #1 1]]^:|
+ |:[url https://claws-mail.org/plugins.php Yes]^[[url #1 1]]^:|
+
+|= Mobile =||::||::||::||::||::|
+
+|:Gmail:|
+ |:Free:|
+ |:Android, iOS:|
+ |:No:|
+ |:No:|
+ |:Yes^[[url #3: 3]]^:|
+
+|:Outlook:|
+ |:Free:|
+ |:Android, iOS:|
+ |:No:|
+ |:No:|
+ |:Yes^[[url #3: 3]]^:|
+
+|:Apple Mail :|
+ |:Free:|
+ |:iOS:|
+ |:Yes:|
+ |:Yes:|
+ |:Yes:|
+
+|:Yahoo!:|
+ |:Free:|
+ |:Android, iOS:|
+ |:No:|
+ |:No:|
+ |:No:|
+
+|:Edison:|
+ |:Free:|
+ |:Android, iOS:|
+ |:No:|
+ |:No:|
+ |:No:|
+
+|:Protonmail:|
+ |:Free:|
+ |:Android, iOS:|
+ |:[url https://proton.me/support/how-to-use-pgp Yes]:|
+ |:[url https://proton.me/support/how-to-use-pgp Yes]:|
+ |: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]:|
+
+|: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 #* *]]^:|
+
+
+<sup id="1">1</sup> Available with an extension/plugin\n
+<sup id="2">2</sup> Available in a paid version of the software (assuming the software is Freemium; this is true for all Premium software)\n
+<sup id="3">3</sup> Available with a Premium account (even if the software is Free)\n
+<sup id="*">*</sup> You can read S/MIME messages, but signing and encrypting is a pro feature
diff --git a/src/tutorials/how-to-encrypt-email/index.md b/src/tutorials/how-to-encrypt-email/index.md
deleted file mode 100644
index 9d95b45..0000000
--- a/src/tutorials/how-to-encrypt-email/index.md
+++ /dev/null
@@ -1,109 +0,0 @@
-# How to encrypt email
-
-## Contents
-
-1. [Getting keys](#getting-keys)
- 1. [PGP](#pgp)
- 1. [pgptool.org](#pgptool.org)
- 2. [GNU Privacy Guard](#gnu-privacy-guard)
- 2. [S/MIME](#smime)
-2. [Exchanging keys](#exchanging-keys)
-3. [Configuring clients](#configuring-clients)
-
-In [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 [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 [discussed](/blog/encrypted-email/#pgp), PGP relies on a [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 [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 [GNU Privacy Guard](https://www.gnupg.org/) (GPG for short). It is [available](https://gnupg.org/download/#binary) on most desktop operating systems, including [Windows](https://gpg4win.org/download.html) and [MacOS](https://gpgtools.org/).
-
-The *Windows* version comes with a graphical user interface, so it's easiest to use that:
-
-1. Open the application "Kleopatra"
-2. Click on `File` -> `New Certificate`
-3. Input your details and press `OK`
- - 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`
-5. You'll be asked for a password. Make one up, and enter it, but do not forget it!
- - 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.
-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`.
-
-On *Linux* and *MacOS*, you can use the command line:
-
-1. Enter this command in your favorite terminal
-
- ```bash
- gpg --full-generate-key
- ```
-2. Follow the prompt on the screen (sample pictures available in [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)
-
- ```bash
- 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 [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 [Actalis](https://www.actalis.com/s-mime-certificates.aspx). Their process is pretty straight forward, just follow the instructions (shown in [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!
-
-## Configuring clients
-
-Now we need to configure your email application to automatically encrypt and decrypt messages. There are a lot of email clients, so I have compiled the most used ones and linked resources on how to set them up.
-
-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.*
-
-|Client |Type |Platform |PGP/Inline |PGP/MIME |S/MIME |
-|-----------|-----------|---------------------|-----------|-----------|-----------|
-|**Web** | | | | | |
-|Gmail |Freemium |Web |[Yes](https://flowcrypt.com/)^[1](#1)|[Yes](https://flowcrypt.com/)^[1](#1)|[Yes](https://support.google.com/a/answer/6374496?hl=en&ref_topic=9061730)^[2](#2)|
-|Outlook |Freemium |Web |No |No |[Yes](https://support.microsoft.com/en-us/office/encrypt-email-messages-373339cb-bf1a-4509-b296-802a39d801dc#bkmk_encryptwithsmime)^[2](#2)|
-|iCloud mail|Freemium |Web |[Yes](https://support.apple.com/en-us/HT201214)|[Yes](https://support.apple.com/en-us/HT201214)|[Yes](https://support.apple.com/en-us/HT202345)|
-|Yahoo! |Freemium |Web |No |No |No |
-|Protonmail |Freemium |Web |[Yes](https://proton.me/support/how-to-use-pgp)|[Yes](https://proton.me/support/how-to-use-pgp)|No|
-|Roundcube |Self-hosted|Web |[Yes](https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma)^[1](#1)|[Yes](https://github.com/roundcube/roundcubemail/tree/master/plugins/enigma)^[1](#1)|[No](https://github.com/roundcube/roundcubemail/issues/4977)|
-|Rainloop |Self-hosted|Web |Yes |[No](https://github.com/RainLoop/rainloop-webmail/issues/1798)|No|
-|**Desktop**|
-|Thunderbird|FOSS |Windows, MacOS, Linux|[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)|[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)|[Yes](https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq)|
-|Outlook |Premium |Windows, MacOS |No |No |[Yes](https://support.microsoft.com/en-us/office/encrypt-email-messages-373339cb-bf1a-4509-b296-802a39d801dc#bkmk_encryptwithsmime) |
-|Mailbird |Premium |Windows |[No](https://mailbird.featureupvote.com/suggestions/74494/pgp-encryption-support)|[No](https://mailbird.featureupvote.com/suggestions/74494/pgp-encryption-support)|[No](https://mailbird.featureupvote.com/suggestions/160861/smime-support)
-|Evolution |FOSS |Linux |[Yes](https://help.gnome.org/users/evolution/stable/mail-encryption-gpg-set-up.html.en) |[Yes](https://help.gnome.org/users/evolution/stable/mail-encryption-gpg-set-up.html.en) |[Yes](https://help.gnome.org/users/evolution/stable/mail-encryption-s-mime-manage.html.en) |
-|Sylpheed |FOSS |Windows, MacOS, Linux|[Yes](https://sylpheed.sraoss.jp/doc/manual/en/sylpheed-8.html#ss8.2) |[Yes](https://sylpheed.sraoss.jp/doc/manual/en/sylpheed-8.html#ss8.2) |[No](https://www.sraoss.jp/pipermail/sylpheed/2011-May/004551.html)|
-|Claws-mail |FOSS |Windows, Linux |[Yes](https://claws-mail.org/plugin.php?plugin=gpg)^[1](#1)|[Yes](https://claws-mail.org/plugin.php?plugin=gpg)^[1](#1)|[Yes](https://claws-mail.org/plugins.php)^[1](#1)|
-|**Mobile** |
-|Gmail |Free |Android, iOS |No |No |Yes^[3](#3)|
-|Outlook |Free |Android, iOS |No |No |Yes^[3](#3)|
-|Apple Mail |Free |iOS |Yes |Yes |Yes |
-|Yahoo! |Free |Android, iOS |No |No |No |
-|Edison |Free |Android, iOS |No |No |No |
-|Protonmail |Free |Android, iOS |[Yes](https://proton.me/support/how-to-use-pgp)|[Yes](https://proton.me/support/how-to-use-pgp)|No|
-|K-9 Mail |FOSS |Android |[Yes](https://docs.k9mail.app/en/current/security/pgp/)|[Yes](https://docs.k9mail.app/en/current/security/pgp/)|[No](https://docs.k9mail.app/en/current/security/overview/#end-to-end-encryption)|
-|FairEmail |FreemiumOSS|Android |[Yes](https://github.com/M66B/FairEmail/blob/master/FAQ.md)|[Yes](https://github.com/M66B/FairEmail/blob/master/FAQ.md)|[Yes](https://github.com/M66B/FairEmail/blob/master/FAQ.md)^[\*](#*)
-
-<sup id="1">1</sup> Available with an extension/plugin
-<sup id="2">2</sup> Available in a paid version of the software (assuming the software is Freemium; this is true for all Premium software)
-<sup id="3">3</sup> Available with a Premium account (even if the software is Free)
-<sup id="*">\*</sup> You can read S/MIME messages, but signing and encrypting is a pro feature
diff --git a/src/tutorials/how-to-use-jira/bug.du b/src/tutorials/how-to-use-jira/bug.du
new file mode 100644
index 0000000..fcd51e3
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/bug.du
@@ -0,0 +1,21 @@
+# Bug tracking template - How to use Jira
+
+'define expected-reading 1 min
+'define created 24 July 2020
+'define edited 16 September 2020
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./scrum.html Scrum template
+'define next_link ./releases.html Releases
+[$pagination_middle]
+
+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]=.
+
+=[There are no boards, no cards, no backlog]=. All issues are accessed from the `[Issues]` page from the sidebar.
+
+[image ./img/issues-sidebar.png]
+
+That's why this template is =[available only when creating a project]=.
+
+Of course, =[you can add boards at any time]=, but this project template doesn't add any by itself.
diff --git a/src/tutorials/how-to-use-jira/bug.md b/src/tutorials/how-to-use-jira/bug.md
deleted file mode 100644
index fefd8e8..0000000
--- a/src/tutorials/how-to-use-jira/bug.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Bug tracking template - How to use Jira
-
-[`<<`](./) || [`< Scrum template`](./scrum.html) || [`Releases >`](./releases.html)
-
-<br>
-
-The Bug Tracking template is completely different from the [Scrum](./scrum.html) and [Kanban](./kanban.html) templates, because it **offers only issue tracking**.
-
-**There are no boards, no cards, no backlog**. All issues are accessed from the `Issues` page from the sidebar.
-
-![](./img/issues-sidebar.png)
-
-That's why this template is **available only when creating a project**.
-
-Of course, **you can add boards at any time**, but this project template doesn't add any by itself.
-
diff --git a/src/tutorials/how-to-use-jira/cards.du b/src/tutorials/how-to-use-jira/cards.du
new file mode 100644
index 0000000..03d0ed4
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/cards.du
@@ -0,0 +1,161 @@
+# Cards - How to use Jira
+
+'define expected-reading 4 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./filters.html Filters
+'define next_link ./projects.html Projects
+[$pagination_middle]
+
+.contents
+.numbered
+1. [url #properties Properties]
+2. [url #creating Creating]
+3. [url #viewing Viewing]
+4. [url #how-to-use 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]
+
+=[Each issue is represented as an object with properties]=. More specifically, these objects are called 'cards'.
+
+[image ./img/kanban-cards.png]
+
+## Properties
+
+Each card has the following properties:
+
+[image ./img/fields-cards.png]
+
+:unordered
+- =[Project]= - the [url ./projects.html project] this card is stored in
+
+ [image ./img/project-create-card.png]
+
+- =[Issue type]= - the basic purpose of an issue (Improvement, Bug, ...)
+
+ [image ./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"
+
+ - [image ./img/bug-type.png Bug] - a problem/error
+
+ - [image ./img/epic-type.png Epic] - a collection of issues, issues are linked through 'Epic link' (see below)
+
+ - [image ./img/task-type.png Task] - 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.
+
+
+- =[Summary]= - a (required) brief explanation of the issue
+
+ [image ./img/summary-create-card.png]
+
+- =[Description]= - detailed explanation of the issue
+
+ [image ./img/description-create-card.png]
+
+- =[Reporter]= - person who created the issue
+
+ [image ./img/reporter-create-card.png]
+
+- =[Assignee]= - person who will work on the issue
+
+ [image ./img/assignee-create-card.png]
+
+- =[Labels]= - tags with which you can organise even more the issue
+
+ [image ./img/label-create-card.png]
+
+- =[Epic link]= - link of issue with type Epic
+
+ [image ./img/epic-link-create-card.png]
+
+
+## Creating
+
+To create a card yourself, you need to =[press the `[Create]` button on the top bar]=.
+
+[image ./img/create-header.png]
+
+## Viewing
+
+=[All]= cards (issues) can be viewed from a [url ./projects.html project]'s side menu, under 'Issues'.
+
+[image ./img/issues-sidebar.png]
+
+Of course, they can also be viewed through =[[url ./filters.html filters]]= and a =[[url ./projects.html project]'s board]=.
+
+## How to use
+
+By default, opening a card presents, at the top, it's =[key]= (think of it as an ID),
+
+[image ./img/card-key.png]
+
+it's =[summary]= below it,
+
+[image ./img/card-summary.png]
+
+options for adding =[attachments]=, =[subtasks]=, =[linking issues]= and =[adding more apps]= (think of apps like extensions),
+
+[image ./img/card-attach-subtask.png]
+
+following are the =[description]=, =[actual attachments]=, =[subtasks]=, =[linked issues]=, etc.,
+
+[image ./img/desc-att-sub-link.png]
+
+and at the bottom you have the =[activity]=, consisting of =[comments]= on the issue,
+
+[image ./img/activity-comments.png]
+
+=[history]= of things that have happened to that issue,
+
+[image ./img/activity-history.png]
+
+and =[work logs]= (a bit later we talk about them in more detail).
+
+[image ./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).
+
+[image ./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).
+
+[image ./img/card-top-right.png]
+
+=[Actions]= are things you can do to the whole card, like moving or deleting it.
+
+[image ./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]`.
+
+### 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 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]
+
+The time remaining takes a =[default]= value from the =[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.
+
+[image ./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].
+
+[image ./img/time-and-configure.png]
diff --git a/src/tutorials/how-to-use-jira/cards.md b/src/tutorials/how-to-use-jira/cards.md
deleted file mode 100644
index 77d27a9..0000000
--- a/src/tutorials/how-to-use-jira/cards.md
+++ /dev/null
@@ -1,151 +0,0 @@
-# Cards - How to use Jira
-
-[`<<`](./) || [`< Filters`](./filters.html) || [`Projects >`](./projects.html)
-
-<br>
-
-## Contents
-
-1. [Properties](#properties)
-2. [Creating](#creating)
-3. [Viewing](#viewing)
-4. [How to use](#how-to-use)
- 1. [Right side](#right-side)
- 2. [Work log](#work-log)
- 3. [Issue flagging](#issue-flagging)
- 4. [Basic issue information](#basic-issue-information)
-
-**Each issue is represented as an object with properties**. More specifically, these objects are called 'cards'.
-
-![](./img/kanban-cards.png)
-
-## Properties
-
-Each card has the following properties:
-
-![](./img/fields-cards.png)
-
-- **Project** - the [project](./projects.html) this card is stored in
-
- ![](./img/project-create-card.png)
-
-- **Issue type** - the basic purpose of an issue (Improvement, Bug, ...)
-
- ![](./img/issue-types.png)
-
- - ![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"
-
- - ![Bug](./img/bug-type.png) - a problem/error
-
- - ![Epic](./img/epic-type.png) - a collection of issues, issues are linked through 'Epic link' (see below)
-
- - ![Task](./img/task-type.png) - a small piece of work
-
- - ![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
-
- ![](./img/summary-create-card.png)
-
-- **Description** - detailed explanation of the issue
-
- ![](./img/description-create-card.png)
-
-- **Reporter** - person who created the issue
-
- ![](./img/reporter-create-card.png)
-
-- **Assignee** - person who will work on the issue
-
- ![](./img/assignee-create-card.png)
-
-- **Labels** - tags with which you can organise even more the issue
-
- ![](./img/label-create-card.png)
-
-- **Epic link** - link of issue with type Epic
-
- ![](./img/epic-link-create-card.png)
-
-## Creating
-
-To create a card yourself, you need to **press the `Create` button on the top bar**.
-
-![](./img/create-header.png)
-
-## Viewing
-
-**All** cards (issues) can be viewed from a [project](./projects.html)'s side menu, under 'Issues'.
-
-![](./img/issues-sidebar.png)
-
-Of course, they can also be viewed through **[filters](./filters.html)** and a **[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),
-
-![](./img/card-key.png)
-
-it's **summary** below it,
-
-![](./img/card-summary.png)
-
-options for adding **attachments**, **subtasks**, **linking issues** and **adding more apps** (think of apps like extensions),
-
-![](./img/card-attach-subtask.png)
-
-following are the **description**, **actual attachments**, **subtasks**, **linked issues**, etc.,
-
-![](./img/desc-att-sub-link.png)
-
-and at the bottom you have the **activity**, consisting of **comments** on the issue,
-
-![](./img/activity-comments.png)
-
-**history** of things that have happened to that issue,
-
-![](./img/activity-history.png)
-
-and **work logs** (a bit later we talk about them in more detail).
-
-![](./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).
-
-![](./img/card-right-side.png)
-
-On the top right you can change **watch options** ([watching an issue](https://www.idalko.com/jira-watch-issues/) means you get notified by all changes done to it), you can **share** the card and do **actions** (the three dots).
-
-![](./img/card-top-right.png)
-
-**Actions** are things you can do to the whole card, like moving or deleting it.
-
-![](./img/card-actions.png)
-
-The most notable options are [`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 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.
-
-![](./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.
-
-### Issue flagging
-
-A **flagged issue** is an issue that is very important. Flagged issues are displayed in yellow to signify their needed attention.
-
-![](./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 [here](https://confluence.atlassian.com/adminjiracloud/changing-a-field-configuration-844500798.html).
-
-![](./img/time-and-configure.png)
-
diff --git a/src/tutorials/how-to-use-jira/components.du b/src/tutorials/how-to-use-jira/components.du
new file mode 100644
index 0000000..c696e62
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/components.du
@@ -0,0 +1,50 @@
+# Components - How to use Jira
+
+'define expected-reading 2 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./pages.html Pages
+'define next_link ./dashboards.html Dashboards
+[$pagination_middle]
+
+.contents
+.numbered
+1. [url #creating-and-editing Creating and editing]
+2. [url #adding-issues 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.
+
+## Creating and editing
+
+Creating and editing them is done from the =[`[Components]` menu in the sidebar]=.
+
+[image ./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]`.
+
+[image ./img/create-component-empty.png]
+
+[image ./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]
+
+=[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]=.
+
+## Adding issues
+
+Adding an issue to a component can be done either =[when creating it]= or =[when viewing it]=.
+
+=[Right under the summary]=, there is a place for indicating a component, named `[Components]`.
+
+[image ./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]`).
+
+[image ./img/show-fields.png]
+
+[image ./img/components-field.png]
diff --git a/src/tutorials/how-to-use-jira/components.md b/src/tutorials/how-to-use-jira/components.md
deleted file mode 100644
index 4f22a31..0000000
--- a/src/tutorials/how-to-use-jira/components.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# Components - How to use Jira
-
-[`<<`](./) || [`< Pages`](./pages.html) || [`Dashboards >`](./dashboards.html)
-
-<br>
-
-## Contents
-
-1. [Creating and editing](#creating-and-editing)
-2. [Adding issues](#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.
-
-## Creating and editing
-
-Creating and editing them is done from the **`Components` menu in the sidebar**.
-
-![](./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`.
-
-![](./img/create-component-empty.png)
-
-![](./img/create-component-full.png)
-
-Clicking on it presents you with a screen where you input it's information.
-
-![](./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**.
-
-## Adding issues
-
-Adding an issue to a component can be done either **when creating it** or **when viewing it**.
-
-**Right under the summary**, there is a place for indicating a component, named `Components`.
-
-![](./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`).
-
-![](./img/show-fields.png)
-
-![](./img/components-field.png)
-
diff --git a/src/tutorials/how-to-use-jira/dashboards.du b/src/tutorials/how-to-use-jira/dashboards.du
new file mode 100644
index 0000000..ab46ac0
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/dashboards.du
@@ -0,0 +1,65 @@
+# Dashboards - How to use Jira
+
+'define expected-reading 2 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./components.html Components
+[$pagination_end]
+
+.contents
+.numbered
+1. [url #adding-a-dashboard Adding a dashboard]
+2. [url #adding-gadgets Adding gadgets]
+
+Dashboards are a =[place where you can view a lot of information]=.
+
+[image ./img/default-dashboard.png]
+
+Dashboards are composed of =[gadgets]=.
+
+[image ./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]=.
+
+## Adding a dashboard
+
+Dashboard can be added from the top bar, under `[Create dashboard]` in the `[Dashboards]` menu
+
+[image ./img/create-dashboard-top.png]
+
+or, if you are already in a dashboard, from `[Create dashboard]` in the three dots menu.
+
+[image ./img/create-dashboard-dots.png]
+
+## Adding gadgets
+
+=[Note]=: you cannot add gadgets to the default dashboard.
+
+You can add gadgets either =[through the `[Add gadget]` button in the top right]=
+
+[image ./img/add-gadget-top.png]
+
+or, =[if you don't have any gadets]=, =[from the `[add a new gadget]` message(s)]=.
+
+[image ./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]`]=).
+
+[image ./img/load-all.png]
+
+[image ./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.
+
+[image ./img/introduction-add.png]
+
+After it is added, you'll =[need to configure it]=, usually a gadget =[requires atleast a filter/project]=.
+
+[image ./img/bubble.png]
+
+Options for different gadgets can be found on =[their top right corner, in the three dots menu]=.
+
+[image ./img/bubble-dots.png]
diff --git a/src/tutorials/how-to-use-jira/dashboards.md b/src/tutorials/how-to-use-jira/dashboards.md
deleted file mode 100644
index 6b3185f..0000000
--- a/src/tutorials/how-to-use-jira/dashboards.md
+++ /dev/null
@@ -1,61 +0,0 @@
-# Dashboards - How to use Jira
-
-[`<<`](./) || [`< Components`](./components.html)
-
-<br>
-
-## Contents
-
-1. [Adding a dashboard](#adding-a-dashboard)
-2. [Adding gadgets](#adding-gadgets)
-
-Dashboards are a **place where you can view a lot of information**.
-
-![](./img/default-dashboard.png)
-
-Dashboards are composed of **gadgets**.
-
-![](./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**.
-
-## Adding a dashboard
-
-Dashboard can be added from the top bar, under `Create dashboard` in the `Dashboards` menu
-
-![](./img/create-dashboard-top.png)
-
-or, if you are already in a dashboard, from `Create dashboard` in the three dots menu.
-
-![](./img/create-dashboard-dots.png)
-
-## Adding gadgets
-
-**Note**: you cannot add gadgets to the default dashboard.
-
-You can add gadgets either **through the `Add gadget` button in the top right**
-
-![](./img/add-gadget-top.png)
-
-or, **if you don't have any gadets**, **from the `add a new gadget` message(s)**.
-
-![](./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`**).
-
-![](./img/load-all.png)
-
-![](./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.
-
-![](./img/introduction-add.png)
-
-After it is added, you'll **need to configure it**, usually a gadget **requires atleast a filter/project**.
-
-![](./img/bubble.png)
-
-Options for different gadgets can be found on **their top right corner, in the three dots menu**.
-
-![](./img/bubble-dots.png)
-
diff --git a/src/tutorials/how-to-use-jira/filters.du b/src/tutorials/how-to-use-jira/filters.du
new file mode 100644
index 0000000..0ec6a9d
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/filters.du
@@ -0,0 +1,44 @@
+# Filters - How to use Jira
+
+'define expected-reading 1 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define prev_link ./ Introduction
+'define next_link ./cards.html Cards
+[$pagination_second]
+
+.contents
+.numbered
+1. [url #criteria Criteria]
+2. [url #jql 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.).
+
+Making filters is done through the `[Advanced issue search]` page, from the `[Filters]` menu.
+
+[image ./img/filters-advanced-issue-search.png]
+
+## Criteria
+
+From here you can see some criteria: `[Project]`, `[Type]`, `[Status]`, `[Assignee]`.
+
+[image ./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.
+
+[image ./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.
+
+[image ./img/save-as-advanced-issue-search.png]
+[image ./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.
+
+[image ./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.
diff --git a/src/tutorials/how-to-use-jira/filters.md b/src/tutorials/how-to-use-jira/filters.md
deleted file mode 100644
index 97ec938..0000000
--- a/src/tutorials/how-to-use-jira/filters.md
+++ /dev/null
@@ -1,40 +0,0 @@
-# Filters - How to use Jira
-
-[`< Introduction`](./) || [`Cards >`](./cards.html)
-
-<br>
-
-## Contents
-
-1. [Criteria](#Criteria)
-2. [JQL](#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.).
-
-Making filters is done through the `Advanced issue search` page, from the `Filters` menu.
-
-![](./img/filters-advanced-issue-search.png)
-
-## Criteria
-
-From here you can see some criteria: `Project`, `Type`, `Status`, `Assignee`.
-
-![](./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.
-
-![](./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.
-
-![](./img/save-as-advanced-issue-search.png)
-![](./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.
-
-![](./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 [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/tutorials/how-to-use-jira/index.du b/src/tutorials/how-to-use-jira/index.du
new file mode 100644
index 0000000..a1b3b0f
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/index.du
@@ -0,0 +1,75 @@
+# Introduction - How to use Jira
+
+'define expected-reading 19 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define next_link ./filters.html Filters
+[$pagination_start]
+
+:contents
+:numbered
+1. [url ./filters.html Filters]
+ .numbered
+ 1. [url ./filters.html#criteria Criteria]
+ 2. [url ./filters.html#jql JQL]
+
+2. [url ./cards.html Cards]
+ .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]
+ .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]
+
+3. [url ./projects.html Projects]
+ :numbered
+ 1. [url ./projects.html#creating-a-project Creating a project]
+ 2. [url ./projects.html#boards Boards]
+ .numbered
+ 1. [url ./projects.html#columns Columns]
+ 2. [url ./projects.html#adding-more-boards-to-a-project Adding more boards to a project]
+
+ 3. [url ./projects.html#backlog Backlog]
+ 4. [url ./projects.html#add-item Add item]
+
+
+4. [url ./kanban.html Kanban template]
+ .numbered
+ 1. [url ./kanban.html#create-board Create board]
+ 2. [url ./kanban.html#backlog Backlog]
+
+5. [url ./scrum.html Scrum template]
+ .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]
+
+6. [url ./bug.html Bug tracking template]
+
+7. [url ./releases.html Releases]
+
+8. [url ./pages.html Pages]
+
+9. [url ./components.html Components]
+ .numbered
+ 1. [url ./components.html#creating-and-editing Creating and editing]
+ 2. [url ./components.html#adding-issues Adding issues]
+
+10. [url ./dashboards.html Dashboards]
+ .numbered
+ 1. [url ./dashboards.html#adding-a-dashboard Adding a dashboard]
+ 2. [url ./dashboards.html#adding-gadgets Adding gadgets]
+
+
+
+[url https://www.atlassian.com/software/jira 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
diff --git a/src/tutorials/how-to-use-jira/index.md b/src/tutorials/how-to-use-jira/index.md
deleted file mode 100644
index 42a3364..0000000
--- a/src/tutorials/how-to-use-jira/index.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Introduction - How to use Jira
-
-[`Filters >`](./filters.html)
-
-<br>
-
-## Contents
-
-1. [Filters](./filters.html)
- 1. [Criteria](./filters.html#criteria)
- 2. [JQL](./filters.html#jql)
-2. [Cards](./cards.html)
- 1. [Properties](./cards.html#properties)
- 2. [Creating](./cards.html#creating)
- 3. [Viewing](./cards.html#viewing)
- 4. [How to use](./cards.html#how-to-use)
- 1. [Right side](./cards.html#right-side)
- 2. [Work log](./cards.html#work-log)
- 3. [Issue flagging](./cards.html#issue-flagging)
- 4. [Basic issue information](./cards.html#basic-issue-information)
-3. [Projects](./projects.html)
- 1. [Creating a project](./projects.html#creating-a-project)
- 2. [Boards](./projects.html#boards)
- 1. [Columns](./projects.html#columns)
- 2. [Adding more boards to a project](./projects.html#adding-more-boards-to-a-project)
- 3. [Backlog](./projects.html#backlog)
- 4. [Add item](./projects.html#add-item)
-4. [Kanban template](./kanban.html)
- 1. [Create board](./kanban.html#create-board)
- 2. [Backlog](./kanban.html#backlog)
-5. [Scrum template](./scrum.html)
- 1. [Backlog](./scrum.html#backlog)
- 2. [Boards and Issues](./scrum.html#boards-and-issues)
- 3. [Create board](./scrum.html#create-board)
-6. [Bug tracking template](./bug.html)
-7. [Releases](./releases.html)
-8. [Pages](./pages.html)
-9. [Components](./components.html)
- 1. [Creating and editing](./components.html#creating-and-editing)
- 2. [Adding issues](./components.html#adding-issues)
-10. [Dashboards](./dashboards.html)
- 1. [Adding a dashboard](./dashboards.html#adding-a-dashboard)
- 2. [Adding gadgets](./dashboards.html#adding-gadgets)
-
-[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
-
diff --git a/src/tutorials/how-to-use-jira/introduction.md b/src/tutorials/how-to-use-jira/introduction.md
deleted file mode 100644
index 6ce830d..0000000
--- a/src/tutorials/how-to-use-jira/introduction.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# Introduction - How to use Jira
-
-[`Filters >`](./filters.html)
-
-<br>
-
-[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
-
-## Contents
-
-1. [Filters](./filters.html)
- 1. [Criteria](./filters.html#criteria)
- 2. [JQL](./filters.html#jql)
-2. [Cards](./cards.html)
- 1. [Properties](./cards.html#properties)
- 2. [Creating](./cards.html#creating)
- 3. [Viewing](./cards.html#viewing)
- 4. [How to use](./cards.html#how-to-use)
- 1. [Right side](./cards.html#right-side)
- 2. [Work log](./cards.html#work-log)
- 3. [Issue flagging](./cards.html#issue-flagging)
- 4. [Basic issue information](./cards.html#basic-issue-information)
-3. [Projects](./projects.html)
- 1. [Creating a project](./projects.html#creating-a-project)
- 2. [Boards](./projects.html#boards)
- 1. [Columns](./projects.html#columns)
- 2. [Adding more boards to a project](./projects.html#adding-more-boards-to-a-project)
- 3. [Backlog](./projects.html#backlog)
- 4. [Add item](./projects.html#add-item)
-4. [Kanban template](./kanban.html)
- 1. [Create board](./kanban.html#create-board)
- 2. [Backlog](./kanban.html#backlog)
-5. [Scrum template](./scrum.html)
- 1. [Backlog](./scrum.html#backlog)
- 2. [Boards and Issues](./scrum.html#boards-and-issues)
- 3. [Create board](./scrum.html#create-board)
-6. [Bug tracking template](./bug.html)
-7. [Releases](./releases.html)
-8. [Pages](./pages.html)
-9. [Components](./components.html)
- 1. [Creating and editing](./components.html#creating-and-editing)
- 2. [Adding issues](./components.html#adding-issues)
-10. [Dashboards](./dashboards.html)
- 1. [Adding a dashboard](./dashboards.html#adding-a-dashboard)
- 2. [Adding gadgets](./dashboards.html#adding-gadgets)
diff --git a/src/tutorials/how-to-use-jira/kanban.du b/src/tutorials/how-to-use-jira/kanban.du
new file mode 100644
index 0000000..5e5eb00
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/kanban.du
@@ -0,0 +1,38 @@
+# Kanban template - How to use Jira
+
+'define expected-reading 1 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./projects.html Projects
+'define next_link ./scrum.html Scrum template
+[$pagination_middle]
+
+.contents
+.numbered
+1. [url #create-board Create board]
+2. [url #backlog 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.
+
+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.
+
+## Create board
+
+This template can be chosen when =[creating a project]=
+
+[image ./img/choose-classic-template.png]
+
+and =[from the `[Create board]` screen]=.
+
+[image ./img/scrum-kanban-board.png]
+
+## Backlog
+
+In kanban, =[the backlog is just another column in your board(s)]=. It can be removed entirely.
+
+[image ./img/backlog-kanban.png]
diff --git a/src/tutorials/how-to-use-jira/kanban.md b/src/tutorials/how-to-use-jira/kanban.md
deleted file mode 100644
index 4818f5c..0000000
--- a/src/tutorials/how-to-use-jira/kanban.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# Kanban template - How to use Jira
-
-[`<<`](./) || [`< Projects`](./projects.html) || [`Scrum template >`](./scrum.html)
-
-<br>
-
-## Contents
-
-1. [Create board](#create-board)
-2. [Backlog](#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 [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 [these sets of articles](https://www.atlassian.com/agile/kanban) from Atlassian.
-
-## Create board
-
-This template can be chosen when **creating a project**
-
-![](./img/choose-classic-template.png)
-
-and **from the `Create board` screen**.
-
-![](./img/scrum-kanban-board.png)
-
-## Backlog
-
-In kanban, **the backlog is just another column in your board(s)**. It can be removed entirely.
-
-![](./img/backlog-kanban.png)
-
diff --git a/src/tutorials/how-to-use-jira/pages.du b/src/tutorials/how-to-use-jira/pages.du
new file mode 100644
index 0000000..b2e0466
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/pages.du
@@ -0,0 +1,22 @@
+# Pages - How to use Jira
+
+'define expected-reading 1 min
+'define created 24 July 2020
+'define edited 16 September 2020
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./releases.html Releases
+'define next_link ./components.html Components
+[$pagination_middle]
+
+=[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.
+
+[image ./img/test-page.png]
+
+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.
+
+=[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.
+
+=[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].
+
diff --git a/src/tutorials/how-to-use-jira/pages.md b/src/tutorials/how-to-use-jira/pages.md
deleted file mode 100644
index adf2c1a..0000000
--- a/src/tutorials/how-to-use-jira/pages.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Pages - How to use Jira
-
-[`<<`](./) || [`< Releases`](./releases.html) || [`Components >`](./components.html)
-
-<br>
-
-**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.
-
-![](./img/test-page.png)
-
-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.
-
-**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.
-
-**Confluence won't be covered in this tutorial**. You can read more about it [here](https://www.atlassian.com/software/confluence/guides/get-started/set-up).
-
diff --git a/src/tutorials/how-to-use-jira/projects.du b/src/tutorials/how-to-use-jira/projects.du
new file mode 100644
index 0000000..ecf5fe9
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/projects.du
@@ -0,0 +1,158 @@
+# Projects - How to use Jira
+
+'define expected-reading 4 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./cards.html Cards
+'define next_link ./kanban.html Kanban template
+[$pagination_middle]
+
+:contents
+:numbered
+1. [url #creating-a-project Creating a project]
+2. [url #boards Boards]
+ .numbered
+ 1. [url #columns Columns]
+ 2. [url #adding-more-boards-to-a-project Adding more boards to a project]
+
+3. [url #backlog Backlog]
+4. [url #add-item Add item]
+
+
+
+In short, =[projects are a collection of issues]= with added functionality for =[organising them, getting statistics, etc]=.
+
+[image ./img/projects.png]
+
+## Creating a project
+
+To create a project, either =[click on `[Create project]` from the menu `[Projects]` in the top bar]=,
+
+[image ./img/create-project-top.png]
+
+or =[click on the `[Create project]` button in the `[View all projects]` page]=.
+
+[image ./img/view-all-projects-top.png]
+
+[image ./img/create-project.png]
+
+=[Note]=: when you =[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]=.
+
+[image ./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]=.
+
+[image ./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]]=.
+
+[image ./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.
+
+Projects also have [url ./releases.html Releases], [url ./pages.html Pages] and [url ./components.html Components], 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.
+
+### Columns
+
+=[Boards are divided into columns]= that contain the cards (issues). A card can move =[freely]= from one column to another.
+
+[image ./img/SOD.png]
+
+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]
+
+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]=.
+
+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]
+
+[image ./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.
+
+This can be done, either while in a board, from =[clicking the three dots and choosing `[Create board]`]=
+
+[image ./img/create-board.png]
+
+or =[in the sidebar, from the `[Board]` menu]=.
+
+[image ./img/sidebar-create-board.png]
+
+After that, you are met with the `[Create a board]` window, where you can choose your template.
+
+[image ./img/scrum-kanban-board.png]
+
+Once you've made your choice, you will be met with three options:
+
+[image ./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).
+
+ [image ./img/npb.png]
+
+- =[Board from existing project]= - creates a board that gets the filter from another project
+
+ [image ./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
+
+ [image ./img/ntb-filter.png]
+
+
+## Backlog
+
+=[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])]=,
+
+[image ./img/scrum-backlog.png]
+
+=[just a column in a board ([url ./kanban.html Kanban])]=,
+
+[image ./img/backlog-kanban.png]
+
+or =[nonexistent ([url ./bug.md bug tracking])]=.
+
+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.
+
+[image ./img/add-item-kanban.png]
+
+From here you can =[add a website shortcut]=, simply by putting the web address and giving it a name.
+
+[image ./img/add-item-to-project.png]
+
+[image ./img/add-shortcut.png]
+
+The name is used for showing the shortcut on the sidebar.
+
+[image ./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]=.
+
+[image ./img/test-repo.png]
+
+[image ./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.
+
+From the `[Add Item]` menu you can also =[toggle the shortcut to [url ./pages.html Pages]]=.
diff --git a/src/tutorials/how-to-use-jira/projects.md b/src/tutorials/how-to-use-jira/projects.md
deleted file mode 100644
index cfe2e0e..0000000
--- a/src/tutorials/how-to-use-jira/projects.md
+++ /dev/null
@@ -1,147 +0,0 @@
-# Projects - How to use Jira
-
-[`<<`](./) || [`< Cards`](./cards.html) || [`Kanban template >`](./kanban.html)
-
-<br>
-
-## Contents
-
-1. [Creating a project](#creating-a-project)
-2. [Boards](#boards)
- 1. [Columns](#columns)
- 2. [Adding more boards to a project](#adding-more-boards-to-a-project)
-3. [Backlog](#backlog)
-4. [Add item](#add-item)
-
-In short, **projects are a collection of issues** with added functionality for **organising them, getting statistics, etc**.
-
-![](./img/projects.png)
-
-## Creating a project
-
-To create a project, either **click on `Create project` from the menu `Projects` in the top bar**,
-
-![](./img/create-project-top.png)
-
-or **click on the `Create project` button in the `View all projects` page**.
-
-![](./img/view-all-projects-top.png)
-
-![](./img/create-project.png)
-
-**Note**: when you **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**.
-
-![](./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**.
-
-![](./img/create-project-new.png)
-
-This tutorial covers **only** the three classic software templates: [**Kanban**](./kanban.html), [**Scrum**](./scrum.html) and [**Bug tracking**](./bug.html).
-
-![](./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.
-
-Projects also have [Releases](./releases.html), [Pages](./pages.html) and [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 [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.
-
-![](./img/SOD.png)
-
-To illustrate how this could be useful, let's say we have three columns: `TO DO`, `DOING` and `DONE`.
-
-![](./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.
-
-Of course, the name, quantity and purpose of different columns **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).
-
-![](./img/board-settings.png)
-
-![](./img/columns-edit.png)
-
-### Adding more boards to a project
-
-You can also add to a project as many [**Scrum**](./scrum.html) and [**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`**
-
-![](./img/create-board.png)
-
-or **in the sidebar, from the `Board` menu**.
-
-![](./img/sidebar-create-board.png)
-
-After that, you are met with the `Create a board` window, where you can choose your template.
-
-![](./img/scrum-kanban-board.png)
-
-Once you've made your choice, you will be met with three options:
-
-![](./img/board-from.png)
-
-- **Board created with new Software project** - creates a new project with a new board (has the name of the project).
-
- ![](./img/npb.png)
-
-- **Board from existing project** - creates a board that gets the filter from another project
-
- ![](./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
-
- ![](./img/ntb-filter.png)
-
-## Backlog
-
-**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 ([Scrum](./scrum.html))**,
-
-![](./img/scrum-backlog.png)
-
-**just a column in a board ([Kanban](./kanban.html))**,
-
-![](./img/backlog-kanban.png)
-
-or **nonexistent ([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.
-
-![](./img/add-item-kanban.png)
-
-From here you can **add a website shortcut**, simply by putting the web address and giving it a name.
-
-![](./img/add-item-to-project.png)
-
-![](./img/add-shortcut.png)
-
-The name is used for showing the shortcut on the sidebar.
-
-![](./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**.
-
-![](./img/test-repo.png)
-
-![](./img/test-repo-sidebar.png)
-
-**Integration won't be covered in this tutorial**, but I can recommend [this](https://www.idalko.com/jira-github-integration/) article for `GitHub` integration and [this](https://www.idalko.com/jira-bitbucket-integration/) one for `Bitbucket` integration.
-
-From the `Add Item` menu you can also **toggle the shortcut to [Pages](./pages.html)**.
-
diff --git a/src/tutorials/how-to-use-jira/releases.du b/src/tutorials/how-to-use-jira/releases.du
new file mode 100644
index 0000000..430de92
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/releases.du
@@ -0,0 +1,21 @@
+# Releases - How to use Jira
+
+'define expected-reading 1 min
+'define created 24 July 2020
+'define edited 16 September 2020
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./bug.html Bug tracking template
+'define next_link ./pages.html Pages
+[$pagination_middle]
+
+The `[Releases]` page in a project shows =[versions]=, the ones in development and the ones that are completed.
+
+=[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.
+
+## Adding issues to a version
+
+When creating an issue, you can specify a version in the `[Fix versions]` property.
+
+[image ./img/fix-versions.png]
diff --git a/src/tutorials/how-to-use-jira/releases.md b/src/tutorials/how-to-use-jira/releases.md
deleted file mode 100644
index d2849d6..0000000
--- a/src/tutorials/how-to-use-jira/releases.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Releases - How to use Jira
-
-[`<<`](./) || [`< Bug tracking template`](./bug.html) || [`Pages >`](./pages.html)
-
-<br>
-
-The `Releases` page in a project shows **versions**, the ones in development and the ones that are completed.
-
-**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.
-
-## Adding issues to a version
-
-When creating an issue, you can specify a version in the `Fix versions` property.
-
-![](./img/fix-versions.png)
-
diff --git a/src/tutorials/how-to-use-jira/scrum.du b/src/tutorials/how-to-use-jira/scrum.du
new file mode 100644
index 0000000..37ca494
--- /dev/null
+++ b/src/tutorials/how-to-use-jira/scrum.du
@@ -0,0 +1,55 @@
+# Scrum template - How to use Jira
+
+'define expected-reading 2 min
+'define created 24 July 2020
+'define edited 03 June 2021
+[$pagenav]
+
+'define start_link ./
+'define prev_link ./kanban.html Kanban template
+'define next_link ./bug.html Bug tracking template
+[$pagination_middle]
+
+.contents
+.numbered
+1. [url #backlog Backlog]
+2. [url #boards-and-issues Boards and Issues]
+3. [url #create-board Create board]
+
+The scrum template is very similar to the kanban template, with one big difference: =[sprints]=.
+
+=[All issues]= are put into the =[backlog]= (which is now a =[separate page]=). From there, they are organised into =[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.
+
+Your =[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]=.
+
+[image ./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.
+
+[image ./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.
+
+[image ./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.
+
+[image ./img/active-sprints.png]
+
+## Create board
+
+This template can be chosen when =[creating a project]=
+
+[image ./img/choose-classic-template.png]
+
+and =[from the `[Create board]` screen]=.
+
+[image ./img/scrum-kanban-board.png]
diff --git a/src/tutorials/how-to-use-jira/scrum.md b/src/tutorials/how-to-use-jira/scrum.md
deleted file mode 100644
index d4e9255..0000000
--- a/src/tutorials/how-to-use-jira/scrum.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# Scrum template - How to use Jira
-
-[`<<`](./) || [`< Kanban template`](./kanban.html) || [`Bug tracking template >`](./bug.html)
-
-<br>
-
-## Contents
-
-1. [Backlog](#backlog)
-2. [Boards and Issues](#boards-and-issues)
-3. [Create board](#create-board)
-
-The scrum template is very similar to the kanban template, with one big difference: **sprints**.
-
-**All issues** are put into the **backlog** (which is now a **separate page**). From there, they are organised into **sprints**.
-
-In general [agile software development](https://www.atlassian.com/agile), 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.
-
-Your **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**.
-
-![](./img/sample-scrum-backlog.png)
-
-From here you can also organise **Versions** (refer to [Releases](./releases.html)) and **Epics** (refer to [Cards](./cards.html)). An important note is that Epics in this context don't need to have their linked issues in only one sprint.
-
-![](./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.
-
-![](./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.
-
-![](./img/active-sprints.png)
-
-## Create board
-
-This template can be chosen when **creating a project**
-
-![](./img/choose-classic-template.png)
-
-and **from the `Create board` screen**.
-
-![](./img/scrum-kanban-board.png)
-
diff --git a/src/tutorials/index.du b/src/tutorials/index.du
new file mode 100644
index 0000000..ec064e2
--- /dev/null
+++ b/src/tutorials/index.du
@@ -0,0 +1,68 @@
+# Tutorials
+
+Educational articles with the sole goal of explaining technologies, processes or anything in between.
+
+\n
+
+#### *[2023]*
+
+:defs
+; [$gb] 16 Dec &emsp; [url /tutorials/fix-qc-timeout Fix "qc timeout" kernel log error]
+: `[Linux]` | `[kernel]` | `[libata]` `[qc]` `[logs]` `[DMA]`
+
+; [$gb] 28 Jun &emsp; [url /tutorials/fix-network-brother-printers Fix networked Brother printers not working in Linux]
+: `[Linux]` | `[CUPS]` | `[Printers]` `[Brother]` `[Network]` `[avahi]`
+
+; [$gb] 14 Jun &emsp; [url /tutorials/gns3-initsh-no-such-file Fix "exec /gns3/init.sh: no such file or directory"]
+: `[Linux]` | `[GNS3]` | `[Docker]` `[busybox]`
+
+; [$gb] 26 Apr &emsp; [url /tutorials/install-drivers-for-epson-scanners Install drivers for Epson scanners]
+: `[Linux]` | `[SANE]` | `[Scanners]` `[Epson]` `[epkowa]` `[iscan]`
+
+; [$gb] 25 Apr &emsp; [url /tutorials/managing-apps-with-adb-without-root Managing Android apps with ADB (and without root)]
+: `[Android]` | `[ADB]` | `[Apps]` `[Linux]` `[Windows]`
+
+; [$gb] 01 Jan &emsp; [url /tutorials/virt-manager-freeze-on-browse virt-manager freezing up when clicking Browse in any window]
+: `[Linux]` | `[virt-manager]` | `[QEMU/KVM]` `[libvirt]` `[Linux]` `[GTK]`
+
+
+#### *[2022]*
+
+:defs
+; [$gb] 16 Sep &emsp; [url /tutorials/how-to-encrypt-email How to encrypt email]
+: `[All]` | `[Email]` | `[PGP]` `[S/MIME]` `[Email Client]` `[Gmail]` `[Outlook]` `[Protonmail]`
+
+; [$gb] 30 Jul &emsp; [url /tutorials/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 /tutorials/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]`
+
+
+#### *[2021]*
+
+:defs
+; [$gb] 01 Nov &emsp; [url /tutorials/turn-off-notifications-windows How to turn off notifications on Windows]
+: `[Windows 10]` | `[Settings]` | `[Notifications]`
+
+; [$gb] 01 Nov &emsp; [url /tutorials/disable-sticky-keys-popup How to disable Sticky Keys prompt]
+: `[Windows]` | `[Settings]` | `[Sticky Keys]`
+
+; [$gb] 26 Oct &emsp; [url /tutorials/remove-weather-widget How to remove Windows Weather Widget]
+: `[Windows 10]` | `[Settings]` | `[Taskbar]` `[Weather Widget]`
+
+; [$gb] 04 Oct &emsp; [url /tutorials/windows-run-dialog Windows Run dialog]
+: `[Windows]` | `[Commands]` | `[Run]` `[Settings]`
+
+; [$gb] 03 Oct &emsp; [url /tutorials/export-skype How to export Skype data]
+: `[Skype]` | `[Export]` | `[Archive]` `[skype-parser]`
+
+
+#### *[2020]*
+
+:defs
+; [$gb] 24 Jul &emsp; [url /tutorials/how-to-use-jira How to use Jira]
+: `[Project Management]` | `[Jira]` | `[Agile]` `[Issue tracking]` `[Bug tracking]` `[Kanban]` `[Atlassian]`
+
+; [$gb] 21 May &emsp; [url /tutorials/connect-to-mysql-in-dotnet-ef Connect to Mysql in .NET and Entity Framework]
+: `[ASP.Net]` | `[MySQL]` | `[Entity Framework]` `[Pomelo]`
diff --git a/src/tutorials/index.md b/src/tutorials/index.md
deleted file mode 100644
index bfd957d..0000000
--- a/src/tutorials/index.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# Tutorials
-
-Educational articles with the sole goal of explaining technologies, processes or anything in between.
-
-<br>
-
-#### *2023*
-
-&.gb 16 Dec &emsp; [Fix "qc timeout" kernel log error](/tutorials/fix-qc-timeout)
-: `Linux` | `kernel` | `libata` `qc` `logs` `DMA`
-
-
-&.gb 28 Jun &emsp; [Fix networked Brother printers not working in Linux](/tutorials/fix-network-brother-printers)
-: `Linux` | `CUPS` | `Printers` `Brother` `Network` `avahi`
-
-&.gb 14 Jun &emsp; [Fix "exec /gns3/init.sh: no such file or directory"](/tutorials/gns3-initsh-no-such-file)
-: `Linux` | `GNS3` | `Docker` `busybox`
-
-&.gb 26 Apr &emsp; [Install drivers for Epson scanners](/tutorials/install-drivers-for-epson-scanners)
-: `Linux` | `SANE` | `Scanners` `Epson` `epkowa` `iscan`
-
-&.gb 25 Apr &emsp; [Managing Android apps with ADB (and without root)](/tutorials/managing-apps-with-adb-without-root)
-: `Android` | `ADB` | `Apps` `Linux` `Windows`
-
-&.gb 01 Jan &emsp; [virt-manager freezing up when clicking Browse in any window](/tutorials/virt-manager-freeze-on-browse)
-: `Linux` | `virt-manager` | `QEMU/KVM` `libvirt` `Linux` `GTK`
-
-#### *2022*
-
-&.gb 16 Sep &emsp; [How to encrypt email](/tutorials/how-to-encrypt-email)
-: `All` | `Email` | `PGP` `S/MIME` `Email Client` `Gmail` `Outlook` `Protonmail`
-
-&.gb 30 Jul &emsp; [Fix "No frame buffer" error in <span class="no-wrap">Plan 9</span>](/tutorials/fix-no-frame-buffer-plan9)
-: `Plan 9` | `Configuration` | `QEMU/KVM` `Linux` `monitor`
-
-&.gb 30 Jul &emsp; [Install <span class="no-wrap">Plan 9</span> with virt-manager](/tutorials/install-plan9-with-virt-manager)
-: `Plan 9` | `Installation` | `Setup` `QEMU/KVM` `virt-manager` `Linux`
-
-#### *2021*
-
-&.gb 01 Nov &emsp; [How to turn off notifications on Windows](/tutorials/turn-off-notifications-windows)
-: `Windows 10` | `Settings` | `Notifications`
-
-&.gb 01 Nov &emsp; [How to disable Sticky Keys prompt](/tutorials/disable-sticky-keys-popup)
-: `Windows` | `Settings` | `Sticky Keys`
-
-&.gb 26 Oct &emsp; [How to remove Windows Weather Widget](/tutorials/remove-weather-widget)
-: `Windows 10` | `Settings` | `Taskbar` `Weather Widget`
-
-&.gb 04 Oct &emsp; [Windows Run dialog](/tutorials/windows-run-dialog)
-: `Windows` | `Commands` | `Run` `Settings`
-
-&.gb 03 Oct &emsp; [How to export Skype data](/tutorials/export-skype)
-: `Skype` | `Export` | `Archive` `skype-parser`
-
-#### *2020*
-
-&.gb 24 Jul &emsp; [How to use Jira](/tutorials/how-to-use-jira)
-: `Project Management` | `Jira` | `Agile` `Issue tracking` `Bug tracking` `Kanban` `Atlassian`
-
-&.gb 21 May &emsp; [Connect to Mysql in .NET and Entity Framework](/tutorials/connect-to-mysql-in-dotnet-ef)
-: `ASP.Net` | `MySQL` | `Entity Framework` `Pomelo`
-
diff --git a/src/tutorials/install-drivers-for-epson-scanners/index.du b/src/tutorials/install-drivers-for-epson-scanners/index.du
new file mode 100644
index 0000000..faba80e
--- /dev/null
+++ b/src/tutorials/install-drivers-for-epson-scanners/index.du
@@ -0,0 +1,62 @@
+# Install drivers for Epson scanners
+
+'define expected-reading 3 min
+'define created 26 April 2023
+'define edited 26 April 2023
+[$pagenav]
+
+'footnote gentoo-sane On Gentoo the package is `[sane-backends]`, as per the [url https://wiki.gentoo.org/wiki/SANE wiki].
+
+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.
+
+## 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]:
+
+```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]`.
+
+## epkowa plus non-free interpreter
+
+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.
+
+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.
+
+:ordered
+1. Install `[rpm]` with your package manager
+
+2. Download the 32 or 64 bit =[[ rpm ]]= package
+
+3. Extract it
+
+ ```bash
+tar -xf epsonscan2-bundle-SOMETHING.rpm.tar.gz
+
+4. Install the core application and non-free plugins with rpm
+
+ ```bash
+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]).
+
+'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]...
+
+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.
diff --git a/src/tutorials/install-drivers-for-epson-scanners/index.md b/src/tutorials/install-drivers-for-epson-scanners/index.md
deleted file mode 100644
index d7f42fd..0000000
--- a/src/tutorials/install-drivers-for-epson-scanners/index.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# Install drivers for Epson scanners
-
-Sometimes your Epson scanner might work out of the box, and sometimes it might not.
-First, make sure you have [SANE](http://sane-project.org/) installed on your machine[^gentoo-sane].
-Second look through [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
-
-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]:
-
-```bash
-systemctl status saned.service
-```
-
-and make sure the [sane-epson2](http://www.sane-project.org/man/sane-epson2.5.html) (or [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
-
-If it's unsupported and there is a note
-
-> 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 [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 [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.
-
-1. Install `rpm` with your package manager
-2. Download the 32 or 64 bit **[ rpm ]** package
-3. Extract it
-
- ```bash
- tar -xf epsonscan2-bundle-SOMETHING.rpm.tar.gz
- ```
-
-4. Install the core application and non-free plugins with rpm
-
- ```bash
- 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 [source](https://download.ebz.epson.net/man/linux/epsonscan2_e.html#sec5-1-4) (source file is available at the bottom of the [support site](https://support.epson.net/linux/en/epsonscan2.php)).
-
-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.
-
-[^gentoo-sane]: On Gentoo the package is `sane-backends`, as per the [wiki](https://wiki.gentoo.org/wiki/SANE).
-[^openrc-sane]: For OpenRC: `rc-service saned status`
-[^gentoo-epkowa]: Surprisingly enough, on my Gentoo installation everything works fine without the package. Either something else is helping me or [something is in the "more magic" position](http://www.catb.org/jargon/html/magic-story.html)...
diff --git a/src/tutorials/install-plan9-with-virt-manager/index.du b/src/tutorials/install-plan9-with-virt-manager/index.du
new file mode 100644
index 0000000..22a8612
--- /dev/null
+++ b/src/tutorials/install-plan9-with-virt-manager/index.du
@@ -0,0 +1,91 @@
+# Install Plan 9 with virt-manager
+
+'define expected-reading 4 min
+'define created 30 July 2022
+'define edited 30 July 2022
+[$pagenav]
+
+.contents
+.numbered
+1. [url #creating-the-virtual-machine Creating the virtual machine]
+2. [url #installing-plan-9-itself 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.
+
+## 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].
+
+:ordered
+1. Press the *["Create a new virtual machine"]* and select *["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)"]*
+
+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.
+ - 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.
+
+5. Finally click finish.
+
+
+## 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].
+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]
+
+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]`
+
+ .unordered
+ - A very incomplete list can be found [url https://9p.io/wiki/plan9/setting_the_right_monitor_size/index.html here]
+
+4. =[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 /tutorials/fix-no-frame-buffer-plan9 this tutorial].
+
+
+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)
+
+ [image ./img/partdisk-partition.png]
+
+2. On "Install mbr" question, enter `[y]`
+
+ [image ./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]`
+
+ [image ./img/partdisk-fdisk.png]
+
+ [image ./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]`
+
+ [image ./img/mountdist-distribution-disk.png]
+
+5. When you get "/%" before cursor (during mountdisk task) just enter `[exit]`
+
+ [image ./img/mountdist-browse.png]
+
+6. On "Enable boot method" enter `[plan9]`
+
+ [image ./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!
diff --git a/src/tutorials/install-plan9-with-virt-manager/index.md b/src/tutorials/install-plan9-with-virt-manager/index.md
deleted file mode 100644
index b81594c..0000000
--- a/src/tutorials/install-plan9-with-virt-manager/index.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Install Plan 9 with virt-manager
-
-## Contents
-
-1. [Creating the virtual machine](#creating-the-virtual-machine)
-2. [Installing Plan 9 itself](#installing-plan-9-itself)
-
-Installing [Plan 9 by Bell Labs](https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs) with `qemu` itself isn't difficult and there are [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 [here](https://9p.io/plan9/download.html). For a compressed version and checksums, refer to [this page](https://9p.io/wiki/plan9/Download/index.html).
-
-1. Press the *"Create a new virtual machine"* and select *"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)"*
-
-3. For memory select 512 MiB (the default 1024 MiB is also fine) and 1 CPU
- - Plan 9 is stupid lightweight and according to [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 [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.
-
-## 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 [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.
-
-1. On the boot screen press 1 and enter
-
- ![](./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`
- - A very incomplete list can be found [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.
- - If you mistakenly leave it at `xga`, refer to [this tutorial](/tutorials/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.
-
-1. On "Disk partiton" question, enter `sdC0` (the option that says Hard Disk on it)
-
- ![](./img/partdisk-partition.png)
-
-2. On "Install mbr" question, enter `y`
-
- ![](./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`
-
- ![](./img/partdisk-fdisk.png)
- ![](./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`
-
- ![](./img/mountdist-distribution-disk.png)
-
-5. When you get "/%" before cursor (during mountdisk task) just enter `exit`
-
- ![](./img/mountdist-browse.png)
-
-6. On "Enable boot method" enter `plan9`
-
- ![](./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!
-
diff --git a/src/tutorials/managing-apps-with-adb-without-root/index.md b/src/tutorials/managing-apps-with-adb-without-root/index.du
index 1c7314e..eee78d4 100644
--- a/src/tutorials/managing-apps-with-adb-without-root/index.md
+++ b/src/tutorials/managing-apps-with-adb-without-root/index.du
@@ -1,123 +1,128 @@
# Managing apps with ADB (and without root)
-## Contents
+'define expected-reading 8 min
+'define created 25 February 2023
+'define edited 25 February 2023
+[$pagenav]
-1. [Installing](#installing)
-2. [Opening a shell and connecting to your device](#opening-a-shell-and-connecting-to-your-device)
-3. [Managing applications](#managing-applications)
-4. [What to remove](#what-to-remove)
+.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]
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 [cause issues](https://www.xda-developers.com/samsung-galaxy-z-fold-3-unlock-bootloader-broken-camera/).
+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].
+
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, [XDA's article](https://www.xda-developers.com/install-adb-windows-macos-linux/), as well as [these](https://www.maketecheasier.com/uninstall-system-apps-without-root-android/) [maketecheasier](https://www.maketecheasier.com/get-started-with-android-debug-bridge-adb/) [articles](https://www.maketecheasier.com/enable-developer-options-in-android-42/) go into more detail and show pictures.
+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.
## Installing
Windows:
-1. Download the official platform tools from [here](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)
+.numbered
+1. Download the official platform tools from [url https://dl.google.com/android/repository/platform-tools-latest-windows.zip here]
2. Extract the files in a folder and navigate to it
Linux (or 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 [here](https://dl.google.com/android/repository/platform-tools-latest-linux.zip) for Linux, and [here](https://dl.google.com/android/repository/platform-tools-latest-darwin.zip) for 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.
## Opening a shell and connecting to your device
ADB is very powerfull, so by default phones don't allow you to connect to the device with it.
First, we'll allow such a connection:
-1. Go to `Settings/About phone` (depending on your Android skin, this might be located in a slightly different place)
+.numbered
+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
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").
-Now, we'll open a shell[^interactive-shell], a program with which to directly enter commands that the device understands:
+'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:
-```
+```shell
adb shell
-```
## Managing applications
There are 3 general commands that you would want to use:
-```
+```shell
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
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
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 =[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 =[AT YOUR OWN RISK!]=
+Although they shouldn't, they might cause problems =[FOR WHICH I'M NOT RESPONSIBLE!]=
+:unordered
- Facebook
-```
+```shell
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
pm uninstall -k --user 0 package:com.facebook.appmanager
-```
- Netflix
-```
+```shell
pm uninstall -k --user 0 com.netflix.partner.activation
pm uninstall -k --user 0 com.netflix.mediaclient
-```
- Microsoft apps
-```
+```shell
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
pm uninstall -k --user 0 com.microsoft.office.word
pm uninstall -k --user 0 com.microsoft.office.powerpoint
-```
- Google apps
-```
+```shell
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
@@ -133,23 +138,20 @@ pm uninstall -k --user 0 com.google.android.talk
pm uninstall -k --user 0 com.google.android.apps.books
pm uninstall -k --user 0 com.google.android.apps.magazines
pm uninstall -k --user 0 com.google.android.apps.plus
-```
- Windows 10 Phone comanion
-```
+```shell
pm uninstall -k --user 0 com.microsoft.appmanager
-```
- AR Emoji
-```
+```shell
pm uninstall -k --user 0 com.samsung.android.aremoji
-```
- Bixby
-```
+```shell
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
@@ -164,88 +166,76 @@ pm uninstall -k --user 0 com.samsung.android.bixby.service
pm uninstall -k --user 0 com.samsung.android.app.routines
pm uninstall -k --user 0 com.samsung.android.visionintelligence
pm uninstall -k --user 0 com.samsung.android.app.spage
-```
- Samsung Pass/Pay
-```
+```shell
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
pm uninstall -k --user 0 com.samsung.android.spay
pm uninstall -k --user 0 com.samsung.android.spayfw
-```
- Samsung Kids
-```
+```shell
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
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
pm uninstall -k --user 0 com.samsung.android.game.gos
-```
- Galaxy Friends
-```
+```shell
pm uninstall -k --user 0 com.samsung.android.mateagent
-```
- Samsung Smartthings
-```
+```shell
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
pm uninstall -k --user 0 com.samsung.android.drivelink.stub
-```
- Stickers
-```
+```shell
pm uninstall -k --user 0 com.sec.android.mimage.avatarstickers
-```
- Samsung Global Goals
-```
+```shell
pm uninstall -k --user 0 com.samsung.sree
-```
- Samsung Members
-```
+```shell
pm uninstall -k --user 0 com.samsung.android.voc
-```
- Samsung LED cover
-```
+```shell
pm uninstall -k --user 0 com.samsung.android.app.ledbackcover
pm uninstall -k --user 0 com.sec.android.cover.ledcover
-```
- Samsung TV
-```
+```shell
pm uninstall -k --user 0 com.sec.android.app.withtv
-```
- Knox
-```
+```shell
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
@@ -253,64 +243,56 @@ pm uninstall -k --user 0 com.sec.enterprise.knox.cloudmdm.smdms
pm uninstall -k --user 0 com.samsung.android.knox.analytics.uploader
pm uninstall -k --user 0 com.sec.enterprise.knox.attestation
pm uninstall -k --user 0 com.samsung.android.knox.containercore
-```
- Samsung DEX
-```
+```shell
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
pm uninstall -k --user 0 com.sec.android.app.sbrowser
pm uninstall -k --user 0 com.samsung.android.app.sbrowseredge
-```
- Samsung Email
-```
+```shell
pm uninstall -k --user 0 com.samsung.android.email.provider
pm uninstall -k --user 0 com.wsomacp
-```
- Samsung Smartthings
-```
+```shell
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
-```
+pm uninstall -k --user 0 com.samsung.android.oneconnect
- Gear VR
-```
+```shell
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
pm uninstall -k --user 0 com.google.vr.vrcore
-```
- Printings
-```
+```shell
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
pm uninstall -k --user 0 de.axelspringer.yana.zeropage
-```
- Verizon
-```
+```shell
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
@@ -319,18 +301,15 @@ pm uninstall -k --user 0 com.motricity.verizon.ssodownloadable
pm uninstall -k --user 0 com.vzw.hs.android.modlite
pm uninstall -k --user 0 com.samsung.vvm
pm uninstall -k --user 0 com.vznavigator.[You_Model_Here]
-```
- T-mobile
-```
+```shell
pm uninstall -k --user 0 com.mobitv.client.tmobiletvhd
pm uninstall -k --user 0 us.com.dt.iq.appsource.tmobile
-```
-<br>
-More information on available package commands can be shown with `pm help`.
-You can learn more about the adb tool from [developer.android.com](https://developer.android.com/studio/command-line/adb).
+\n
-[^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
+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].
diff --git a/src/tutorials/remove-weather-widget/index.du b/src/tutorials/remove-weather-widget/index.du
new file mode 100644
index 0000000..b8193fc
--- /dev/null
+++ b/src/tutorials/remove-weather-widget/index.du
@@ -0,0 +1,19 @@
+# How to remove Windows Weather Widget
+
+'define expected-reading 1 min
+'define created 26 October 2021
+'define edited 26 October 2021
+[$pagenav]
+
+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.
+
+This is how:
+
+:ordered
+1. Right-click on an empty spot in the taskbar
+
+ [image ./img/windows10-taskbar.png]
+
+2. Go up to *[News and interests]*, and then click *[Turn off]* in the popped up window
+
+ [image ./img/remove-newsweather-windows10.png]
diff --git a/src/tutorials/remove-weather-widget/index.md b/src/tutorials/remove-weather-widget/index.md
deleted file mode 100644
index ecdc213..0000000
--- a/src/tutorials/remove-weather-widget/index.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# How to remove Windows Weather Widget
-
-From June 2021 Microsoft introduced the `Weather Widget` on Windows 10. Given that it takes up space on the taskbar [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:
-
-1. Right-click on an empty spot in the taskbar
-
- ![](./img/windows10-taskbar.png)
-2. Go up to *News and interests*, and then click *Turn off* in the popped up window
-
- ![](./img/remove-newsweather-windows10.png)
diff --git a/src/tutorials/turn-off-notifications-windows/index.du b/src/tutorials/turn-off-notifications-windows/index.du
new file mode 100644
index 0000000..cf60632
--- /dev/null
+++ b/src/tutorials/turn-off-notifications-windows/index.du
@@ -0,0 +1,27 @@
+# How to turn off notifications on Windows
+
+'define expected-reading 1 min
+'define created 01 November 2021
+'define edited 01 November 2021
+[$pagenav]
+
+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
+
+ [image ./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
+
+ [image ./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]*
+
+ .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
+
+ [image ./img/windows-settings-notifications-application.png]
+
+3. Finally, you can simply close the window
diff --git a/src/tutorials/turn-off-notifications-windows/index.md b/src/tutorials/turn-off-notifications-windows/index.md
deleted file mode 100644
index 4d9b8f4..0000000
--- a/src/tutorials/turn-off-notifications-windows/index.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# How to turn off notifications on Windows
-
-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:
-
-1. In the *Search bar* type in **Notification**. The **Notification & actions settings** option should show up, click it
-
- ![](./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
-
- ![](./img/windows-settings-notifications-off.png)
-
- *Note: "Suggest best ways", "Welcome Experience" and "Tips and tricks" will still show up, you'll have to uncheck those individually*
-
- 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
-
- ![](./img/windows-settings-notifications-application.png)
-
-3. Finally, you can simply close the window
diff --git a/src/tutorials/virt-manager-freeze-on-browse/index.md b/src/tutorials/virt-manager-freeze-on-browse/index.du
index 85fc620..067c86d 100644
--- a/src/tutorials/virt-manager-freeze-on-browse/index.md
+++ b/src/tutorials/virt-manager-freeze-on-browse/index.du
@@ -1,20 +1,23 @@
# virt-manager freezing up when clicking Browse in any window
+'define expected-reading 1 min
+'define created 01 January 2023
+'define edited 01 January 2023
+[$pagenav]
+
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.
-This issue is caused by some sort of problem with the storage pools[^storage-pools] when it tries to load them.
+'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.
+
+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
sudo mv /etc/libvirt/storage /etc/libvirt/storage-broken
-```
libvirt automagically regenerates the original folder, so you might need to restart it:
-```
+```shell
sudo systemctl restart libvirtd
-```
-
-[^storage-pools]: The storage pool is just a folder with files that store what locations can be used by virtual machines (more info [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.
diff --git a/src/tutorials/windows-run-dialog/index.du b/src/tutorials/windows-run-dialog/index.du
new file mode 100644
index 0000000..5f54169
--- /dev/null
+++ b/src/tutorials/windows-run-dialog/index.du
@@ -0,0 +1,125 @@
+# Windows Run dialog
+
+'define expected-reading 3 min
+'define created 04 October 2021
+'define edited 31 October 2021
+[$pagenav]
+
+:contents
+:numbered
+1. [url #opening-the-run-dialog Opening the Run dialog]
+
+2. [url #commands Commands]
+ .numbered
+ 1. [url #folders Folders]
+ 2. [url #programs Programs]
+ 3. [url #windows-settings Windows settings]
+
+3. [url #for-more 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]=.
+
+## Opening the Run dialog
+
+To open the Run dialog, you can either:
+
+*[A)]* Press `[Win + R]` key combination
+
+or
+
+*[B)]* Right click on the Windows menu, and then press `[Run]`
+
+[image ./img/open-run-windows-menu.png]
+
+## Commands
+
+[image ./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\\]`.
+
+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
+|=Command=||=Location=|
+|:`[%ProgramFiles%]`:||:Program Files Folder:|
+|:`[%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.
+
+### 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]`.
+
+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
+|=Command=||=Application=|
+|:`[calc]`:||:Calculator:|
+|:`[mspaint]`:||:Microsoft Paint:|
+|:`[snippingtool]`:||:Snipping Tool:|
+|:`[notepad]`:||:Notepad:|
+|:`[sndvol]`:||:Volume Mixer:|
+|:`[soundrecroder]`:||:Sound Recorder:|
+|:`[wuapp]`:||:Windows Updates:|
+|:`[shutdown]`\*:||:Shutdown or restart computer:|
+|::||::|
+|:`[cmd]`:||:Command Prompt:|
+|:`[powershell]`:||:Windows PowerShell:|
+|:`[control]`:||:Control Panel:|
+|:`[taskmgr]`:||:Task Manager:|
+|:`[msinfo32]`:||:System Information:|
+|:`[winver]`:||:Windows Version Window:|
+|:`[cleanmgr]`:||:Disk Cleanup:|
+|:`[dfrgui]`:||:Disk Cleanup (defragmentation):|
+|:`[mstsc]`:||:Remote Desktop Connection:|
+|::||::|
+|:`[regedit]`:||:Registry Editor:|
+|:`[msconfig]`:||:System Configuration Settings:|
+|:`[dcomcnfg]`:||:Component Services:|
+|:`[sigverif]`:||:File Signature Verification Tool:|
+
+\*: The `[shutdown]` command [url https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/shutdown requires parameters]:
+
+.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!)
+
+### Windows settings
+
+There are also many "shortcuts" to different Windows settings windows. Those include:
+
+.table
+|=Command=||=Setting=|
+|:`[mmsys.cpl]`:||:Sound Properties:|
+|:`[powercfg.cpl]`:||:Power Options:|
+|:`[timedate.cpl]`:||:Time and Date Options:|
+|:`[ncpa.cpl]`:||:Network Connections:|
+|::||::|
+|:`[inetcpl.cpl]`:||:Internet Properties:|
+|:`[compmgmt.msc]`:||:Computer Manager:|
+|:`[devmgmt.msc]`:||:Device Manager:|
+|:`[diskmgmt.msc]`:||:Disk Management:|
+|:`[firewall.cpl]`:||:Windows Firewall:|
+|::||::|
+|:`[sysdm.cpl]`:||:System Properties:|
+|:`[services.msc]`:||:Services:|
+|:`[comexp.msc]`:||:Component Services:|
+|:`[gpedit.msc]`:||:Group Policy Editor:|
+|:`[lusrmgr.msc]`:||:Local Users and Groups:|
+|:`[certmgr.msc]`:||:Certificate Manager:|
+|:`[taskschd.msc]`:||:Task Scheduler:|
+|:`[fsmgmt.msc]`:||:Shared Folders:|
+
+=[Note]=: `[cpl]` stands for *[Control Panel Item]* and `[msc]` stands for *[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.
diff --git a/src/tutorials/windows-run-dialog/index.md b/src/tutorials/windows-run-dialog/index.md
deleted file mode 100644
index 48eba00..0000000
--- a/src/tutorials/windows-run-dialog/index.md
+++ /dev/null
@@ -1,114 +0,0 @@
-# Windows Run dialog
-
-## Contents
-
-1. [Opening the Run dialog](#opening-the-run-dialog)
-2. [Commands](#commands)
- 1. [Folders](#folders)
- 2. [Programs](#programs)
- 3. [Windows settings](#windows-settings)
-3. [For more](#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**.
-
-## Opening the Run dialog
-
-To open the Run dialog, you can either:
-
-*A)* Press `Win + R` key combination
-
-or
-
-*B)* Right click on the Windows menu, and then press `Run`
-
-![](./img/open-run-windows-menu.png)
-
-## Commands
-
-![](./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\`.
-
-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:
-
-|Command|Location|
-|---|---|
-|`%ProgramFiles%`|Program Files Folder|
-|`%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.
-
-### 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`.
-
-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:
-
-|Command|Application|
-|---|---|
-|`calc`|Calculator|
-|`mspaint`|Microsoft Paint|
-|`snippingtool`|Snipping Tool|
-|`notepad`|Notepad|
-|`sndvol`|Volume Mixer|
-|`soundrecroder`|Sound Recorder|
-|`wuapp`|Windows Updates|
-|`shutdown`\*|Shutdown or restart computer|
-|||
-|`cmd`|Command Prompt|
-|`powershell`|Windows PowerShell|
-|`control`|Control Panel|
-|`taskmgr`|Task Manager|
-|`msinfo32`|System Information|
-|`winver`|Windows Version Window|
-|`cleanmgr`|Disk Cleanup|
-|`dfrgui`|Disk Cleanup (defragmentation)|
-|`mstsc`|Remote Desktop Connection|
-|||
-|`regedit`|Registry Editor|
-|`msconfig`|System Configuration Settings|
-|`dcomcnfg`|Component Services|
-|`sigverif`|File Signature Verification Tool|
-
-\* The `shutdown` command [requires parameters](https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/shutdown):
-
-- `/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:
-
-|Command|Setting|
-|---|---|
-|`mmsys.cpl`|Sound Properties|
-|`powercfg.cpl`|Power Options|
-|`timedate.cpl`|Time and Date Options|
-|`ncpa.cpl`|Network Connections|
-|||
-|`inetcpl.cpl`|Internet Properties|
-|`compmgmt.msc`|Computer Manager|
-|`devmgmt.msc`|Device Manager|
-|`diskmgmt.msc`|Disk Management|
-|`firewall.cpl`|Windows Firewall|
-|||
-|`sysdm.cpl`|System Properties|
-|`services.msc`|Services|
-|`comexp.msc`|Component Services|
-|`gpedit.msc`|Group Policy Editor|
-|`lusrmgr.msc`|Local Users and Groups|
-|`certmgr.msc`|Certificate Manager|
-|`taskschd.msc`|Task Scheduler|
-|`fsmgmt.msc`|Shared Folders|
-
-**Note**: `cpl` stands for *Control Panel Item* and `msc` stands for *Microsoft System Configuration*.
-
-## For more
-
-For more commands, check out [windowsruncommands.com](https://windowsruncommands.com/). They have a much bigger list of commands and shortcuts you can use.