%s`,
+ post.Title,
+ markdown.Render(post.Content),
+ )
+ }
+
+ return render(ctx, head, content)
})
s.Run(":8080")
}
-func mustLoadClean(path string) string {
- data := mustLoad(path)
- data = strings.ReplaceAll(data, "\t", "")
- data = strings.ReplaceAll(data, "\n", "")
- return data
-}
-
-func mustLoad(path string) string {
+func load(path string) string {
dataBytes, err := os.ReadFile(path)
if err != nil {
@@ -90,32 +120,9 @@ func mustLoad(path string) string {
return string(dataBytes)
}
-func loadPosts(directory string) map[string]string {
- entries, err := os.ReadDir(directory)
-
- if err != nil {
- panic(err)
- }
-
- posts := map[string]string{}
-
- for _, entry := range entries {
- fileName := entry.Name()
-
- if !strings.HasSuffix(fileName, ".md") {
- continue
- }
-
- baseName := strings.TrimSuffix(fileName, ".md")
- content := mustLoad("posts/" + fileName)
-
- if strings.HasPrefix(content, "---\n") {
- end := strings.Index(content[4:], "---\n") + 4
- content = content[end+4:]
- }
-
- posts[baseName] = markdown.Render(content)
- }
-
- return posts
+func loadClean(path string) string {
+ data := load(path)
+ data = strings.ReplaceAll(data, "\t", "")
+ data = strings.ReplaceAll(data, "\n", "")
+ return data
}
diff --git a/Post.go b/Post.go
new file mode 100644
index 0000000..97e3717
--- /dev/null
+++ b/Post.go
@@ -0,0 +1,78 @@
+package main
+
+import (
+ "os"
+ "strings"
+)
+
+type Post struct {
+ Slug string
+ Content string
+ Title string
+ Tags []string
+ Created string
+ Published bool
+}
+
+func loadPosts(directory string) map[string]*Post {
+ entries, err := os.ReadDir(directory)
+
+ if err != nil {
+ panic(err)
+ }
+
+ posts := map[string]*Post{}
+
+ for _, entry := range entries {
+ fileName := entry.Name()
+
+ if !strings.HasSuffix(fileName, ".md") {
+ continue
+ }
+
+ baseName := strings.TrimSuffix(fileName, ".md")
+ content := load("posts/" + fileName)
+
+ post := &Post{
+ Slug: baseName,
+ }
+
+ if strings.HasPrefix(content, "---\n") {
+ end := strings.Index(content[4:], "---\n") + 4
+ frontmatter := content[4:end]
+ content = content[end+4:]
+
+ parseFrontmatter(frontmatter, func(key, value string) {
+ switch key {
+ case "title":
+ post.Title = value
+ case "tags":
+ post.Tags = strings.Split(value, " ")
+ case "created":
+ post.Created = value
+ case "published":
+ post.Published = value == "true"
+ }
+ })
+ }
+
+ post.Content = content
+ posts[baseName] = post
+ }
+
+ return posts
+}
+
+func parseFrontmatter(frontmatter string, assign func(key string, value string)) {
+ lines := strings.Split(frontmatter, "\n")
+
+ for _, line := range lines {
+ colon := strings.Index(line, ":")
+
+ if colon == -1 {
+ continue
+ }
+
+ assign(line[:colon], strings.TrimSpace(line[colon+1:]))
+ }
+}
diff --git a/posts/about.md b/posts/about.md
new file mode 100644
index 0000000..78e8392
--- /dev/null
+++ b/posts/about.md
@@ -0,0 +1,66 @@
+---
+title: About
+tags: about
+created: 2023-07-09T20:04:03Z
+published: true
+---
+
+Hi ๐
+
+I'm Eduard Urbach, a software developer trying to create high quality [open source](https://git.akyoto.dev/explore/repos) software solutions.
+
+## Philosophy
+
+In an age where technology is meant to simplify our lives, it's ironic how often we find ourselves grappling with bloated software - programs that are swollen with unnecessary features, bogged down by excessive complexity, and burdened with what feels like digital excess baggage.
+Welcome to the era of feature creep, where software developers seem to prioritize quantity over quality, overwhelming users with an avalanche of functionalities that they never asked for nor needed.
+
+As a wise man once said:
+
+> Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.
+
+We shouldn't ask ourselves how much we can add, but how much we can remove, while still maintaining the core task of the software. This leads to much simpler and easy to understand code. I'll quote Terry Davis:
+
+> An idiot admires complexity, a genius admires simplicity.
+
+Making a topic look complex is easy, but making it simple and easy to understand is what truly takes skill. Instead of complex and over-engineered solutions that make us "feel intelligent" just because they're complex we should strive for simplicity.
+
+## Languages
+
+One of the more unique facts about my life is that I spent 8 years in Asia, more specifically Japan and Korea. This helped me broaden the pool of languages I can utilize to communicate and it also gave me an understanding of the subtle differences between Western and Eastern cultures.
+
+Currently I speak:
+
+| | |
+| ----------- | -------------------------------- |
+| ๐ฌ๐ง English | - |
+| ๐ฉ๐ช German | Fuรbodenschleifmaschinenverleih. |
+| ๐ฏ๐ต Japanese | ไปๆนใชใใใญใ |
+| ๐ฐ๐ท Korean | ๋์ ๋ ธ ๊น์น? |
+| ๐ท๐บ Russian | ะดะฐะฒะฐะน ะดะฐะฒะฐะน! |
+
+## Software
+
+I like [Arch Linux](https://archlinux.org) as my operating system for multiple reasons:
+
+- minimal system
+- rolling release
+- pacman is awesome
+- wiki is amazing
+
+My desktop is now based on [Hyprland](https://hyprland.org) after having used [Gnome Shell](https://gnome.org) for the past 10 years.
+
+I use [Neovim](https://neovim.io) as my lightweight editor and [VS Code](https://code.visualstudio.com) only if it has better plugins for the project I'm working on.
+
+I am currently experimenting with [fish](https://fishshell.com) as my daily shell replacing [zsh](https://zsh.org).
+
+## Community
+
+In case you want to contribute to any projects, join [#community:akyoto.dev](https://matrix.to/#/#community:akyoto.dev) with a client you like.
+I recommend [Cinny](https://cinny.in/) because it has a beautiful design and closely resembles Discord.
+
+## Donations
+
+- [Kofi](https://ko-fi.com/akyoto)
+- [LiberaPay](https://liberapay.com/akyoto/donate)
+- [PayPal](https://www.paypal.com/donate/?hosted_button_id=EUBC5TT82APK6)
+- [Stripe](https://donate.stripe.com/28o9Dn2xlehb6Zi8ww)
diff --git a/posts/blender.md b/posts/blender.md
new file mode 100644
index 0000000..cb0d7ab
--- /dev/null
+++ b/posts/blender.md
@@ -0,0 +1,60 @@
+---
+title: Blender
+tags: note troubleshooting
+created: 2024-02-05T14:03:13Z
+published: true
+---
+
+## Basics
+
+| | |
+| ---------------- | --------- |
+| Add | Shift A |
+| Grab | G |
+| Rotate | R |
+| Scale | S |
+| Extrude | E |
+| Inset | I |
+| Bevel | Ctrl B |
+| Loop cut | Ctrl R |
+| Fill | F |
+| Merge | M |
+| Apply | Ctrl A |
+| Join | Ctrl J |
+| Parent | Ctrl P |
+| Grab on X axis | G X |
+| Grab on YZ plane | G Shift X |
+| Slide | G G |
+
+## Vision
+
+| | |
+| -------------- | ------- |
+| Hide | H |
+| Unhide | Alt H |
+| Focus | Num . |
+| Focus region | Shift B |
+| Focus all | Home |
+| Isolate | / |
+| Viewpoint menu | ~ |
+
+## Modes
+
+| | |
+| ----------- | --- |
+| Vertex mode | 1 |
+| Edge mode | 2 |
+| Face mode | 3 |
+
+## Troubleshooting
+
+### How to rename something?
+
+You can rename objects with F2 but in many other places you need to double click the name with your mouse.
+
+### What is neutral_bone?
+
+When you export a rigged model with Blender in glTF format, you will sometimes notice a `neutral_bone` in the exported data.
+This is because some vertices were not assigned a vertex group.
+
+In edit mode, go to `Select > Select all by trait > Ungrouped vertices` to find the problematic vertices and delete them.
diff --git a/posts/contact.md b/posts/contact.md
new file mode 100644
index 0000000..3a3c9d9
--- /dev/null
+++ b/posts/contact.md
@@ -0,0 +1,17 @@
+---
+title: Contact
+tags: about
+created: 2023-07-23T12:43:21Z
+published: true
+---
+
+| | |
+| ------------- | ------------------------------------------------------------ |
+| Name | Eduard Urbach |
+| Occupation | Software Engineer |
+| Business type | Freelancer |
+| E-Mail | admin [at] akyoto.dev |
+| Chat | [@akyoto:akyoto.dev](https://matrix.to/#/@akyoto:akyoto.dev) |
+| Mobile | +49 1520 4296914 |
+| Tax number | DE 362234011 |
+| Address | [n/a](https://dserver.bundestag.de/btd/19/077/1907714.pdf) |
diff --git a/posts/emoji.md b/posts/emoji.md
new file mode 100644
index 0000000..749d23e
--- /dev/null
+++ b/posts/emoji.md
@@ -0,0 +1,1912 @@
+---
+title: Emoji
+tags: note emoji unicode
+created: 2023-07-24T09:13:37Z
+published: true
+---
+
+๐
+๐
+๐
+๐
+๐
+๐
+๐คฃ
+๐
+๐
+๐
+๐ซ
+๐
+๐
+๐
+๐ฅฐ
+๐
+๐คฉ
+๐
+๐
+โบ๏ธ
+๐
+๐
+๐ฅฒ
+๐
+๐
+๐
+๐คช
+๐
+๐ค
+๐ค
+๐คญ
+๐ซข
+๐ซฃ
+๐คซ
+๐ค
+๐ซก
+๐ค
+๐คจ
+๐
+๐
+๐ถ
+๐ซฅ
+๐ถโ๐ซ๏ธ
+๐
+๐
+๐
+๐ฌ
+๐ซจ
+๐ฎโ๐จ
+๐คฅ
+๐
+๐
+๐ช
+๐คค
+๐ด
+๐ท
+๐ค
+๐ค
+๐คข
+๐คฎ
+๐คง
+๐ฅต
+๐ฅถ
+๐ฅด
+๐ต
+๐ตโ๐ซ
+๐คฏ
+๐ค
+๐ฅณ
+๐ฅธ
+๐
+๐ค
+๐ง
+๐
+๐ซค
+๐
+๐
+โน๏ธ
+๐ฎ
+๐ฏ
+๐ฒ
+๐ณ
+๐ฅบ
+๐ฅน
+๐ฆ
+๐ง
+๐จ
+๐ฐ
+๐ฅ
+๐ข
+๐ญ
+๐ฑ
+๐
+๐ฃ
+๐
+๐
+๐ฉ
+๐ซ
+๐ฅฑ
+๐ค
+๐ก
+๐
+๐คฌ
+๐
+๐ฟ
+๐
+โ ๏ธ
+๐ฉ
+๐คก
+๐น
+๐บ
+๐ป
+๐ฝ
+๐พ
+๐ค
+๐บ
+๐ธ
+๐น
+๐ป
+๐ผ
+๐ฝ
+๐
+๐ฟ
+๐พ
+๐
+๐
+๐ค
+๐๏ธ
+โ
+๐
+๐ซฑ
+๐ซฒ
+๐ซณ
+๐ซด
+๐
+๐ค
+๐ค
+โ๏ธ
+๐ค
+๐ซฐ
+๐ค
+๐ค
+๐ค
+๐
+๐
+๐
+๐
+๐
+โ๏ธ
+๐ซต
+๐
+๐
+โ
+๐
+๐ค
+๐ค
+๐
+๐
+๐ซถ
+๐
+๐คฒ
+๐ค
+๐
+โ๏ธ
+๐
+๐คณ
+๐ช
+๐ฆพ
+๐ฆฟ
+๐ฆต
+๐ฆถ
+๐
+๐ฆป
+๐
+๐ง
+๐ซ
+๐ซ
+๐ฆท
+๐ฆด
+๐
+๐๏ธ
+๐
+๐
+๐ซฆ
+๐ถ
+๐ง
+๐ฆ
+๐ง
+๐ง
+๐ฑ
+๐จ
+๐ง
+๐จโ๐ฆฐ
+๐จโ๐ฆฑ
+๐จโ๐ฆณ
+๐จโ๐ฆฒ
+๐ฉ
+๐ฉโ๐ฆฐ
+๐งโ๐ฆฐ
+๐ฉโ๐ฆฑ
+๐งโ๐ฆฑ
+๐ฉโ๐ฆณ
+๐งโ๐ฆณ
+๐ฉโ๐ฆฒ
+๐งโ๐ฆฒ
+๐ฑโโ๏ธ
+๐ฑโโ๏ธ
+๐ง
+๐ด
+๐ต
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐
+๐ โโ๏ธ
+๐ โโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐คฆ
+๐คฆโโ๏ธ
+๐คฆโโ๏ธ
+๐คท
+๐คทโโ๏ธ
+๐คทโโ๏ธ
+๐งโโ๏ธ
+๐จโโ๏ธ
+๐ฉโโ๏ธ
+๐งโ๐
+๐จโ๐
+๐ฉโ๐
+๐งโ๐ซ
+๐จโ๐ซ
+๐ฉโ๐ซ
+๐งโโ๏ธ
+๐จโโ๏ธ
+๐ฉโโ๏ธ
+๐งโ๐พ
+๐จโ๐พ
+๐ฉโ๐พ
+๐งโ๐ณ
+๐จโ๐ณ
+๐ฉโ๐ณ
+๐งโ๐ง
+๐จโ๐ง
+๐ฉโ๐ง
+๐งโ๐ญ
+๐จโ๐ญ
+๐ฉโ๐ญ
+๐งโ๐ผ
+๐จโ๐ผ
+๐ฉโ๐ผ
+๐งโ๐ฌ
+๐จโ๐ฌ
+๐ฉโ๐ฌ
+๐งโ๐ป
+๐จโ๐ป
+๐ฉโ๐ป
+๐งโ๐ค
+๐จโ๐ค
+๐ฉโ๐ค
+๐งโ๐จ
+๐จโ๐จ
+๐ฉโ๐จ
+๐งโโ๏ธ
+๐จโโ๏ธ
+๐ฉโโ๏ธ
+๐งโ๐
+๐จโ๐
+๐ฉโ๐
+๐งโ๐
+๐จโ๐
+๐ฉโ๐
+๐ฎ
+๐ฎโโ๏ธ
+๐ฎโโ๏ธ
+๐ต๏ธ
+๐ต๏ธโโ๏ธ
+๐ต๏ธโโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐ฅท
+๐ท
+๐ทโโ๏ธ
+๐ทโโ๏ธ
+๐ซ
+๐คด
+๐ธ
+๐ณ
+๐ณโโ๏ธ
+๐ณโโ๏ธ
+๐ฒ
+๐ง
+๐คต
+๐คตโโ๏ธ
+๐คตโโ๏ธ
+๐ฐ
+๐ฐโโ๏ธ
+๐ฐโโ๏ธ
+๐คฐ
+๐ซ
+๐ซ
+๐คฑ
+๐ฉโ๐ผ
+๐จโ๐ผ
+๐งโ๐ผ
+๐ผ
+๐
+๐คถ
+๐งโ๐
+๐ฆธ
+๐ฆธโโ๏ธ
+๐ฆธโโ๏ธ
+๐ฆน
+๐ฆนโโ๏ธ
+๐ฆนโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐ถ
+๐ถโโ๏ธ
+๐ถโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐งโ๐ฆฏ
+๐จโ๐ฆฏ
+๐ฉโ๐ฆฏ
+๐งโ๐ฆผ
+๐จโ๐ฆผ
+๐ฉโ๐ฆผ
+๐งโ๐ฆฝ
+๐จโ๐ฆฝ
+๐ฉโ๐ฆฝ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐
+๐บ
+๐ด๏ธ
+๐ฏ
+๐ฏโโ๏ธ
+๐ฏโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ง
+๐งโ๐คโ๐ง
+๐ญ
+๐ซ
+๐ฌ
+๐
+๐ฉโโค๏ธโ๐โ๐จ
+๐จโโค๏ธโ๐โ๐จ
+๐ฉโโค๏ธโ๐โ๐ฉ
+๐
+๐ฉโโค๏ธโ๐จ
+๐จโโค๏ธโ๐จ
+๐ฉโโค๏ธโ๐ฉ
+๐ช
+๐จโ๐ฉโ๐ฆ
+๐จโ๐ฉโ๐ง
+๐จโ๐ฉโ๐งโ๐ฆ
+๐จโ๐ฉโ๐ฆโ๐ฆ
+๐จโ๐ฉโ๐งโ๐ง
+๐จโ๐จโ๐ฆ
+๐จโ๐จโ๐ง
+๐จโ๐จโ๐งโ๐ฆ
+๐จโ๐จโ๐ฆโ๐ฆ
+๐จโ๐จโ๐งโ๐ง
+๐ฉโ๐ฉโ๐ฆ
+๐ฉโ๐ฉโ๐ง
+๐ฉโ๐ฉโ๐งโ๐ฆ
+๐ฉโ๐ฉโ๐ฆโ๐ฆ
+๐ฉโ๐ฉโ๐งโ๐ง
+๐จโ๐ฆ
+๐จโ๐ฆโ๐ฆ
+๐จโ๐ง
+๐จโ๐งโ๐ฆ
+๐จโ๐งโ๐ง
+๐ฉโ๐ฆ
+๐ฉโ๐ฆโ๐ฆ
+๐ฉโ๐ง
+๐ฉโ๐งโ๐ฆ
+๐ฉโ๐งโ๐ง
+๐ฃ๏ธ
+๐ค
+๐ฅ
+๐ซ
+๐ฃ
+๐งณ
+๐
+โ๏ธ
+๐
+๐งต
+๐งถ
+๐
+๐ถ๏ธ
+๐ฅฝ
+๐ฅผ
+๐ฆบ
+๐
+๐
+๐
+๐งฃ
+๐งค
+๐งฅ
+๐งฆ
+๐
+๐
+๐ฅป
+๐ฉฑ
+๐ฉฒ
+๐ฉณ
+๐
+๐
+๐
+๐
+๐
+๐
+๐ฉด
+๐
+๐
+๐ฅพ
+๐ฅฟ
+๐
+๐ก
+๐ฉฐ
+๐ข
+๐
+๐
+๐ฉ
+๐
+๐งข
+๐ช
+โ๏ธ
+๐
+๐
+๐ผ
+๐ฉธ
+
+---
+
+๐
+๐
+๐
+๐ฅ
+๐ซ
+๐ฆ
+๐จ
+๐ต
+๐
+๐ฆ
+๐ฆง
+๐ถ
+๐
+๐ฆฎ
+๐โ๐ฆบ
+๐ฉ
+๐บ
+๐ฆ
+๐ฆ
+๐ฑ
+๐
+๐โโฌ
+๐ฆ
+๐ฏ
+๐
+๐
+๐ด
+๐
+๐ฆ
+๐ฆ
+๐ซ
+๐ฆ
+๐ซ
+๐ฆฌ
+๐ฎ
+๐
+๐
+๐
+๐ท
+๐
+๐
+๐ฝ
+๐
+๐
+๐
+๐ช
+๐ซ
+๐ฆ
+๐ฆ
+๐
+๐ฆฃ
+๐ฆ
+๐ฆ
+๐ญ
+๐
+๐
+๐น
+๐ฐ
+๐
+๐ฟ๏ธ
+๐ฆซ
+๐ฆ
+๐ฆ
+๐ป
+๐ปโโ๏ธ
+๐จ
+๐ผ
+๐ฆฅ
+๐ฆฆ
+๐ฆจ
+๐ฆ
+๐ฆก
+๐พ
+๐ฆ
+๐
+๐
+๐ฃ
+๐ค
+๐ฅ
+๐ฆ
+๐ง
+๐๏ธ
+๐ฆ
+๐ฆ
+๐ฆข
+๐ชฟ
+๐ฆ
+๐ฆค
+๐ชฝ
+๐ชถ
+๐ฆฉ
+๐ฆ
+๐ฆ
+๐ธ
+๐
+๐ข
+๐ฆ
+๐
+๐ฒ
+๐
+๐ฆ
+๐ฆ
+๐ณ
+๐
+๐ฌ
+๐ฆญ
+๐
+๐
+๐ก
+๐ฆ
+๐
+๐ชผ
+๐
+๐ชธ
+๐
+๐ฆ
+๐
+๐
+๐
+๐ชฒ
+๐
+๐ฆ
+๐ชณ
+๐ท๏ธ
+๐ธ๏ธ
+๐ฆ
+๐ฆ
+๐ชฐ
+๐ชฑ
+๐ฆ
+๐
+๐ธ
+๐ฎ
+๐ชท
+๐ต๏ธ
+๐น
+๐ฅ
+๐บ
+๐ชป
+๐ป
+๐ผ
+๐ท
+๐ฑ
+๐ชด
+๐ฒ
+๐ณ
+๐ด
+๐ต
+๐พ
+๐ฟ
+โ๏ธ
+๐
+๐
+๐
+๐
+๐ชน
+๐ชบ
+๐
+๐ฐ
+๐ฆ
+๐ฆ
+๐ฆ
+๐ฆ
+๐
+๐
+๐
+๐
+๐ชจ
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+โ๏ธ
+๐
+๐
+โญ
+๐
+๐
+โ๏ธ
+โ
+โ๏ธ
+๐ค๏ธ
+๐ฅ๏ธ
+๐ฆ๏ธ
+๐ง๏ธ
+๐จ๏ธ
+๐ฉ๏ธ
+๐ช๏ธ
+๐ซ๏ธ
+๐ฌ๏ธ
+๐
+โ๏ธ
+โ
+โก
+โ๏ธ
+โ๏ธ
+โ
+โ๏ธ
+๐ฅ
+๐ง
+๐
+๐
+โจ
+๐
+๐
+๐ซง
+
+---
+
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐ฅญ
+๐
+๐
+๐
+๐
+๐
+๐
+๐ซ
+๐ฅ
+๐
+๐ซ
+๐ฅฅ
+๐ฅ
+๐
+๐ฅ
+๐ฅ
+๐ฝ
+๐ถ๏ธ
+๐ซ
+๐ฅ
+๐ฅฌ
+๐ฅฆ
+๐ซ
+๐ง
+๐ง
+๐ซ
+๐
+๐ฅ
+๐ซ
+๐ฐ
+๐
+๐ฅ
+๐ฅ
+๐ซ
+๐ฅจ
+๐ฅฏ
+๐ฅ
+๐ง
+๐ง
+๐
+๐
+๐ฅฉ
+๐ฅ
+๐
+๐
+๐
+๐ญ
+๐ฅช
+๐ฎ
+๐ฏ
+๐ซ
+๐ฅ
+๐ง
+๐ฅ
+๐ณ
+๐ฅ
+๐ฒ
+๐ซ
+๐ฅฃ
+๐ฅ
+๐ฟ
+๐ง
+๐ง
+๐ฅซ
+๐ฑ
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐ข
+๐ฃ
+๐ค
+๐ฅ
+๐ฅฎ
+๐ก
+๐ฅ
+๐ฅ
+๐ฅก
+๐ฆช
+๐ฆ
+๐ง
+๐จ
+๐ฉ
+๐ช
+๐
+๐ฐ
+๐ง
+๐ฅง
+๐ซ
+๐ฌ
+๐ญ
+๐ฎ
+๐ฏ
+๐ผ
+๐ฅ
+โ
+๐ซ
+๐ต
+๐ถ
+๐พ
+๐ท
+๐ธ
+๐น
+๐บ
+๐ป
+๐ฅ
+๐ฅ
+๐ซ
+๐ฅค
+๐ง
+๐ง
+๐ง
+๐ง
+๐ฅข
+๐ฝ๏ธ
+๐ด
+๐ฅ
+๐ซ
+
+---
+
+๐ด๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐คบ
+๐
+โท๏ธ
+๐
+๐๏ธ
+๐๏ธโโ๏ธ
+๐๏ธโโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+๐ฃ
+๐ฃโโ๏ธ
+๐ฃโโ๏ธ
+๐
+๐โโ๏ธ
+๐โโ๏ธ
+โน๏ธ
+โน๏ธโโ๏ธ
+โน๏ธโโ๏ธ
+๐๏ธ
+๐๏ธโโ๏ธ
+๐๏ธโโ๏ธ
+๐ด
+๐ดโโ๏ธ
+๐ดโโ๏ธ
+๐ต
+๐ตโโ๏ธ
+๐ตโโ๏ธ
+๐คธ
+๐คธโโ๏ธ
+๐คธโโ๏ธ
+๐คผ
+๐คผโโ๏ธ
+๐คผโโ๏ธ
+๐คฝ
+๐คฝโโ๏ธ
+๐คฝโโ๏ธ
+๐คพ
+๐คพโโ๏ธ
+๐คพโโ๏ธ
+๐คน
+๐คนโโ๏ธ
+๐คนโโ๏ธ
+๐ง
+๐งโโ๏ธ
+๐งโโ๏ธ
+๐ช
+๐น
+๐ผ
+๐ถ
+๐๏ธ
+๐๏ธ
+๐ซ
+๐๏ธ
+๐
+๐
+๐ฅ
+๐ฅ
+๐ฅ
+โฝ
+โพ
+๐ฅ
+๐
+๐
+๐
+๐
+๐พ
+๐ฅ
+๐ณ
+๐
+๐
+๐
+๐ฅ
+๐
+๐ธ
+๐ฅ
+๐ฅ
+๐ฅ
+โณ
+โธ๏ธ
+๐ฃ
+๐ฝ
+๐ฟ
+๐ท
+๐ฅ
+๐ฏ
+๐ฑ
+๐ฎ
+๐ฐ
+๐ฒ
+๐งฉ
+๐ชฉ
+โ๏ธ
+๐ญ
+๐จ
+๐งต
+๐งถ
+๐ผ
+๐ค
+๐ง
+๐ท
+๐ช
+๐ธ
+๐น
+๐บ
+๐ป
+๐ช
+๐ฅ
+๐ช
+๐ช
+๐ฌ
+๐น
+
+---
+
+๐ฃ
+๐พ
+๐๏ธ
+โฐ๏ธ
+๐
+๐ป
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐
+๐๏ธ
+๐๏ธ
+๐
+๐ก
+๐ข
+๐ฃ
+๐ค
+๐ฅ
+๐ฆ
+๐จ
+๐ฉ
+๐ช
+๐ซ
+๐ฌ
+๐ญ
+๐ฏ
+๐ฐ
+๐
+๐ผ
+๐ฝ
+โช
+๐
+๐
+๐
+โฉ๏ธ
+๐
+โฒ
+โบ
+๐
+๐
+๐๏ธ
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐ก
+๐ข
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐ป
+๐
+๐
+๐
+๐๏ธ
+๐๏ธ
+๐ต
+๐บ
+๐ฒ
+๐ด
+๐
+๐ฃ๏ธ
+๐ค๏ธ
+โฝ
+๐
+๐จ
+๐ฅ
+๐ฆ
+๐ง
+โ
+๐
+โต
+๐ค
+๐ณ๏ธ
+โด๏ธ
+๐ฅ๏ธ
+๐ข
+โ๏ธ
+๐ฉ๏ธ
+๐ซ
+๐ฌ
+๐ช
+๐บ
+๐
+๐
+๐
+๐ก
+๐ฐ๏ธ
+๐
+๐ธ
+๐ช
+๐
+๐
+โฑ๏ธ
+๐
+๐
+๐
+๐ด
+๐ต
+๐ถ
+๐ท
+๐ฟ
+๐
+๐
+๐
+๐
+
+---
+
+๐
+๐ณ๏ธ
+๐ฃ
+๐
+๐
+๐ช
+๐บ
+๐บ๏ธ
+๐งญ
+๐งฑ
+๐
+๐ฆฝ
+๐ฆผ
+๐ข๏ธ
+๐๏ธ
+๐งณ
+โ
+โณ
+โ
+โฐ
+โฑ๏ธ
+โฒ๏ธ
+๐ฐ๏ธ
+๐ก๏ธ
+โฑ๏ธ
+๐งจ
+๐
+๐
+๐
+๐
+๐
+๐
+๐งง
+๐
+๐
+๐คฟ
+๐ช
+๐ช
+๐ฎ
+๐ช
+๐งฟ
+๐ชฌ
+๐น๏ธ
+๐งธ
+๐ช
+๐ช
+๐ผ๏ธ
+๐งต
+๐ชก
+๐งถ
+๐ชข
+๐ชญ
+๐๏ธ
+๐ฟ
+๐ชฎ
+๐
+๐ฏ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐ป
+๐ช
+๐ฑ
+๐ฒ
+โ๏ธ
+๐
+๐
+๐
+๐
+๐
+๐ป
+๐ฅ๏ธ
+๐จ๏ธ
+โจ๏ธ
+๐ฑ๏ธ
+๐ฒ๏ธ
+๐ฝ
+๐พ
+๐ฟ
+๐
+๐งฎ
+๐ฅ
+๐๏ธ
+๐ฝ๏ธ
+๐บ
+๐ท
+๐ธ
+๐น
+๐ผ
+๐
+๐
+๐ฏ๏ธ
+๐ก
+๐ฆ
+๐ฎ
+๐ช
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐ฐ
+๐๏ธ
+๐
+๐
+๐ท๏ธ
+๐ฐ
+๐ช
+๐ด
+๐ต
+๐ถ
+๐ท
+๐ธ
+๐ณ
+๐งพ
+โ๏ธ
+๐ง
+๐จ
+๐ฉ
+๐ค
+๐ฅ
+๐ฆ
+๐ซ
+๐ช
+๐ฌ
+๐ญ
+๐ฎ
+๐ณ๏ธ
+โ๏ธ
+โ๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐
+๐
+๐
+๐๏ธ
+๐
+๐
+๐๏ธ
+๐๏ธ
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐๏ธ
+๐
+๐
+โ๏ธ
+๐๏ธ
+๐๏ธ
+๐๏ธ
+๐
+๐
+๐
+๐
+๐
+๐๏ธ
+๐จ
+๐ช
+โ๏ธ
+โ๏ธ
+๐ ๏ธ
+๐ก๏ธ
+โ๏ธ
+๐ซ
+๐ช
+๐ก๏ธ
+๐ช
+๐ง
+๐ช
+๐ฉ
+โ๏ธ
+๐๏ธ
+โ๏ธ
+๐ฆฏ
+๐
+โ๏ธ
+๐ช
+๐งฐ
+๐งฒ
+๐ช
+โ๏ธ
+๐งช
+๐งซ
+๐งฌ
+๐ฌ
+๐ญ
+๐ก
+๐
+๐ฉธ
+๐
+๐ฉน
+๐ฉผ
+๐ฉบ
+๐ช
+๐ช
+๐ช
+๐๏ธ
+๐๏ธ
+๐ช
+๐ฝ
+๐ช
+๐ฟ
+๐
+๐ชค
+๐ช
+๐งด
+๐งท
+๐งน
+๐งบ
+๐งป
+๐ชฃ
+๐งผ
+๐ชฅ
+๐งฝ
+๐งฏ
+๐
+๐ฌ
+โฐ๏ธ
+๐ชฆ
+โฑ๏ธ
+๐ฟ
+๐ชง
+๐ชช
+๐ฐ
+
+---
+
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+โฃ๏ธ
+๐
+โค๏ธโ๐ฅ
+โค๏ธโ๐ฉน
+โค๏ธ
+๐ฉท
+๐งก
+๐
+๐
+๐
+๐ฉต
+๐
+๐ค
+๐ค
+๐ฉถ
+๐ค
+๐ฏ
+๐ข
+๐ฌ
+๐๏ธโ๐จ๏ธ
+๐จ๏ธ
+๐ฏ๏ธ
+๐ญ
+๐ค
+๐ฎ
+โจ๏ธ
+๐
+๐
+๐
+๐ง
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐ก
+๐
+๐ข
+๐
+๐ฃ
+๐
+๐ค
+๐
+๐ฅ
+๐
+๐ฆ
+๐
+โ ๏ธ
+โฅ๏ธ
+โฆ๏ธ
+โฃ๏ธ
+๐
+๐
+๐ด
+๐
+๐
+๐
+๐
+๐ข
+๐ฃ
+๐ฏ
+๐
+๐
+๐ต
+๐ถ
+๐น
+๐
+๐ง
+๐ฎ
+๐ฐ
+โฟ
+๐น
+๐บ
+๐ป
+๐ผ
+๐พ
+โ ๏ธ
+๐ธ
+โ
+๐ซ
+๐ณ
+๐ญ
+๐ฏ
+๐ฑ
+๐ท
+๐ต
+๐
+โข๏ธ
+โฃ๏ธ
+โฌ๏ธ
+โ๏ธ
+โก๏ธ
+โ๏ธ
+โฌ๏ธ
+โ๏ธ
+โฌ ๏ธ
+โ๏ธ
+โ๏ธ
+โ๏ธ
+โฉ๏ธ
+โช๏ธ
+โคด๏ธ
+โคต๏ธ
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+๐
+โ๏ธ
+๐๏ธ
+โก๏ธ
+โธ๏ธ
+โฏ๏ธ
+โ๏ธ
+โฆ๏ธ
+โช๏ธ
+๐ชฏ
+โฎ๏ธ
+๐
+๐ฏ
+โ
+โ
+โ
+โ
+โ
+โ
+โ
+โ
+โ
+โ
+โ
+โ
+โ
+๐
+๐
+๐
+โถ๏ธ
+โฉ
+โญ๏ธ
+โฏ๏ธ
+โ๏ธ
+โช
+โฎ๏ธ
+๐ผ
+โซ
+๐ฝ
+โฌ
+โธ๏ธ
+โน๏ธ
+โบ๏ธ
+โ๏ธ
+๐ฆ
+๐
+๐
+๐
+๐ถ
+๐ณ
+๐ด
+โ๏ธ
+โ๏ธ
+โ๏ธ
+โ
+โ
+โ
+๐ฐ
+โพ๏ธ
+โผ๏ธ
+โ๏ธ
+โ
+โ
+โ
+โ
+ใฐ๏ธ
+๐ฑ
+๐ฒ
+โ๏ธ
+โป๏ธ
+โ๏ธ
+๐ฑ
+๐
+๐ฐ
+โญ
+โ
+โ๏ธ
+โ๏ธ
+โ
+โ
+โฐ
+โฟ
+ใฝ๏ธ
+โณ๏ธ
+โด๏ธ
+โ๏ธ
+ยฉ๏ธ
+ยฎ๏ธ
+โข๏ธ
+#๏ธโฃ
+\*๏ธโฃ
+0๏ธโฃ
+1๏ธโฃ
+2๏ธโฃ
+3๏ธโฃ
+4๏ธโฃ
+5๏ธโฃ
+6๏ธโฃ
+7๏ธโฃ
+8๏ธโฃ
+9๏ธโฃ
+๐
+๐
+๐ก
+๐ข
+๐ฃ
+๐ค
+๐ ฐ๏ธ
+๐
+๐ ฑ๏ธ
+๐
+๐
+๐
+โน๏ธ
+๐
+โ๏ธ
+๐
+๐
+๐ พ๏ธ
+๐
+๐ ฟ๏ธ
+๐
+๐
+๐
+๐
+๐๏ธ
+๐ท๏ธ
+๐ถ
+๐ฏ
+๐
+๐น
+๐
+๐ฒ
+๐
+๐ธ
+๐ด
+๐ณ
+ใ๏ธ
+ใ๏ธ
+๐บ
+๐ต
+๐ด
+๐
+๐ก
+๐ข
+๐ต
+๐ฃ
+๐ค
+โซ
+โช
+๐ฅ
+๐ง
+๐จ
+๐ฉ
+๐ฆ
+๐ช
+๐ซ
+โฌ
+โฌ
+โผ๏ธ
+โป๏ธ
+โพ
+โฝ
+โช๏ธ
+โซ๏ธ
+๐ถ
+๐ท
+๐ธ
+๐น
+๐บ
+๐ป
+๐
+๐
+๐ณ
+๐ฒ
+
+---
+
+๐
+๐ฉ
+๐
+๐ด
+๐ณ๏ธ
+๐ณ๏ธโ๐
+๐ณ๏ธโโง๏ธ
+๐ดโโ ๏ธ
+๐ฆ๐จ
+๐ฆ๐ฉ
+๐ฆ๐ช
+๐ฆ๐ซ
+๐ฆ๐ฌ
+๐ฆ๐ฎ
+๐ฆ๐ฑ
+๐ฆ๐ฒ
+๐ฆ๐ด
+๐ฆ๐ถ
+๐ฆ๐ท
+๐ฆ๐ธ
+๐ฆ๐น
+๐ฆ๐บ
+๐ฆ๐ผ
+๐ฆ๐ฝ
+๐ฆ๐ฟ
+๐ง๐ฆ
+๐ง๐ง
+๐ง๐ฉ
+๐ง๐ช
+๐ง๐ซ
+๐ง๐ฌ
+๐ง๐ญ
+๐ง๐ฎ
+๐ง๐ฏ
+๐ง๐ฑ
+๐ง๐ฒ
+๐ง๐ณ
+๐ง๐ด
+๐ง๐ถ
+๐ง๐ท
+๐ง๐ธ
+๐ง๐น
+๐ง๐ป
+๐ง๐ผ
+๐ง๐พ
+๐ง๐ฟ
+๐จ๐ฆ
+๐จ๐จ
+๐จ๐ฉ
+๐จ๐ซ
+๐จ๐ฌ
+๐จ๐ญ
+๐จ๐ฎ
+๐จ๐ฐ
+๐จ๐ฑ
+๐จ๐ฒ
+๐จ๐ณ
+๐จ๐ด
+๐จ๐ต
+๐จ๐ท
+๐จ๐บ
+๐จ๐ป
+๐จ๐ผ
+๐จ๐ฝ
+๐จ๐พ
+๐จ๐ฟ
+๐ฉ๐ช
+๐ฉ๐ฌ
+๐ฉ๐ฏ
+๐ฉ๐ฐ
+๐ฉ๐ฒ
+๐ฉ๐ด
+๐ฉ๐ฟ
+๐ช๐ฆ
+๐ช๐จ
+๐ช๐ช
+๐ช๐ฌ
+๐ช๐ญ
+๐ช๐ท
+๐ช๐ธ
+๐ช๐น
+๐ช๐บ
+๐ซ๐ฎ
+๐ซ๐ฏ
+๐ซ๐ฐ
+๐ซ๐ฒ
+๐ซ๐ด
+๐ซ๐ท
+๐ฌ๐ฆ
+๐ฌ๐ง
+๐ฌ๐ฉ
+๐ฌ๐ช
+๐ฌ๐ซ
+๐ฌ๐ฌ
+๐ฌ๐ญ
+๐ฌ๐ฎ
+๐ฌ๐ฑ
+๐ฌ๐ฒ
+๐ฌ๐ณ
+๐ฌ๐ต
+๐ฌ๐ถ
+๐ฌ๐ท
+๐ฌ๐ธ
+๐ฌ๐น
+๐ฌ๐บ
+๐ฌ๐ผ
+๐ฌ๐พ
+๐ญ๐ฐ
+๐ญ๐ฒ
+๐ญ๐ณ
+๐ญ๐ท
+๐ญ๐น
+๐ญ๐บ
+๐ฎ๐จ
+๐ฎ๐ฉ
+๐ฎ๐ช
+๐ฎ๐ฑ
+๐ฎ๐ฒ
+๐ฎ๐ณ
+๐ฎ๐ด
+๐ฎ๐ถ
+๐ฎ๐ท
+๐ฎ๐ธ
+๐ฎ๐น
+๐ฏ๐ช
+๐ฏ๐ฒ
+๐ฏ๐ด
+๐ฏ๐ต
+๐ฐ๐ช
+๐ฐ๐ฌ
+๐ฐ๐ญ
+๐ฐ๐ฎ
+๐ฐ๐ฒ
+๐ฐ๐ณ
+๐ฐ๐ต
+๐ฐ๐ท
+๐ฐ๐ผ
+๐ฐ๐พ
+๐ฐ๐ฟ
+๐ฑ๐ฆ
+๐ฑ๐ง
+๐ฑ๐จ
+๐ฑ๐ฎ
+๐ฑ๐ฐ
+๐ฑ๐ท
+๐ฑ๐ธ
+๐ฑ๐น
+๐ฑ๐บ
+๐ฑ๐ป
+๐ฑ๐พ
+๐ฒ๐ฆ
+๐ฒ๐จ
+๐ฒ๐ฉ
+๐ฒ๐ช
+๐ฒ๐ซ
+๐ฒ๐ฌ
+๐ฒ๐ญ
+๐ฒ๐ฐ
+๐ฒ๐ฑ
+๐ฒ๐ฒ
+๐ฒ๐ณ
+๐ฒ๐ด
+๐ฒ๐ต
+๐ฒ๐ถ
+๐ฒ๐ท
+๐ฒ๐ธ
+๐ฒ๐น
+๐ฒ๐บ
+๐ฒ๐ป
+๐ฒ๐ผ
+๐ฒ๐ฝ
+๐ฒ๐พ
+๐ฒ๐ฟ
+๐ณ๐ฆ
+๐ณ๐จ
+๐ณ๐ช
+๐ณ๐ซ
+๐ณ๐ฌ
+๐ณ๐ฎ
+๐ณ๐ฑ
+๐ณ๐ด
+๐ณ๐ต
+๐ณ๐ท
+๐ณ๐บ
+๐ณ๐ฟ
+๐ด๐ฒ
+๐ต๐ฆ
+๐ต๐ช
+๐ต๐ซ
+๐ต๐ฌ
+๐ต๐ญ
+๐ต๐ฐ
+๐ต๐ฑ
+๐ต๐ฒ
+๐ต๐ณ
+๐ต๐ท
+๐ต๐ธ
+๐ต๐น
+๐ต๐ผ
+๐ต๐พ
+๐ถ๐ฆ
+๐ท๐ช
+๐ท๐ด
+๐ท๐ธ
+๐ท๐บ
+๐ท๐ผ
+๐ธ๐ฆ
+๐ธ๐ง
+๐ธ๐จ
+๐ธ๐ฉ
+๐ธ๐ช
+๐ธ๐ฌ
+๐ธ๐ญ
+๐ธ๐ฎ
+๐ธ๐ฏ
+๐ธ๐ฐ
+๐ธ๐ฑ
+๐ธ๐ฒ
+๐ธ๐ณ
+๐ธ๐ด
+๐ธ๐ท
+๐ธ๐ธ
+๐ธ๐น
+๐ธ๐ป
+๐ธ๐ฝ
+๐ธ๐พ
+๐ธ๐ฟ
+๐น๐ฆ
+๐น๐จ
+๐น๐ฉ
+๐น๐ซ
+๐น๐ฌ
+๐น๐ญ
+๐น๐ฏ
+๐น๐ฐ
+๐น๐ฑ
+๐น๐ฒ
+๐น๐ณ
+๐น๐ด
+๐น๐ท
+๐น๐น
+๐น๐ป
+๐น๐ผ
+๐น๐ฟ
+๐บ๐ฆ
+๐บ๐ฌ
+๐บ๐ฒ
+๐บ๐ณ
+๐บ๐ธ
+๐บ๐พ
+๐บ๐ฟ
+๐ป๐ฆ
+๐ป๐จ
+๐ป๐ช
+๐ป๐ฌ
+๐ป๐ฎ
+๐ป๐ณ
+๐ป๐บ
+๐ผ๐ซ
+๐ผ๐ธ
+๐ฝ๐ฐ
+๐พ๐ช
+๐พ๐น
+๐ฟ๐ฆ
+๐ฟ๐ฒ
+๐ฟ๐ผ
+๐ด๓ ง๓ ข๓ ฅ๓ ฎ๓ ง๓ ฟ
+๐ด๓ ง๓ ข๓ ณ๓ ฃ๓ ด๓ ฟ
+๐ด๓ ง๓ ข๓ ท๓ ฌ๓ ณ๓ ฟ
diff --git a/posts/environment-variables.md b/posts/environment-variables.md
new file mode 100644
index 0000000..444d41e
--- /dev/null
+++ b/posts/environment-variables.md
@@ -0,0 +1,62 @@
+---
+title: Environment Variables
+tags: article software linux system configuration
+created: 2024-03-07T10:09:08Z
+published: true
+---
+
+Recently, I had to configure some user specific environment variables for my Linux installation.
+The problem was that I needed those variables to work in all of my shells and in every desktop environment.
+Since `.pam_environment` is deprecated and `.profile` isn't sourced by every shell, I needed another solution that works globally.
+
+## User variables
+
+One solution is to use `systemd` for this task.
+You can configure user environment variables in the `~/.config/environment.d` directory.
+Multiple files can be added and all of them will be processed on session start:
+
+```
+.
+โโโ 10-xdg.conf
+โโโ 20-dirs.conf
+โโโ 30-general.conf
+โโโ 40-apps.conf
+```
+
+The format inside these files is very simple:
+
+```ini
+KEY=value
+KEY=value
+KEY=value
+```
+
+They support variable expansion so it's possible to use things like `$HOME` in the value text.
+You can take a look at my [environment.d](https://git.akyoto.dev/sys/home/src/branch/main/.config/environment.d) if you need some examples.
+
+GDM and KDE Plasma will automatically source these variables on session start.
+If you don't use these or you don't want to rely on them, you need to manually load the variables in your shell config files.
+
+### bash / zsh
+
+```bash
+export $(/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)
+```
+
+### fish
+
+```bash
+export (/usr/lib/systemd/user-environment-generators/30-systemd-environment-d-generator)
+```
+
+Even if you use a graphical environment it makes sense to add these to your shell startup because it allows you to see the changes made to your environment immediately. In case you're worried about execution time, it adds about 3 ms to the shell startup on my machine and is well worth the price.
+
+## System variables
+
+Hardware and system specific variables that do not need to live in a version controlled repository can be set in `/etc/environment`. For example, on a system with an Nvidia GPU:
+
+```ini
+GBM_BACKEND=nvidia-drm
+LIBVA_DRIVER_NAME=nvidia
+__GLX_VENDOR_LIBRARY_NAME=nvidia
+```
diff --git a/posts/file-structure.md b/posts/file-structure.md
new file mode 100644
index 0000000..db9e470
--- /dev/null
+++ b/posts/file-structure.md
@@ -0,0 +1,64 @@
+---
+title: File Structure
+tags: article software
+created: 2023-07-28T09:21:24Z
+published: true
+---
+
+There are two widely used types of source code organization and I will explain why one of these should be avoided.
+As an example, let's take a look at the model-view-controller pattern:
+
+## "by type"
+
+An inexperienced programmer will often create this file structure when asked to create an MVC project:
+
+```text
+.
+โโโ controllers
+โย ย โโโ Post.controller
+โย ย โโโ User.controller
+โโโ models
+โย ย โโโ Post.model
+โย ย โโโ User.model
+โโโ views
+ โโโ Post.view
+ โโโ User.view
+```
+
+We call this "by type" organization and it should be avoided like the devil.
+
+First of all, it violates the software principle that related things should always stay close to each other.
+It becomes very hard to find all the files related to a component.
+Nowadays fuzzy finders can help offset this problem, but it's nonetheless a problem that could have been avoided in the first place instead of requiring extra tooling.
+
+Secondly, this structure makes deletion non-trivial. If a component is no longer needed, then you need to delete it from your repository.
+This should be a trivial task, ideally removing one directory and you're done. If your component, however, happens to be spread out over 15 different folders, then the deletion process is very complex.
+
+## "by feature"
+
+There is a very simple solution to all of these problems and it's called "by feature" organization:
+
+```text
+.
+โโโ Post
+โย ย โโโ Post.controller
+โย ย โโโ Post.model
+โย ย โโโ Post.view
+โโโ User
+ โโโ User.controller
+ โโโ User.model
+ โโโ User.view
+```
+
+With this file structure:
+
+- All related code is closely grouped together
+- Deleting a component is very easy
+
+Depending on the style regulations, you might encounter the plural forms `Posts` and `Users`, but it's the same principle. Personally, I prefer singular names because plurals aren't consistent. If your code uses type names via reflection to build the paths, you're better off with singular names.
+
+## Conclusion
+
+- Don't organize files by their file type
+- Organize files by feature
+- Make deletion simple
diff --git a/posts/firefox.md b/posts/firefox.md
new file mode 100644
index 0000000..9e1a1a2
--- /dev/null
+++ b/posts/firefox.md
@@ -0,0 +1,19 @@
+---
+title: Firefox
+tags: note
+created: 2024-03-07T18:31:12Z
+published: false
+---
+
+| | |
+| ----------- | -------------- |
+| Back | Alt Left |
+| Forward | Alt Right |
+| Tab left | Ctrl Shift Tab |
+| Tab right | Ctrl Tab |
+| Address bar | Ctrl L |
+| Web search | Ctrl K |
+| Quick find | / |
+| Zoom in | Ctrl + |
+| Zoom out | Ctrl - |
+| Zoom reset | Ctrl 0 |
diff --git a/posts/git.md b/posts/git.md
new file mode 100644
index 0000000..264a5e3
--- /dev/null
+++ b/posts/git.md
@@ -0,0 +1,76 @@
+---
+title: Git
+tags: note software git
+created: 2023-07-01T08:52:17Z
+published: true
+---
+
+## git
+
+### Delete branch
+
+```bash
+git branch -d $branch
+```
+
+### Delete remote branch
+
+```bash
+git push origin --delete $branch
+```
+
+### Push branch to remote
+
+```bash
+git push -u origin $branch
+```
+
+### Rebase preserving dates
+
+```bash
+git rebase -i --root --committer-date-is-author-date
+```
+
+### Rename branch
+
+```bash
+git branch -m $old $new
+```
+
+### Sign last commit
+
+```bash
+git commit --amend --no-edit -S
+```
+
+### Show log
+
+```bash
+git log --oneline
+```
+
+### Show remote
+
+```bash
+git remote -v
+```
+
+### Undo `git add`
+
+```bash
+git reset $file
+```
+
+## git lfs
+
+### Show files
+
+```bash
+git lfs ls-files
+```
+
+### Show files in the entire history
+
+```bash
+git lfs ls-files --all
+```
diff --git a/posts/hardware.md b/posts/hardware.md
new file mode 100644
index 0000000..7b088b2
--- /dev/null
+++ b/posts/hardware.md
@@ -0,0 +1,17 @@
+---
+title: Hardware
+tags: about
+created: 2023-06-28T08:20:41Z
+published: true
+---
+
+The hardware I'm currently using:
+
+- MSI Z370-A PRO
+- Intel Core i7-8700
+- Nvidia GeForce GTX 1070
+- 32 GB T-Force DDR4 (4 x 8GB)
+- 512 GB E5012 M.2 NVMe 2280
+- Corsair K70 Rapidfire
+- Logitech G Pro Superlight
+- BenQ MOBIUZ EX240
diff --git a/posts/license.md b/posts/license.md
new file mode 100644
index 0000000..9e00e88
--- /dev/null
+++ b/posts/license.md
@@ -0,0 +1,26 @@
+---
+title: License
+tags: legal license
+created: 2023-08-31T13:46:52Z
+published: true
+---
+
+Copyright ยฉ Eduard Urbach
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/posts/linux.md b/posts/linux.md
new file mode 100644
index 0000000..1de4564
--- /dev/null
+++ b/posts/linux.md
@@ -0,0 +1,192 @@
+---
+title: Linux
+tags: note software linux
+created: 2023-07-01T08:51:23Z
+published: true
+---
+
+The following commands have been tested with Arch Linux.
+They might work in other distributions with a few modifications.
+The commands assume standard user permissions and will include `sudo` if root permissions are required.
+
+## lsof
+
+### List open TCP connections
+
+```bash
+sudo lsof -PniTCP
+```
+
+### List open UDP connections
+
+```bash
+sudo lsof -PniUDP
+```
+
+## nu
+
+### Sort files and directories by size
+
+```bash
+ls -ad | sort-by size | reverse
+```
+
+### Filter processes with a high cpu usage
+
+```bash
+ps | where cpu > 0 | sort-by cpu | reverse
+```
+
+### Filter processes with a high memory usage
+
+```bash
+ps | where mem > 30MB | sort-by mem | reverse
+```
+
+## openssl
+
+### Show certificate info
+
+```bash
+openssl x509 -text -noout -in $file
+```
+
+## pacman
+
+### Install a package
+
+```bash
+sudo pacman -S $package
+```
+
+### Uninstall a package and its dependencies
+
+```bash
+sudo pacman -Rs $package
+```
+
+### List installed packages
+
+```bash
+pacman -Q
+```
+
+### List orphaned packages
+
+```bash
+pacman -Qtdq
+```
+
+### Clear cache
+
+```bash
+sudo pacman -Sc
+```
+
+## rg
+
+### Search recursively
+
+```bash
+rg $text
+```
+
+### Search single file
+
+```bash
+rg $text $file
+```
+
+### Disable all filters
+
+```bash
+rg -uuu $text
+```
+
+## rsync
+
+### Sync directory with a server
+
+```bash
+rsync -avz $source $destination
+```
+
+### Preview changes
+
+```bash
+rsync -avz $source $destination --dry-run
+```
+
+## systemd
+
+### List all running services
+
+```bash
+systemctl --type=service --state=running
+```
+
+### List all enabled services
+
+```bash
+systemctl list-unit-files --type=service --state=enabled
+```
+
+### Follow log messages
+
+```bash
+journalctl -f
+```
+
+### Follow log messages for a specific unit
+
+```bash
+journalctl -f -u $unit
+```
+
+### Show boot time analysis
+
+```bash
+systemd-analyze blame
+```
+
+### Reboot into BIOS
+
+```bash
+systemctl reboot --firmware-setup
+```
+
+## tar
+
+### Compress ze vucking files
+
+```bash
+tar czvf $name.tar.gz .
+```
+
+### Extract ze vucking files
+
+```bash
+tar xzvf $name.tar.gz
+```
+
+## users
+
+### Add a user
+
+```bash
+useradd -m $user
+```
+
+### Add a group to a user
+
+```bash
+usermod -aG $group $user
+```
+
+## wmctrl
+
+### Close all windows
+
+```bash
+wmctrl -l | awk '{print $1}' | xargs -rn1 wmctrl -ic
+```
diff --git a/posts/neovim.md b/posts/neovim.md
new file mode 100644
index 0000000..648fed1
--- /dev/null
+++ b/posts/neovim.md
@@ -0,0 +1,59 @@
+---
+title: Neovim
+tags: note software editor neovim
+created: 2023-07-01T10:23:16Z
+published: true
+---
+
+## Basics
+
+| | |
+| ------------------------------- | -------- |
+| Normal | `Esc` |
+| Insert | `i` |
+| Append after cursor | `a` |
+| Append at end of line | `A` |
+| Append line (after) | `o` |
+| Append line (before) | `O` |
+| Move to next word | `w` |
+| Move to beginning of word | `b` |
+| Move to end of word | `e` |
+| Move forward to character | `f` |
+| Move backward to character | `F` |
+| Move to start of file | `gg` |
+| Move to end of file | `G` |
+| Move to start of line | `0` |
+| Move to end of line | `$` |
+| Move to first character of line | `^` |
+| Select | `v` |
+| Select line | `V` |
+| Copy | `y` |
+| Copy line | `yy` |
+| Paste (before cursor) | `P` |
+| Paste (after cursor) | `p` |
+| Delete | `d` |
+| Delete until end of line | `D` |
+| Delete line | `dd` |
+| Repeat last command | `.` |
+| Undo | `u` |
+| Redo | `Ctrl r` |
+| Search | `/` |
+
+## Commands
+
+| | |
+| --------- | ------------- |
+| Command | `:` |
+| Edit file | `:e file.txt` |
+| Replace | `:%s/a/b` |
+
+## Combinations
+
+| | |
+| --------------------------------------- | ------ |
+| Change word under cursor | `ciw` |
+| Delete word and whitespace under cursor | `daw` |
+| Rewrite line | `^Da` |
+| Select word under cursor | `viw` |
+| Select next block | `va{` |
+| Select everything | `ggVG` |
diff --git a/posts/network-update-rate.md b/posts/network-update-rate.md
new file mode 100644
index 0000000..edc9dbc
--- /dev/null
+++ b/posts/network-update-rate.md
@@ -0,0 +1,35 @@
+---
+title: Network Update Rate
+tags: article gamedev network multiplayer
+created: 2024-02-21T22:17:01Z
+published: true
+---
+
+In game development, the send rate of server and client updates dictates how good the prediction of the real player position is. However, not all increases in send rate give you equal returns for the increased CPU and bandwidth costs you're paying.
+
+I've recorded and averaged the prediction error over multiple runs on some common send rates to see how much the prediction improves. The test involves a character running in circles which tests a range of parameters like extrapolation, interpolation and update rate.
+
+## Data
+
+| Update rate | Error distance |
+| ----------------------------------- | -------------- |
+| 1 Hz | 73.4 cm |
+| 2 Hz | 51.5 cm |
+| 5 Hz | 23.3 cm |
+| 10 Hz | 12.5 cm |
+| 15 Hz | 8.9 cm |
+| 20 Hz | 7.4 cm |
+| 25 Hz | 6.2 cm |
+| 50 Hz | 4.5 cm |
+| 100 Hz | 3.5 cm |
+
+The error distance represents the distance of the client's predicted position to the server position sampled on each network packet receival.
+The move speed used in the test was 4.5 meters per second.
+
+The test data shows that there's barely any noticeable benefit in running more than 20 Hz. The movement actually looks very smooth with only 10 Hz, but suffers in a few edge cases (ping-pong movement) where 20 Hz can lead to much better results. The final choice will of course depend on your prediction algorithms and the game type.
+
+## Conclusion
+
+- Too little updates make it really hard to predict where the player is
+- Too many updates will severely increase server CPU & bandwidth usage
+- Prefer a send & receive rate somewhere in the ballpark of 10-20 Hz
diff --git a/posts/projects.md b/posts/projects.md
new file mode 100644
index 0000000..a7c0c75
--- /dev/null
+++ b/posts/projects.md
@@ -0,0 +1,21 @@
+---
+title: Projects
+tags: about
+created: 2024-03-03T23:11:14Z
+published: true
+---
+
+| | |
+| --- | --- |
+| ๐ค [akyoto.dev](https://git.akyoto.dev/web/akyoto.dev) | this website |
+| ๐ฆ [assert](https://git.akyoto.dev/go/assert) | assertions for software correctness |
+| ๐ฎ [bom](https://git.akyoto.dev/game/bom) | game using Godot with Go servers |
+| ๐ [color](https://git.akyoto.dev/go/color) | color for terminals |
+| ๐ฟ [data](https://git.akyoto.dev/go/data) | in-memory key value store |
+| ๐ข [hash](https://git.akyoto.dev/go/hash) | non-cryptographic hash for etags |
+| ๐ [home](https://git.akyoto.dev/sys/home) | personal dotfiles |
+| ๐ [markdown](https://git.akyoto.dev/go/markdown) | markdown renderer for this site |
+| ๐ [notify.moe](https://git.akyoto.dev/web/notify.moe) | anime tracker |
+| ๐ฑ [q](https://git.akyoto.dev/cli/q) | simple programming language |
+| ๐ [router](https://git.akyoto.dev/go/router) | http router based on radix trees |
+| ๐ [web](https://git.akyoto.dev/go/web) | web server for this site |
\ No newline at end of file
diff --git a/posts/separation-of-concerns.md b/posts/separation-of-concerns.md
new file mode 100644
index 0000000..83fc147
--- /dev/null
+++ b/posts/separation-of-concerns.md
@@ -0,0 +1,38 @@
+---
+title: Separation of Concerns
+tags: article software
+created: 2018-06-25T00:16:40Z
+published: true
+---
+
+> Do one thing and do it well.
+
+Separation of concerns is a concept that can be described as the art of only doing what the tool should be concerned with, never more than needs to be done.
+You don't expect a knife to function as a lighter. A knife only needs to cut and it does that one thing very well.
+
+## How does this apply to software?
+
+Any type of modern software architecture allows us to structure our code into modules, packages, files, libraries, engines and other types of abstractions that let us reuse existing functionality.
+
+Whenever you write a new module, ask yourself this: Does this module really need to contain all the code it has inside it?
+Is every part of this module really dealing with the same problem, the same _concern_?
+
+Chances are high that you have written a module in the past that does much more than it needs to do. The module is doing things that it should not be concerned with. These different concerns should be separated into different modules, each dealing only with the bare minimum they need to deal with.
+
+## What's the benefit?
+
+By doing so, you will notice that your code gains a higher chance of being reused in a different project.
+Modules can be tested much easier because the amount of possible states you need to reason about becomes much smaller, therefore contributing to overall better software quality.
+
+## What about frameworks?
+
+This is actually one of the main reasons I don't like monolithic frameworks. You import one package (the framework) and it concerns itself with a multitude of problems. It becomes hard to test and reason about this software. Understanding and fixing bugs becomes difficult because it deals with so many things, the faulty state could have been caused by any part of the system.
+
+Instead, what software developers should strive for, is to make small and independent packages that deal with a single problem only.
+Do not offer a single package that deals with all of the world's problems, offer a set of modules that developers can choose from. By doing so, a framework becomes a _specification_ of modules, a _concept_, rather than an actual package with thousand dependencies.
+
+## Conclusion
+
+- Separate concerns.
+- Do one thing and do it well.
+- Avoid centralism, prefer composition.
diff --git a/posts/static-ip-configuration.md b/posts/static-ip-configuration.md
new file mode 100644
index 0000000..3be8e7f
--- /dev/null
+++ b/posts/static-ip-configuration.md
@@ -0,0 +1,96 @@
+---
+title: Static IP Configuration
+tags: article guide software linux config
+created: 2023-07-02T21:43:42Z
+published: true
+---
+
+When installing Arch Linux on a VPS, you usually need to enable VNC and configure the networking by yourself before you can SSH into your machine.
+This post serves as a guide to connect your server to the internet.
+
+## Connectivity check
+
+First of all, confirm that networking hasn't been set up yet:
+
+```bash
+ping google.com
+```
+
+There should be no response from the ping.
+
+## Network interface
+
+Now let's find out the name of the network interface:
+
+```bash
+networkctl list
+```
+
+You should see an ethernet device named like `eth0` or `ens0`.
+The number at the end will differ.
+This is the name of the network interface we'll configure in the following steps.
+
+## Network manager
+
+Arch Linux uses `systemd` which includes the `systemd-networkd` network manager by default.
+To configure the network manager, edit the following file:
+
+```bash
+sudo vim /etc/systemd/network/20-wired.network
+```
+
+Start by specifying the network interface name:
+
+```ini
+[Match]
+Name=ens0
+```
+
+Now you need to enter your IP address, subnet mask and the gateway.
+Ideally your VPS provider should include that data in your dashboard.
+You can enter the addresses in the network section:
+
+```ini
+[Network]
+Address=2.1.1.2/32
+Gateway=2.1.1.1
+DNS=1.1.1.1
+```
+
+The DNS shown here is the Cloudflare DNS because it's reliable and easy to remember,
+but feel free to use a different DNS.
+
+If your VPS has an IPv6 address you can add more of the same lines to the network section:
+
+```ini
+Address=1111:1111:1111::2345
+Gateway=1111:1111:1111::1111
+DNS=2606:4700:4700::1111
+```
+
+## Service installation
+
+Try to start the DNS resolver and the network manager:
+
+```bash
+sudo systemctl start systemd-resolved
+sudo systemctl start systemd-networkd
+```
+
+Check if we're online on both IPv4 and IPv6:
+
+```bash
+ping -4 google.com
+ping -6 google.com
+```
+
+If everything went smooth, make the DNS resolver and the network manager start automatically on boot:
+
+```bash
+sudo systemctl enable systemd-resolved
+sudo systemctl enable systemd-networkd
+```
+
+## DNS records
+
+To finalize the setup, add an `A` record for IPv4 and an `AAAA` record for IPv6 to your DNS and your server should be fully configured.
diff --git a/posts/tabs-vs-spaces.md b/posts/tabs-vs-spaces.md
new file mode 100644
index 0000000..4dc6b2f
--- /dev/null
+++ b/posts/tabs-vs-spaces.md
@@ -0,0 +1,65 @@
+---
+title: Tabs vs. Spaces
+tags: article software
+created: 2018-06-24T07:03:20Z
+published: true
+---
+
+Let's take a look at tabs vs. spaces. This discussion is famous amongst all skill levels of developers and it seems that noone can really convince the other side. People have different opinions on why one side is better than the other and cannot unanimously agree on one style. I think one of the main reasons for this problem is that the discussion is always about 100% tabs vs. 100% spaces instead of looking at an alternative approach: Using both.
+
+## Both?
+
+At first it might sound weird, but we're not just going to randomly insert a different indentation character whenever we want to. There is going to be a ruleset and that ruleset will be well defined. That means by going hybrid, there are no discussions needed for when tabs or spaces should be used, as every situation will be clearly covered by those rules.
+
+## Which rules, exactly?
+
+1. Tabs for semantic indentation
+2. Spaces for presentational alignment
+
+### Semantic indentation
+
+> Relating to meaning in language or logic.
+
+Semantic indentation is required when the whitespace has a meaning in the given context. Note that _meaning_ doesn't necessarily imply that it is needed for the compiler to process the code as in the case of Python e.g., _meaning_ can simply refer to an indented block of code, let's say a `for` loop, where the body of the loop is semantically different from the surrounding code and therefore is indented.
+
+```go
+for {
+ // This is semantic indentation: Use tabs.
+}
+```
+
+Semantic indentation should be performed as the very first step, using **tabs**.
+
+Spaces would need to be repeated multiple times to represent a single meaning. This is inefficient for disk space and therefore code parsing, let alone the fact that doing so doesn't give us any benefits in the first place. Or when was the last time you used 4 square brackets to represent an array in JSON?
+
+```json
+[[[["Behold the new JSON standard!"]]]]
+```
+
+Why use more when you can do it with less?
+
+We also get the added benefit of letting every team member be able to adjust the tab width and therefore personalize how much pixel space he or she would prefer to be used for a single tab. This can heavily improve readability for a person that is used to very different widths on his or her monitor. Normally, if you used tabs 100% of the time, this argument would be held up **against** using tabs because it can break the alignment of your code. That is exactly why we are going to define separate rules for alignment.
+
+### Presentational alignment
+
+> The proper positioning or state of adjustment of parts in relation to each other.
+
+Presentational alignment refers to positioning different parts better in relation to each other and does not convey any meaning. It will make the code look better but the whitespace doesn't convey that the code is different from the surrounding code, thus being only used to align parts with each other for presentational purposes.
+
+```go
+type User struct {
+ // Note how we're using tabs to indent the struct
+ // and spaces to align the name of the data type.
+ ID string
+ Name string
+ Age int
+}
+```
+
+Alignment should be used _after_ semantic indentation and should be done using **spaces**. The reason is that alignment requires precise positioning on a monospace font and the tab character can't do that because it has dynamic width.
+
+Your team members will thank you because they can finally change the indentation width to something they like and it won't break the alignment of the code.
+
+## Conclusion
+
+Rather than going full tabs or full spaces, consider using a hybrid approach where each character does what it's best at and therefore combining the best of both worlds. I have been using this system for as long as I can remember and I never had a problem with it. For me, this is the de facto standard nowadays and the more people start switching to this system, the better. Amen.
diff --git a/posts/the-final-newline.md b/posts/the-final-newline.md
new file mode 100644
index 0000000..0bbf80d
--- /dev/null
+++ b/posts/the-final-newline.md
@@ -0,0 +1,98 @@
+---
+title: The Final Newline
+tags: article software
+created: 2023-06-28T14:52:08Z
+published: true
+---
+
+The beautiful thing about the language of mathematics is that it is precise and definitions must apply to every case
+presented, 100%, else the definition is considered wrong and needs to be altered. 99% isn't good enough for a
+definition. If there is even a single case showing that the proposed definition doesn't apply to it, we consider the definition to be incorrect.
+
+I'm a little surprised that in software engineering, which must be as precise as mathematics in definitions and specifications, we have come to accept this definition of a line:
+
+> A sequence of zero or more non-newline characters plus a terminating newline character.
+
+As mentioned earlier, if there is even one case that doesn't satisfy the definition, then it's incorrect.
+This definition of a line completely falls apart when you look at a file with the following contents:
+
+```text
+This is a line of text.
+```
+
+Let's save this as `single-line.txt`, without the newline character at the end.
+
+Is this a line? Of course it is, humans don't use line terminators when writing something down in real life.
+Ask any person around you, they will say "yeah, it's one line of text".
+
+## Counting lines
+
+Without a final newline character, POSIX compliant programs will fail to recognize this line:
+
+```bash
+> "This is a line of text." | wc -l
+0
+```
+
+That's because the POSIX definition of a line is wrong. We have one line of text and the computer is telling us we have zero lines in our file.
+
+Now, before you go and send pull requests to the authors of `wc`, let me quickly add: Their documentation explicitly mentions that the flag abbreviated with `-l` does - in fact - not count lines. ๐ค
+
+It only counts _newlines_. The authors of `wc`, Paul Rubin and David MacKenzie, probably wanted to avoid this
+controversy and the documentation states that it only counts newline characters, not lines.
+
+## Separator vs. Terminator
+
+There are 2 ways to interpret the newline character:
+
+- As a line separator
+- As a line terminator
+
+With the "line separator" interpretation you basically treat the contents of a file as a
+
+```go
+strings.Join(lines, "\n")
+```
+
+whereas the "line terminator" interpretation is better expressed as:
+
+```go
+for _, line := range lines {
+ w.WriteString(line)
+ w.WriteByte('\n')
+}
+```
+
+## Definition vs. Regulation
+
+As we have seen, not every line is terminated with a newline character.
+Thus we cannot regard the "line terminator" interpretation as a _definition_, because it's incorrect.
+It's a _regulation_.
+
+A regulation is different because it forces you to do something as opposed to trying to define something.
+
+## Does the POSIX regulation make sense?
+
+The thing about regulations is that we all hate them, but we hate inconsistencies even more.
+
+Even if I personally think that the newline character should be a line separator because it's more in line (pun intended) with how humans see a text file,
+I also recognize that some fights aren't worth fighting.
+
+It would have been a lot easier to discuss this topic in the early days of computing, before the existence of tools that adopted the POSIX standard.
+Now it's hard to argue against it when your co-worker just wants an easy way to disable the annoying "No newline at end of file" warning on every `git diff`.
+
+So my suggestion to developers is that everybody needs to decide for themselves what is worth their time.
+
+If you say that you want to argue with existing standards and try to improve them for the future, then I will fully
+respect that. But know what you're getting yourself into. Everything has an [opportunity cost](https://en.wikipedia.org/wiki/Opportunity_cost).
+I think it's mostly the younger generation that tries to initiate changes and that's not necessarily a bad thing.
+
+Deep down, I really wish somebody would stop this line terminating madness someday. But this isn't my fight.
+
+## Conclusion
+
+- In an ideal world, newline characters would be line separators, not line terminators
+- Tools in the UNIX world have already widely adopted the POSIX regulation
+- It's very hard to make a change in this area
+- Decide for yourself if this is a fight that is worth your time [or not](https://en.wikipedia.org/wiki/Law_of_triviality)
+- If you are not the owner, adopt the style regulations of the project you are contributing to
diff --git a/posts/vector.md b/posts/vector.md
new file mode 100644
index 0000000..4ccbd0c
--- /dev/null
+++ b/posts/vector.md
@@ -0,0 +1,102 @@
+---
+title: Vector
+tags: note vector math
+created: 2023-08-29T11:59:28Z
+published: true
+---
+
+## 2D
+
+### Angle
+
+```go
+atan2(y, x)
+```
+
+### Cross
+
+```go
+x * y2 - y * x2
+```
+
+### Distance
+
+```go
+(a - b).Length()
+```
+
+### Dot
+
+```go
+x * x2 + y * y2
+```
+
+### From angle
+
+```go
+x = cos(angle)
+y = sin(angle)
+```
+
+### Length
+
+```go
+sqrt(x * x + y * y)
+```
+
+### Normalize
+
+```go
+length := x * x + y * y
+
+if length == 0 {
+ return
+}
+
+length = sqrt(length)
+x /= length
+y /= length
+```
+
+## 3D
+
+### Cross
+
+```go
+( y * z2 - z * y2,
+ z * x2 - x * z2,
+ x * y2 - y * x2 )
+```
+
+### Distance
+
+```go
+(a - b).Length()
+```
+
+### Dot
+
+```go
+x * x2 + y * y2 + z * z2
+```
+
+### Length
+
+```go
+sqrt(x * x + y * y + z * z)
+```
+
+### Normalize
+
+```go
+length := x * x + y * y + z * z
+
+if length == 0 {
+ return
+}
+
+length = sqrt(length)
+x /= length
+y /= length
+z /= length
+```
diff --git a/posts/workspace-matrix.md b/posts/workspace-matrix.md
new file mode 100644
index 0000000..9800fcc
--- /dev/null
+++ b/posts/workspace-matrix.md
@@ -0,0 +1,46 @@
+---
+title: Workspace Matrix
+tags: article software linux productivity
+created: 2024-03-01T21:57:39Z
+published: true
+---
+
+I use a 3 x 3 workspace matrix with the numbers on my numpad bound to each workspace.
+My wife also started using the same workflow and she has been pretty fond of it ever since.
+
+I wanted to share this method in case anyone else wants to try this on GNOME or Hyprland.
+For KDE users: I believe the settings menu lets you configure this out of the box.
+
+## Gnome
+
+Normally, you can only set 4 workspace shortcuts in the GNOME settings menu.
+However, by accessing the dconf settings you can circumvent this restriction.
+
+```bash
+export WS=/org/gnome/desktop/wm/keybindings/switch-to-workspace
+dconf write $WS-1 "['KP_7']"
+dconf write $WS-2 "['KP_8']"
+dconf write $WS-3 "['KP_9']"
+dconf write $WS-4 "['KP_4']"
+dconf write $WS-5 "['KP_5']"
+dconf write $WS-6 "['KP_6']"
+dconf write $WS-7 "['KP_1']"
+dconf write $WS-8 "['KP_2']"
+dconf write $WS-9 "['KP_3']"
+```
+
+## Hyprland
+
+Simply add this to your config file.
+
+```ini
+bind = , KP_Home, workspace, 1
+bind = , KP_Up, workspace, 2
+bind = , KP_Prior, workspace, 3
+bind = , KP_Left, workspace, 4
+bind = , KP_Begin, workspace, 5
+bind = , KP_Right, workspace, 6
+bind = , KP_End, workspace, 7
+bind = , KP_Down, workspace, 8
+bind = , KP_Next, workspace, 9
+```
diff --git a/public/app.css b/public/app.css
index 9125328..d559e9a 100644
--- a/public/app.css
+++ b/public/app.css
@@ -100,6 +100,7 @@ blockquote p::after {
h1 {
color: white;
font-size: 2.2rem;
+ font-weight: normal;
letter-spacing: -0.02em;
}
@@ -137,28 +138,14 @@ th:empty {
display: none;
}
-@media (min-width: 800px) {
- h2 {
- margin-left: -1rem;
- }
-
- .post-header {
- margin-left: -1rem;
- }
-
- .post-time {
- margin-left: 0.5rem;
- }
-}
-
-header,
+body > header,
main {
width: 100%;
max-width: var(--max-width);
padding: var(--padding);
}
-header {
+body > header {
max-width: calc(var(--max-width) + 4rem);
}
@@ -186,11 +173,21 @@ nav a:hover {
color: var(--main-color);
}
-p time {
+article header time {
font-size: 0.8rem;
color: var(--grey-color);
}
+.blog li {
+ display: flex;
+}
+
+.blog li time {
+ flex: 1;
+ text-align: right;
+ color: var(--grey-color);
+}
+
.comment {
color: gray;
font-style: italic;
@@ -238,11 +235,12 @@ p time {
}
@media (min-width: 800px) {
+ article header,
h2 {
margin-left: -1rem;
}
- p time {
- margin-left: .5rem;
+ article header time {
+ margin-left: 0.5rem;
}
}
\ No newline at end of file