about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.envrc2
-rw-r--r--.gitattributes9
-rwxr-xr-xbootstrap/01_activate.sh29
-rwxr-xr-xbootstrap/01_install.sh92
-rwxr-xr-xbootstrap/02_setup.sh33
-rwxr-xr-xbootstrap/03_config_setup.sh21
-rwxr-xr-xbootstrap/99_ensure_config_variables.sh133
-rw-r--r--bootstrap/default.nix49
-rw-r--r--flake.lock445
-rw-r--r--flake.nix136
-rw-r--r--flake/apps/default.nix32
-rw-r--r--flake/default.nix111
-rw-r--r--flake/nixosConfigurations/default.nix95
-rw-r--r--flake/packages/default.nix11
-rw-r--r--hosts/apzu/default.nix131
-rw-r--r--hosts/by-name/apzu/configuration.nix60
-rw-r--r--hosts/by-name/apzu/hardware.nix (renamed from hosts/apzu/hardware.nix)0
-rw-r--r--hosts/by-name/tiamat/configuration.nix79
-rw-r--r--hosts/by-name/tiamat/hardware.nix (renamed from hosts/tiamat/hardware.nix)0
-rw-r--r--hosts/default.nix61
-rw-r--r--hosts/tiamat/default.nix144
-rw-r--r--lib/default.nix26
-rw-r--r--modules/by-name/ad/adb/module.nix11
-rw-r--r--modules/by-name/ag/age/module.nix25
-rw-r--r--modules/by-name/al/alacritty/module.nix468
-rw-r--r--modules/by-name/al/alacritty/theme.toml (renamed from modules/home.legacy/conf/alacritty/toml/colorscheme.toml)28
-rw-r--r--modules/by-name/at/atuin/module.nix20
-rw-r--r--modules/by-name/ba/backup/module.nix193
-rw-r--r--modules/by-name/ba/backup/secrets/local/repository_password.age20
-rw-r--r--modules/by-name/ba/backup/secrets/storagebox/repository_password.age (renamed from modules/common/secrets/backup/privatePassword.age)0
-rw-r--r--modules/by-name/ba/backup/secrets/storagebox/ssh_key.age (renamed from modules/common/secrets/backup/privateSshKey.age)0
-rw-r--r--modules/by-name/bo/boot/module.nix11
-rw-r--r--modules/by-name/co/constants/module.nix59
-rw-r--r--modules/by-name/co/coredump/module.nix17
-rw-r--r--modules/by-name/dh/dhcpcd/module.nix21
-rw-r--r--modules/by-name/di/disks/module.nix25
-rw-r--r--modules/by-name/fi/firefox/extensions.json50
-rw-r--r--modules/by-name/fi/firefox/extensions.json.license9
-rw-r--r--modules/by-name/fi/firefox/module.nix243
-rw-r--r--modules/by-name/fi/firefox/profile.nix189
-rw-r--r--modules/by-name/fi/firefox/search_engines/default.nix113
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg1
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg.license9
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/brave.svg25
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/brave.svg.license9
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/google_scholar.icobin3871 -> 0 bytes
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/google_scholar.ico.license9
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/rust_std.svg47
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/rust_std.svg.license9
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/rust_tokio.pngbin3551 -> 0 bytes
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/rust_tokio.png.license9
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg1
-rw-r--r--modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg.license9
-rwxr-xr-xmodules/by-name/fi/firefox/update_extensions.sh22
-rw-r--r--modules/by-name/fi/firefox/userChrome.css53
-rw-r--r--modules/by-name/fo/fonts/module.nix16
-rw-r--r--modules/by-name/fw/fwupd/module.nix6
-rw-r--r--modules/by-name/gi/git/module.nix42
-rw-r--r--modules/by-name/gp/gpg/module.nix9
-rw-r--r--modules/by-name/ha/hardware/module.nix2
-rw-r--r--modules/by-name/hl/lhedger/module.nix57
-rw-r--r--modules/by-name/ho/home-manager/module.nix36
-rw-r--r--modules/by-name/i3/i3bar-river/module.nix197
-rw-r--r--modules/by-name/i3/i3status-rust/module.nix154
-rwxr-xr-xmodules/by-name/i3/i3status-rust/scripts/mpd_song_name.sh (renamed from modules/by-name/ya/yambar/scripts/mpd_song_name.sh)23
-rw-r--r--modules/by-name/ia/iamb/module.nix59
-rw-r--r--modules/by-name/im/impermanence/module.nix27
-rw-r--r--modules/by-name/le/less/module.nix2
-rwxr-xr-xmodules/by-name/lf/lf/commands/base.sh4
-rw-r--r--modules/by-name/lf/lf/commands/default.nix45
-rwxr-xr-xmodules/by-name/lf/lf/commands/scripts/set_wallpaper.sh4
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix2
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/audio/audio.sh2
-rw-r--r--modules/by-name/lf/lf/ctpv/prev/text/default.nix5
-rw-r--r--modules/by-name/lf/lf/keybindings/default.nix2
-rw-r--r--modules/by-name/lf/lf/module.nix11
-rw-r--r--modules/by-name/lf/lf/wrappers/default.nix4
-rw-r--r--modules/by-name/lf/lf/wrappers/ll/default.nix (renamed from pkgs/by-name/ll/ll/package.nix)0
-rwxr-xr-xmodules/by-name/lf/lf/wrappers/ll/ll.sh (renamed from pkgs/by-name/ll/ll/ll.sh)2
-rw-r--r--modules/by-name/lf/lf/wrappers/lm/default.nix (renamed from pkgs/by-name/lm/lm/package.nix)0
-rwxr-xr-xmodules/by-name/lf/lf/wrappers/lm/lm.sh (renamed from pkgs/by-name/lm/lm/lm.sh)0
-rw-r--r--modules/by-name/lo/locale/keymaps/dvorak_modified.xkb12
-rw-r--r--modules/by-name/lo/locale/module.nix6
-rw-r--r--modules/by-name/ma/mako/module.nix81
-rw-r--r--modules/by-name/me/mergiraf/module.nix (renamed from modules/by-name/nv/nvim/plgs/lsp/servers/servers/pylyzer.nix)23
-rw-r--r--modules/by-name/mp/mpd/module.nix3
-rw-r--r--modules/by-name/mp/mpdpopm/module.nix65
-rw-r--r--modules/by-name/mp/mpv/module.nix276
-rw-r--r--modules/by-name/ms/msr/module.nix17
-rw-r--r--modules/by-name/ne/networking/module.nix16
-rw-r--r--modules/by-name/ni/nix-index/command_not_found.sh (renamed from modules/by-name/zs/zsh/config/command_not_found/command_not_found.sh)6
-rw-r--r--modules/by-name/ni/nix-index/module.nix44
-rw-r--r--modules/by-name/ni/nix/module.nix11
-rw-r--r--modules/by-name/ni/nixos-option/module.nix18
-rw-r--r--modules/by-name/ni/nixos-shell/module.nix128
-rwxr-xr-xmodules/by-name/ni/nixos-shell/nixos-shell.sh60
-rw-r--r--modules/by-name/ni/nixos-shell/shell_setup.nix191
-rw-r--r--modules/by-name/ni/nixpkgs/config.nix43
-rw-r--r--modules/by-name/ni/nixpkgs/module.nix29
-rw-r--r--modules/by-name/ns/nscd/module.nix18
-rw-r--r--modules/by-name/nv/nvim/mappings/default.nix41
-rw-r--r--modules/by-name/nv/nvim/module.nix41
-rw-r--r--modules/by-name/nv/nvim/options/default.nix1
-rw-r--r--modules/by-name/nv/nvim/performance/default.nix24
-rw-r--r--modules/by-name/nv/nvim/plgs/comment-nvim/default.nix1
-rw-r--r--modules/by-name/nv/nvim/plgs/debugprint/default.nix82
-rw-r--r--modules/by-name/nv/nvim/plgs/debugprint/lua/debugprint.lua13
-rw-r--r--modules/by-name/nv/nvim/plgs/default.nix42
-rw-r--r--modules/by-name/nv/nvim/plgs/femaco/default.nix13
-rw-r--r--modules/by-name/nv/nvim/plgs/femaco/lua/femaco.lua50
-rw-r--r--modules/by-name/nv/nvim/plgs/flatten-nvim/default.nix33
-rw-r--r--modules/by-name/nv/nvim/plgs/flatten-nvim/lua/flatten-nvim.lua114
-rw-r--r--modules/by-name/nv/nvim/plgs/leap/default.nix74
-rw-r--r--modules/by-name/nv/nvim/plgs/lf-nvim/default.nix83
-rw-r--r--modules/by-name/nv/nvim/plgs/lf-nvim/lua/lf-nvim.lua53
-rw-r--r--modules/by-name/nv/nvim/plgs/lsp-progress-nvim/default.nix62
-rw-r--r--modules/by-name/nv/nvim/plgs/lsp-progress-nvim/lua/lsp-progress-nvim.lua156
-rw-r--r--modules/by-name/nv/nvim/plgs/lsp/servers/default.nix1
-rw-r--r--modules/by-name/nv/nvim/plgs/lsp/servers/servers/openscad.nix6
-rw-r--r--modules/by-name/nv/nvim/plgs/lsp/servers/servers/quick-lint-js.nix4
-rw-r--r--modules/by-name/nv/nvim/plgs/lsp/servers/servers/ruff-lsp.nix2
-rw-r--r--modules/by-name/nv/nvim/plgs/lspkind/default.nix2
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/default.nix77
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/lua/luasnip.lua17
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/all.lua221
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/html/html.lua112
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/delimiter.lua38
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/greek.lua47
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/snippets/all.lua338
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/delimiter.lua41
-rw-r--r--modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/greek.lua49
-rw-r--r--modules/by-name/nv/nvim/plgs/neorg/default.nix10
-rw-r--r--modules/by-name/nv/nvim/plgs/nvim-cmp/default.nix113
-rw-r--r--modules/by-name/nv/nvim/plgs/raw_plugins/default.nix26
-rw-r--r--modules/by-name/nv/nvim/plgs/treesitter/default.nix44
-rw-r--r--modules/by-name/nv/nvim/plgs/vim-tex/default.nix3
-rw-r--r--modules/by-name/oo/oomd/module.nix18
-rw-r--r--modules/by-name/op/openssh/module.nix42
-rw-r--r--modules/by-name/po/polkit/module.nix3
-rw-r--r--modules/by-name/pr/printing/module.nix (renamed from modules/by-name/pi/printing/module.nix)26
-rw-r--r--modules/by-name/qu/qutebrowser/include/redirects.py64
-rw-r--r--modules/by-name/qu/qutebrowser/module.hm.nix490
-rw-r--r--modules/by-name/qu/qutebrowser/module.nix106
-rw-r--r--modules/by-name/qu/qutebrowser/settings/default.nix537
-rw-r--r--modules/by-name/qu/qutebrowser/settings/keybindings.nix289
-rw-r--r--modules/by-name/re/resolvconf/module.nix15
-rwxr-xr-xmodules/by-name/ri/river/init_base.sh5
-rw-r--r--modules/by-name/ri/river/keymap.nix191
-rw-r--r--modules/by-name/ri/river/module.nix31
-rw-r--r--modules/by-name/ri/river/river-start/package.nix (renamed from pkgs/by-name/ri/river-start/package.nix)4
-rwxr-xr-xmodules/by-name/ri/river/river-start/river-start.sh (renamed from pkgs/by-name/ri/river-start/river-start.sh)3
-rw-r--r--modules/by-name/ro/rofi/module.nix31
-rw-r--r--modules/by-name/ro/rofi/nord-twoLines.rasi (renamed from modules/home.legacy/conf/rofi/nord-twoLines.rasi)0
-rw-r--r--modules/by-name/ro/rofi/nord-twoLines.rasi.license (renamed from modules/home.legacy/conf/rofi/nord-twoLines.rasi.license)0
-rw-r--r--modules/by-name/se/serverphone/module.currently_ignored.nix15
-rw-r--r--modules/by-name/so/sound/module.nix8
-rw-r--r--modules/by-name/ss/ssh/module.nix34
-rw-r--r--modules/by-name/st/steam/module.nix5
-rw-r--r--modules/by-name/ta/taskwarrior/module.nix12
-rw-r--r--modules/by-name/ts/tskm/module.nix15
-rw-r--r--modules/by-name/un/unison/module.nix3
-rw-r--r--modules/by-name/un/unison/shellScript.nix29
-rw-r--r--modules/by-name/up/upower/module.nix23
-rw-r--r--modules/by-name/us/users/module.nix2
-rw-r--r--modules/by-name/xd/xdg/module.nix10
-rw-r--r--modules/by-name/ya/yambar/config/config.yml52
-rw-r--r--modules/by-name/ya/yambar/module.nix80
-rwxr-xr-xmodules/by-name/ya/yambar/scripts/disk.sh31
-rwxr-xr-xmodules/by-name/ya/yambar/scripts/network.sh57
-rwxr-xr-xmodules/by-name/ya/yambar/scripts/sound-volume.sh30
-rw-r--r--modules/by-name/ya/yambar/settings/default.nix383
-rw-r--r--modules/by-name/yt/yt/config.toml12
-rwxr-xr-xmodules/by-name/yt/yt/external_commands_script.sh9
-rw-r--r--modules/by-name/yt/yt/input.conf14
-rw-r--r--modules/by-name/yt/yt/input.conf.license9
-rw-r--r--modules/by-name/yt/yt/module.nix99
-rw-r--r--modules/by-name/yt/yt/mpv.conf1
-rw-r--r--modules/by-name/yt/yt/mpv.conf.license9
-rw-r--r--modules/by-name/zs/zsh/config/command_not_found/command_not_found_insult.sh309
-rw-r--r--modules/by-name/zs/zsh/module.nix20
-rw-r--r--modules/common/default.nix121
-rw-r--r--modules/common/nixos_shell_configuration.nix66
-rw-r--r--modules/common/projects.json71
-rw-r--r--modules/default.nix5
-rw-r--r--modules/home.legacy/conf/alacritty/default.nix39
-rw-r--r--modules/home.legacy/conf/alacritty/toml/bell.toml17
-rw-r--r--modules/home.legacy/conf/alacritty/toml/env.toml13
-rw-r--r--modules/home.legacy/conf/alacritty/toml/font.toml25
-rw-r--r--modules/home.legacy/conf/alacritty/toml/general.toml24
-rw-r--r--modules/home.legacy/conf/alacritty/toml/hints.toml35
-rw-r--r--modules/home.legacy/conf/alacritty/toml/keyboard_bindings.toml307
-rw-r--r--modules/home.legacy/conf/alacritty/toml/mouse.toml12
-rw-r--r--modules/home.legacy/conf/alacritty/toml/mouse_bindings.toml13
-rw-r--r--modules/home.legacy/conf/alacritty/toml/scrolling.toml13
-rw-r--r--modules/home.legacy/conf/alacritty/toml/selection.toml13
-rw-r--r--modules/home.legacy/conf/alacritty/toml/window.toml28
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/base.yml27
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/bell.yml52
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/colors.yml157
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/colorscheme.yml41
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/cursor.yml53
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/debug.yml39
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/env.yml21
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/font.yml83
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/hints.yml87
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/key_bindings.yml392
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/mouse.yml21
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/mouse_bindings.yml42
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/scrolling.yml17
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/selection.yml17
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/shell.yml23
-rw-r--r--modules/home.legacy/conf/alacritty/yaml/window.yml99
-rw-r--r--modules/home.legacy/conf/beets/default.nix50
-rw-r--r--modules/home.legacy/conf/beets/plugins.nix24
-rw-r--r--modules/home.legacy/conf/beets/plugins/default.nix5
-rw-r--r--modules/home.legacy/conf/beets/plugins/fuzzy/default.nix15
-rw-r--r--modules/home.legacy/conf/beets/plugins/ihate/default.nix1
-rw-r--r--modules/home.legacy/conf/beets/plugins/inline/default.nix43
-rw-r--r--modules/home.legacy/conf/beets/plugins/lastgenre/default.nix16
-rw-r--r--modules/home.legacy/conf/beets/plugins/mbsubmit/default.nix18
-rw-r--r--modules/home.legacy/conf/beets/plugins/smartplaylist/default.nix42
-rw-r--r--modules/home.legacy/conf/beets/replace_override.yaml20
-rw-r--r--modules/home.legacy/conf/default.nix9
-rw-r--r--modules/home.legacy/conf/hyfetch/default.nix29
-rw-r--r--modules/home.legacy/conf/iamb/config.json9
-rw-r--r--modules/home.legacy/conf/iamb/config.json.license9
-rw-r--r--modules/home.legacy/conf/iamb/default.nix12
-rw-r--r--modules/home.legacy/conf/latexindent/default.nix13
-rw-r--r--modules/home.legacy/conf/latexindent/indentconfig.yaml12
-rw-r--r--modules/home.legacy/conf/latexindent/mysettings.yaml682
-rw-r--r--modules/home.legacy/conf/mail/accounts/soispha.nix4
-rw-r--r--modules/home.legacy/conf/mail/default.nix2
-rw-r--r--modules/home.legacy/conf/mako/default.nix49
-rw-r--r--modules/home.legacy/conf/nix-index/default.nix23
-rw-r--r--modules/home.legacy/conf/rclone/default.nix12
-rw-r--r--modules/home.legacy/conf/rclone/rclone.conf10
-rw-r--r--modules/home.legacy/conf/rclone/rclone.conf.license9
-rw-r--r--modules/home.legacy/conf/rofi/default.nix19
-rw-r--r--modules/home.legacy/conf/starship/default.nix26
-rw-r--r--modules/home.legacy/conf/tridactyl/config.vim57
-rw-r--r--modules/home.legacy/conf/tridactyl/default.nix12
-rw-r--r--modules/home.legacy/default.nix14
-rwxr-xr-xpkgs/by-name/co/con2pdf/con2pdf.sh2
-rwxr-xr-xpkgs/by-name/fu/fupdate-flake/fupdate-flake.sh4
-rw-r--r--pkgs/by-name/fu/fupdate-flake/package.nix6
-rwxr-xr-xpkgs/by-name/fu/fupdate-sys/fupdate-sys.sh2
-rw-r--r--pkgs/by-name/fu/fupdate/Cargo.lock159
-rw-r--r--pkgs/by-name/fu/fupdate/Cargo.toml6
-rw-r--r--pkgs/by-name/fu/fupdate/flake.lock6
-rw-r--r--pkgs/by-name/fu/fupdate/flake.nix12
-rw-r--r--pkgs/by-name/fu/fupdate/src/main.rs21
-rwxr-xr-xpkgs/by-name/fu/fupdate/update.sh3
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/Cargo.lock1662
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/Cargo.toml24
-rwxr-xr-xpkgs/by-name/ge/generate_moz_extension/examples/generate_extensions.sh27
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/flake.lock98
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/flake.nix84
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/res/generate_extensions.py55
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/res/reference.json30
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/res/reference.json.license9
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/res/test.json30
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/res/test.json.license9
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/src/main.rs148
-rw-r--r--pkgs/by-name/ge/generate_moz_extension/src/types.rs81
-rwxr-xr-xpkgs/by-name/gi/git-edit-index/git-edit-index.sh3
-rw-r--r--pkgs/by-name/i3/i3bar-river-patched/0001-feat-crate-bar-Put-the-leftmost-block-in-the-middle-.patch110
-rw-r--r--pkgs/by-name/i3/i3bar-river-patched/package.nix54
-rw-r--r--pkgs/by-name/i3/i3status-rust-patched/package.nix (renamed from modules/home.legacy/conf/beets/plugins/play/default.nix)23
-rw-r--r--pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch190
-rw-r--r--pkgs/by-name/lf/lf-make-map/Cargo.lock280
-rw-r--r--pkgs/by-name/lf/lf-make-map/Cargo.toml8
-rw-r--r--pkgs/by-name/lf/lf-make-map/flake.lock6
-rw-r--r--pkgs/by-name/lf/lf-make-map/flake.nix12
-rw-r--r--pkgs/by-name/lf/lf-make-map/src/mapping/map_key.rs2
-rwxr-xr-xpkgs/by-name/lf/lf-make-map/tests/cases/child_insert/test.sh2
-rwxr-xr-xpkgs/by-name/lf/lf-make-map/tests/cases/simple/test.sh2
-rw-r--r--pkgs/by-name/mp/mpdpopm/.envrc22
-rw-r--r--pkgs/by-name/mp/mpdpopm/.gitignore16
-rw-r--r--pkgs/by-name/mp/mpdpopm/Cargo.lock1449
-rw-r--r--pkgs/by-name/mp/mpdpopm/Cargo.toml46
-rw-r--r--pkgs/by-name/mp/mpdpopm/README.md260
-rw-r--r--pkgs/by-name/mp/mpdpopm/README.org214
-rw-r--r--pkgs/by-name/mp/mpdpopm/build.rs15
-rw-r--r--pkgs/by-name/mp/mpdpopm/config.lsp10
-rw-r--r--pkgs/by-name/mp/mpdpopm/flake.lock48
-rw-r--r--pkgs/by-name/mp/mpdpopm/flake.nix66
-rw-r--r--pkgs/by-name/mp/mpdpopm/package.nix (renamed from pkgs/by-name/ya/yambar-modules/package.nix)16
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs604
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs150
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/clients.rs1200
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/config.rs286
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/dj/algorithms.rs155
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/dj/mod.rs28
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/filters.lalrpop160
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/filters_ast.rs1022
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/lib.rs185
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/messanges/mod.rs110
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/playcounts.rs313
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/storage/mod.rs145
-rw-r--r--pkgs/by-name/mp/mpdpopm/src/vars.rs4
-rwxr-xr-xpkgs/by-name/mp/mpdpopm/update.sh14
-rwxr-xr-xpkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh4
-rwxr-xr-xpkgs/by-name/mp/mpp/mpp.sh6
-rw-r--r--pkgs/by-name/mp/mpp/package.nix8
-rw-r--r--pkgs/by-name/no/notify-run/.envrc (renamed from pkgs/by-name/ge/generate_moz_extension/.envrc)11
-rw-r--r--pkgs/by-name/no/notify-run/.gitignore (renamed from pkgs/by-name/ge/generate_moz_extension/.gitignore)3
-rw-r--r--pkgs/by-name/no/notify-run/Cargo.lock25
-rw-r--r--pkgs/by-name/no/notify-run/Cargo.toml (renamed from pkgs/by-name/ya/yambar-modules/Cargo.toml)7
-rw-r--r--pkgs/by-name/no/notify-run/flake.lock27
-rw-r--r--pkgs/by-name/no/notify-run/flake.lock.license (renamed from pkgs/by-name/ge/generate_moz_extension/flake.lock.license)0
-rw-r--r--pkgs/by-name/no/notify-run/flake.nix34
-rw-r--r--pkgs/by-name/no/notify-run/package.nix (renamed from pkgs/by-name/ge/generate_moz_extension/package.nix)34
-rw-r--r--pkgs/by-name/no/notify-run/src/main.rs65
-rwxr-xr-xpkgs/by-name/no/notify-run/update.sh (renamed from pkgs/by-name/ge/generate_moz_extension/update.sh)2
-rw-r--r--pkgs/by-name/qu/qutebrowser-patched/0001-fix-standardpaths-Continue-to-work-with-xdg-while-ba.patch54
-rw-r--r--pkgs/by-name/qu/qutebrowser-patched/package.nix6
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/Cargo.lock725
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/Cargo.toml20
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/TODO1
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/TODO.license9
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/contrib/example.json7
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/contrib/init.json261
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/flake.lock6
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/flake.nix24
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/package.nix18
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/resources/river-control-unstable-v1.xml85
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/resources/river-status-unstable-v1.xml148
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/cli.rs18
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/key_map/commands.rs386
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/key_map/mod.rs118
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/main.rs62
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs173
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/dispatches.rs214
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/mod.rs272
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/render/layout.rs57
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/render/mod.rs129
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/river/mod.rs1
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/river/protocols.rs28
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/mod.rs21
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/multi.rs437
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/raw.rs290
-rw-r--r--pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/slot.rs596
-rwxr-xr-xpkgs/by-name/ri/river-mk-keymap/update.sh3
-rwxr-xr-xpkgs/by-name/sc/screenshot_persistent/screenshot_persistent.sh2
-rw-r--r--pkgs/by-name/st/stamp/package.nix2
-rw-r--r--pkgs/by-name/sw/swallow/package.nix (renamed from modules/home.legacy/conf/alacritty/toml/cursor.toml)24
-rwxr-xr-xpkgs/by-name/sw/swallow/swallow.sh23
-rw-r--r--pkgs/by-name/tr/tree-sitter-yts/package.nix42
-rw-r--r--pkgs/by-name/ts/tskm/.envrc3
-rw-r--r--pkgs/by-name/ts/tskm/Cargo.lock701
-rw-r--r--pkgs/by-name/ts/tskm/Cargo.toml23
-rw-r--r--pkgs/by-name/ts/tskm/flake.lock6
-rw-r--r--pkgs/by-name/ts/tskm/flake.nix12
-rw-r--r--pkgs/by-name/ts/tskm/package.nix2
-rw-r--r--pkgs/by-name/ts/tskm/src/browser/mod.rs202
-rw-r--r--pkgs/by-name/ts/tskm/src/cli.rs98
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/input/handle.rs114
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/input/mod.rs185
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs20
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs2
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/handle.rs310
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/open/mod.rs240
-rw-r--r--pkgs/by-name/ts/tskm/src/interface/project/handle.rs12
-rw-r--r--pkgs/by-name/ts/tskm/src/main.rs4
-rw-r--r--pkgs/by-name/ts/tskm/src/state.rs2
-rw-r--r--pkgs/by-name/ts/tskm/src/task/mod.rs9
-rwxr-xr-xpkgs/by-name/ts/tskm/update.sh3
-rw-r--r--pkgs/by-name/ya/yambar-modules/.envrc13
-rw-r--r--pkgs/by-name/ya/yambar-modules/.gitignore11
-rw-r--r--pkgs/by-name/ya/yambar-modules/Cargo.lock141
-rw-r--r--pkgs/by-name/ya/yambar-modules/flake.lock61
-rw-r--r--pkgs/by-name/ya/yambar-modules/flake.lock.license9
-rw-r--r--pkgs/by-name/ya/yambar-modules/flake.nix41
-rw-r--r--pkgs/by-name/ya/yambar-modules/src/cpu.rs31
-rw-r--r--pkgs/by-name/ya/yambar-modules/src/main.rs36
-rw-r--r--pkgs/by-name/ya/yambar-modules/src/memory.rs39
-rw-r--r--pkgs/by-name/yt/yt/package.nix108
-rw-r--r--pkgs/default.nix6
-rwxr-xr-xpkgs/update_pkgs.sh2
-rwxr-xr-xscripts/build.sh (renamed from build.sh)10
-rwxr-xr-xscripts/why-depends23
-rw-r--r--secrets.nix5
-rwxr-xr-xupdate.sh3
383 files changed, 18211 insertions, 12013 deletions
diff --git a/.envrc b/.envrc
index 294de504..f1c78da8 100644
--- a/.envrc
+++ b/.envrc
@@ -11,3 +11,5 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
 use flake
+
+PATH_add ./scripts
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index cc83ed2f..00000000
--- a/.gitattributes
+++ /dev/null
@@ -1,9 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/bootstrap/01_activate.sh b/bootstrap/01_activate.sh
deleted file mode 100755
index 832fe669..00000000
--- a/bootstrap/01_activate.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-. %SCRIPT_ENSURE_CONFIG_VARIABLES
-
-nix run github:nix-community/disko --experimental-features 'nix-command flakes' -- --flake "git+https://codeberg.org/soispha/nixos-config#$NIX_HOST" --mode mount
-
-msg "Finished mounting"
-
-case "$ACTIVATE_TO_SETUP" in
-"yes")
-    nix run "git+https://codeberg.org/soispha/nixos-config#setup" --experimental-features 'nix-command flakes'
-    ;;
-*) ;;
-esac
-
-# vim: ft=sh
diff --git a/bootstrap/01_install.sh b/bootstrap/01_install.sh
deleted file mode 100755
index 3e33866a..00000000
--- a/bootstrap/01_install.sh
+++ /dev/null
@@ -1,92 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-INSTALL=y . %SCRIPT_ENSURE_CONFIG_VARIABLES
-
-msg "Important information:"
-msg2 "Choose disk id is: $NIX_DISK"
-warning "This information needs to be entered in the host configuration BEFORE rebuilding it. Otherwise you'll have to wait for a 1 h cooldown!"
-info_applied=false
-while [ "$info_applied" = false ]; do
-    readp "Have you updated your chosen host with the choose disk id? [N/y]: " result
-    # shellcheck disable=SC2154
-    case $result in
-    [Yy])
-        info_applied=true
-        ;;
-    *)
-        warning "You won't be able to boot, if you don't update it!"
-        ;;
-    esac
-done
-
-msg "Started creating filesystem..."
-nix run github:nix-community/disko --experimental-features 'nix-command flakes' -- --flake "git+https://codeberg.org/soispha/nixos-config#$NIX_HOST" --mode disko
-msg "Finished mounting and generating btrfs subvolumes"
-
-msg "Creating swapfile..."
-msg2 "$(btrfs filesystem mkswapfile --size "$(free -m | awk '{if (NR==2) {printf "%sm\n", $2 + 500}}')" /mnt/swap/swapfile)"
-msg "Finished creating swapfile!"
-
-msg "Important information:"
-msg2 "Swapfile UUID is: $(findmnt -no UUID -T /mnt/swap/swapfile)"
-msg2 "Swapfile resume offset is: $(btrfs inspect-internal map-swapfile -r /mnt/swap/swapfile)"
-warning "This information needs to be entered in the host configuration BEFORE rebuilding it. Otherwise the system won't boot!"
-
-info_applied=false
-while [ "$info_applied" = false ]; do
-    readp "Have you updated your chosen host with this information? [N/y]: " result
-    case $result in
-    [Yy])
-        info_applied=true
-        ;;
-    *)
-        warning "You won't be able to boot, if you don't update it!"
-        ;;
-    esac
-done
-
-msg "Checking for incompatibilities..."
-ssd_or_hdd="$(cat /sys/block/"$(basename "$(readlink -f "/dev/disk/by-id/$NIX_DISK")" | tr -d '\n')"/queue/rotational)"
-case "$ssd_or_hdd" in
-0)
-    msg2 "You seem to use a ssd."
-    trim_support=$(lsblk --bytes --json --discard | jq --arg name "$(basename "$(readlink -f "/dev/disk/by-id/$NIX_DISK")" | tr -d '\n')" '.blockdevices | .[] | select(.name == $name) | (.["disc-gran"] + .["disc-max"]) != 0')
-    case $trim_support in
-    "true")
-        msg2 "Yay, your ssd supports trim, go on and activate it"
-        ;;
-    "false")
-        msg2 "Nay, your ssd doesn't support trim"
-        ;;
-    *)
-        warning "Your ssd doesn't seem to exists, if this bothers you please open an issue."
-        ;;
-    esac
-    ;;
-1)
-    msg2 "You seem to use a hdd there is nothing you have to do"
-    ;;
-*)
-    warning "There is no indicator, which shows, which drive your are using.\n This means, that you have to check yourself, which optimizations you should activate."
-    ;;
-esac
-
-case "$INSTALL_TO_SETUP" in
-"yes")
-    nix run "git+https://codeberg.org/soispha/nixos-config#setup" --experimental-features 'nix-command flakes'
-    ;;
-*) ;;
-esac
diff --git a/bootstrap/02_setup.sh b/bootstrap/02_setup.sh
deleted file mode 100755
index 5d811030..00000000
--- a/bootstrap/02_setup.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-. %SCRIPT_ENSURE_CONFIG_VARIABLES
-
-nixos-install --flake git+https://codeberg.org/soispha/nixos-config#"$NIX_HOST" --no-root-passwd
-
-# clone the git config
-git clone https://codeberg.org/soispha/nixos-config.git /mnt/srv/etc/nixos
-
-# setup persistent home dir
-mkdir --parents /mnt/srv/home
-chown 1000:100 --recursive /mnt/srv/home
-chmod 700 /mnt/srv/home
-
-case "$SETUP_TO_CONFIG_SETUP" in
-"yes")
-    nix run "git+https://codeberg.org/soispha/nixos-config#config_setup" --experimental-features 'nix-command flakes'
-    ;;
-*) ;;
-esac
diff --git a/bootstrap/03_config_setup.sh b/bootstrap/03_config_setup.sh
deleted file mode 100755
index 872d1fe1..00000000
--- a/bootstrap/03_config_setup.sh
+++ /dev/null
@@ -1,21 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-# clone packer.nvim to the needed dir, for the nvim install to work
-git clone --depth 1 https://github.com/wbthomason/packer.nvim /mnt/srv/home/soispha/.local/share/nvim/site/pack/packer/start/packer.nvim
-
-nixos-enter --command 'nvim -c "PackerSync" -c "qall" -u "/mnt/srv/home/soispha/.config/nvim/init.lua" --headless'
-
-# vim: ft=sh
diff --git a/bootstrap/99_ensure_config_variables.sh b/bootstrap/99_ensure_config_variables.sh
deleted file mode 100755
index 12d9ce8f..00000000
--- a/bootstrap/99_ensure_config_variables.sh
+++ /dev/null
@@ -1,133 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-if ! [ "$NIX_ENVIRONMENT_VARIABLES_SET" ]; then
-    if ! [ "$NIX_HOST" ]; then
-        msg "Select a host:"
-        _hosts=$(mktmp)
-        curl https://codeberg.org/soispha/nixos-config/raw/branch/prime/flake/nixosConfigurations/default.nix 2>/dev/null | awk -F '"' '/hosts = /{for (i=2;i<NF;i+=2) {print $i}}' >"$_hosts"
-
-        while ! grep "$host" "$_hosts" >/dev/null || [ "$(printf "%s" "$host" | wc -c)" -eq 0 ]; do
-            i=1
-            while read -r host_read; do
-                printf "%4s) %s \n" "$i" "$host_read"
-                i=$((i + 1))
-            done <"$_hosts"
-            printf "%4s) Exit\n" "q"
-            readp "Enter a option: " host
-
-            [ "$host" = "q" ] && exit 1
-            host=$(awk -v i="$host" '{if (NR==i) {print $0}}' "$_hosts")
-            if ! grep "$host" "$_hosts" >/dev/null || [ "$(printf "%s" "$host" | wc -c)" -eq 0 ]; then
-                warning "No host selected. Select a host to continue.\n"
-            fi
-        done
-
-        export NIX_HOST="$host"
-    fi
-    if ! [ "$NIX_DISK" ] && [ "$INSTALL" ]; then
-        available_disks="$(mktmp)"
-        lsblk -J | jq '.[] | map(.name) | [foreach .[] as $item ({item: null, index: -1}; {$item, index: (.index + 1)})]' >"$available_disks"
-
-        [ "$(jq '.[]' "$available_disks" | wc -l)" -eq 0 ] && die "No disks found"
-        msg "Select a disk to format:"
-
-        i=9999 # nobody will have so many disks attached
-
-        while ! jq -e --argjson i "$i" '.[$i]' "$available_disks" >/dev/null 2>&1; do
-            for _disk in $(jq -c '.[]' "$available_disks"); do
-                printf "%4s) %s \n" "$(echo "$_disk" | jq '.index')" "$(echo "$_disk" | jq '.item' | tr -d '"')"
-            done
-            printf "%4s) Exit\n" "q"
-            readp "Enter a option: " _disk
-
-            if [ "$_disk" = "q" ]; then
-                exit 1
-            else
-                i="$_disk"
-            fi
-            if jq -e --argjson i "$i" 'nth($i)' "$available_disks" >/dev/null 2>&1; then
-                _disk=$(mktmp)
-                jq -e --argjson i "$i" 'nth($i)' "$available_disks" >"$_disk"
-            else
-                warning "No disk selected. Select a disk to continue.\n"
-            fi
-        done
-
-        warn "All data on disk $(jq '.item' "$_disk") will be deleted."
-        readp "Continue with this disk? [N/y]: " result
-        # shellcheck disable=SC2154
-        case "$result" in
-        [Yy])
-            msg "Great, continuing..."
-            _disk="$(jq '.item' "$_disk" | tr -d '"')"
-            _disk_serial="$(udevadm info --query=all --name="$_disk" | grep ID_SERIAL= | awk 'BEGIN{FS="="}{print $2}')"
-            case "$_disk" in
-            "nvme"*)
-                _nix_disk="nvme-$_disk_serial"
-                ;;
-            "sd"*)
-                _nix_disk="ata-$_disk_serial"
-                ;;
-            *)
-                die "Disk with name '$_disk' and serial '$_disk_serial' not yet supported!"
-                ;;
-            esac
-            export NIX_DISK="$_nix_disk"
-            ;;
-        *)
-            msg "Sure, keep your data"
-            exit 1
-            ;;
-        esac
-    fi
-
-    if ! [ "$ACTIVATE_TO_SETUP" ] && ! [ "$INSTALL" ]; then
-        readp "Do you want to continue with nixos-install after activation? [N/y]: " result
-        case $result in
-        [Yy])
-            export ACTIVATE_TO_SETUP=yes
-            ;;
-        *)
-            export ACTIVATE_TO_SETUP=no
-            ;;
-        esac
-    fi
-    if ! [ "$INSTALL_TO_SETUP" ] && [ "$INSTALL" ]; then
-        readp "Do you want to continue with nixos-install after disk formatting? [N/y]: " result
-        case $result in
-        [Yy])
-            export INSTALL_TO_SETUP=yes
-            ;;
-        *)
-            export INSTALL_TO_SETUP=no
-            ;;
-        esac
-    fi
-    if ! [ "$SETUP_TO_CONFIG_SETUP" ]; then
-        readp "Do you want to continue with the user configuration setup after setup? [N/y]: " result
-        case $result in
-        [Yy])
-            export SETUP_TO_CONFIG_SETUP=yes
-            ;;
-        *)
-            export SETUP_TO_CONFIG_SETUP=no
-            ;;
-        esac
-    fi
-    export NIX_ENVIRONMENT_VARIABLES_SET="set"
-fi
-
-# vim: ft=sh
diff --git a/bootstrap/default.nix b/bootstrap/default.nix
deleted file mode 100644
index a5492290..00000000
--- a/bootstrap/default.nix
+++ /dev/null
@@ -1,49 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  pkgs,
-  sysLib,
-  ...
-}: let
-  ensure_config_variables_dependencies = builtins.attrValues {inherit (pkgs) systemd jq dash gnugrep curl;};
-  replacementStrings = {SCRIPT_ENSURE_CONFIG_VARIABLES = "${ensure_config_variables}/bin/ensure_config_variables";};
-  activate = sysLib.writeShellScript {
-    dependencies = with pkgs; [jq gawk curl coreutils libuuid lix git] ++ ensure_config_variables_dependencies;
-    name = "activate";
-    src = ./01_activate.sh;
-    inherit replacementStrings;
-  };
-  install = sysLib.writeShellScript {
-    dependencies = with pkgs; [jq dash curl gawk btrfs-progs coreutils libuuid gptfdisk dosfstools toybox lix git] ++ ensure_config_variables_dependencies;
-    name = "install";
-    src = ./01_install.sh;
-    inherit replacementStrings;
-  };
-  setup = sysLib.writeShellScript {
-    dependencies = with pkgs; [dash gawk curl git lix gnugrep nixos-install-tools coreutils libuuid] ++ ensure_config_variables_dependencies;
-    name = "setup";
-    src = ./02_setup.sh;
-    inherit replacementStrings;
-  };
-  config_setup = sysLib.writeShellScript {
-    dependencies = builtins.attrValues {inherit (pkgs) git neovim;} ++ ensure_config_variables_dependencies;
-    name = "config_setup";
-    src = ./03_config_setup.sh;
-    keepPath = true;
-    inherit replacementStrings;
-  };
-  ensure_config_variables = sysLib.writeShellScript {
-    name = "ensure_config_variables";
-    src = ./99_ensure_config_variables.sh;
-    wrap = false;
-  };
-  output = {inherit activate install setup config_setup ensure_config_variables;};
-in
-  output
diff --git a/flake.lock b/flake.lock
index 2d80a3fc..65390eb9 100644
--- a/flake.lock
+++ b/flake.lock
@@ -16,11 +16,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1736955230,
-        "narHash": "sha256-uenf8fv2eG5bKM8C/UvFaiJMZ4IpUFaQxk9OH5t/1gA=",
+        "lastModified": 1762618334,
+        "narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
         "owner": "ryantm",
         "repo": "agenix",
-        "rev": "e600439ec4c273cf11e06fe4d9d906fb98fa097c",
+        "rev": "fcdea223397448d35d9b31f798479227e80183f6",
         "type": "github"
       },
       "original": {
@@ -29,50 +29,33 @@
         "type": "github"
       }
     },
-    "arkenfox-nixos": {
+    "beautysh": {
       "inputs": {
-        "flake-compat": [
-          "flake-compat"
+        "flake-parts": [
+          "flake-parts"
         ],
-        "nixpkgs": [
-          "nixpkgs"
+        "git-hooks-nix": [
+          "git-hooks"
+        ],
+        "nix-github-actions": [
+          "nix-github-actions"
         ],
-        "pre-commit": [
-          "pre-commit-hooks"
-        ]
-      },
-      "locked": {
-        "lastModified": 1744011341,
-        "narHash": "sha256-ZwyAdfXgfigchDLMZ/UqSjLc5YKk2xnchGHuWaNfqmQ=",
-        "owner": "dwarfmaster",
-        "repo": "arkenfox-nixos",
-        "rev": "57eefe49b80ea5e02f42199db531292de34a4350",
-        "type": "github"
-      },
-      "original": {
-        "owner": "dwarfmaster",
-        "repo": "arkenfox-nixos",
-        "type": "github"
-      }
-    },
-    "beautysh": {
-      "inputs": {
         "nixpkgs": [
           "nixpkgs"
         ],
-        "poetry2nix": [
-          "poetry2nix"
+        "pyproject-build-systems": "pyproject-build-systems",
+        "pyproject-nix": "pyproject-nix",
+        "treefmt-nix": [
+          "treefmt-nix"
         ],
-        "utils": [
-          "flake-utils"
-        ]
+        "uv2nix": "uv2nix"
       },
       "locked": {
-        "lastModified": 1680308980,
-        "narHash": "sha256-aUEHV0jk2qIFP3jlsWYWhBbm+w/N9gzH3e4I5DcdB5s=",
+        "lastModified": 1764601770,
+        "narHash": "sha256-jM4ChpHM/YTr2YIL5uZ1j4K8SoSrQUSJed2g9Z9GbVY=",
         "owner": "lovesegfault",
         "repo": "beautysh",
-        "rev": "9845efc3ea3e86cc0d41465d720a47f521b2799c",
+        "rev": "18907582aeb81b3aa0457183f42e95e16ab68c92",
         "type": "github"
       },
       "original": {
@@ -83,11 +66,11 @@
     },
     "crane": {
       "locked": {
-        "lastModified": 1745454774,
-        "narHash": "sha256-oLvmxOnsEKGtwczxp/CwhrfmQUG2ym24OMWowcoRhH8=",
+        "lastModified": 1768700043,
+        "narHash": "sha256-rfs2aP+wdueJZ6uABaj0e0PavQyzkRJuJX30HNcBPTg=",
         "owner": "ipetkov",
         "repo": "crane",
-        "rev": "efd36682371678e2b6da3f108fdb5c613b3ec598",
+        "rev": "935de8bd6838d940988bb065be2a2034259327b9",
         "type": "github"
       },
       "original": {
@@ -103,11 +86,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1741473158,
-        "narHash": "sha256-kWNaq6wQUbUMlPgw8Y+9/9wP0F8SHkjy24/mN3UAppg=",
+        "lastModified": 1764011051,
+        "narHash": "sha256-M7SZyPZiqZUR/EiiBJnmyUbOi5oE/03tCeFrTiUZchI=",
         "owner": "numtide",
         "repo": "devshell",
-        "rev": "7c9e793ebe66bcba8292989a68c0419b737a22a0",
+        "rev": "17ed8d9744ebe70424659b0ef74ad6d41fc87071",
         "type": "github"
       },
       "original": {
@@ -123,11 +106,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1745502102,
-        "narHash": "sha256-LqhRwzvIVPEjH0TaPgwzqpyhW6DtCrvz7FnUJDoUZh8=",
+        "lastModified": 1768727946,
+        "narHash": "sha256-le2GY+ZR6uRHMuOAc60sBR3gBD2BEk1qOZ3S5C/XFpU=",
         "owner": "nix-community",
         "repo": "disko",
-        "rev": "ca27b88c88948d96feeee9ed814cbd34f53d0d70",
+        "rev": "558e84658d0eafc812497542ad6ca0d9654b3b0f",
         "type": "github"
       },
       "original": {
@@ -139,11 +122,11 @@
     "flake-compat": {
       "flake": false,
       "locked": {
-        "lastModified": 1733328505,
-        "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
+        "lastModified": 1767039857,
+        "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
         "owner": "edolstra",
         "repo": "flake-compat",
-        "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
+        "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
         "type": "github"
       },
       "original": {
@@ -159,11 +142,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1743550720,
-        "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
+        "lastModified": 1768135262,
+        "narHash": "sha256-PVvu7OqHBGWN16zSi6tEmPwwHQ4rLPU9Plvs8/1TUBY=",
         "owner": "hercules-ci",
         "repo": "flake-parts",
-        "rev": "c621e8422220273271f52058f618c94e405bb0f5",
+        "rev": "80daad04eddbbf5a4d883996a73f3f542fa437ac",
         "type": "github"
       },
       "original": {
@@ -192,32 +175,6 @@
         "type": "github"
       }
     },
-    "flake_version_update": {
-      "inputs": {
-        "flake-utils": [
-          "flake-utils"
-        ],
-        "nixpkgs": [
-          "nixpkgs"
-        ],
-        "systems": [
-          "systems"
-        ]
-      },
-      "locked": {
-        "lastModified": 1685288691,
-        "narHash": "sha256-oP6h34oJ8rm6KlUpyZrX+ww3hnoWny2ecrEXxkU7F3c=",
-        "ref": "refs/heads/prime",
-        "rev": "e9a97e01eca780bd16e1dbdbd8856b59558f4959",
-        "revCount": 5,
-        "type": "git",
-        "url": "https://codeberg.org/soispha/flake_version_update.git"
-      },
-      "original": {
-        "type": "git",
-        "url": "https://codeberg.org/soispha/flake_version_update.git"
-      }
-    },
     "git-hooks": {
       "inputs": {
         "flake-compat": [
@@ -231,11 +188,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1742649964,
-        "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
+        "lastModified": 1767281941,
+        "narHash": "sha256-6MkqajPICgugsuZ92OMoQcgSHnD6sJHwk8AxvMcIgTE=",
         "owner": "cachix",
         "repo": "git-hooks.nix",
-        "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
+        "rev": "f0927703b7b1c8d97511c4116eb9b4ec6645a0fa",
         "type": "github"
       },
       "original": {
@@ -251,11 +208,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1709087332,
-        "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+        "lastModified": 1762808025,
+        "narHash": "sha256-XmjITeZNMTQXGhhww6ed/Wacy2KzD6svioyCX7pkUu4=",
         "owner": "hercules-ci",
         "repo": "gitignore.nix",
-        "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+        "rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
         "type": "github"
       },
       "original": {
@@ -291,11 +248,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1745555634,
-        "narHash": "sha256-lhVyVn1utb2UVTbyKJ6mfKB7wLTjrj14OlebvO0WU2s=",
+        "lastModified": 1768707181,
+        "narHash": "sha256-GdwFfnwdUgABFpc4sAmX7GYx8eQs6cEjOPo6nBJ0YaI=",
         "owner": "nix-community",
         "repo": "home-manager",
-        "rev": "98f4fef7fd7b4a77245db12e33616023162bc6d9",
+        "rev": "83bcb17377f0242376a327e742e9404e9a528647",
         "type": "github"
       },
       "original": {
@@ -306,12 +263,20 @@
       }
     },
     "impermanence": {
+      "inputs": {
+        "home-manager": [
+          "home-manager"
+        ],
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
       "locked": {
-        "lastModified": 1737831083,
-        "narHash": "sha256-LJggUHbpyeDvNagTUrdhe/pRVp4pnS6wVKALS782gRI=",
+        "lastModified": 1768741755,
+        "narHash": "sha256-plWg64Pku30ZDY0MV2wMlHdZbrqLeQLdCwF3LKJ2aig=",
         "owner": "nix-community",
         "repo": "impermanence",
-        "rev": "4b3e914cdf97a5b536a889e939fb2fd2b043a170",
+        "rev": "5eed14a23246e1a6e008374e4df758c10187a972",
         "type": "github"
       },
       "original": {
@@ -332,16 +297,16 @@
         ]
       },
       "locked": {
-        "lastModified": 1737371634,
-        "narHash": "sha256-fTVAWzT1UMm1lT+YxHuVPtH+DATrhYfea3B0MxG/cGw=",
+        "lastModified": 1754860581,
+        "narHash": "sha256-EM0IE63OHxXCOpDHXaTyHIOk2cNvMCGPqLt/IdtVxgk=",
         "owner": "NuschtOS",
         "repo": "ixx",
-        "rev": "a1176e2a10ce745ff8f63e4af124ece8fe0b1648",
+        "rev": "babfe85a876162c4acc9ab6fb4483df88fa1f281",
         "type": "github"
       },
       "original": {
         "owner": "NuschtOS",
-        "ref": "v0.0.7",
+        "ref": "v0.1.1",
         "repo": "ixx",
         "type": "github"
       }
@@ -351,16 +316,10 @@
         "crane": [
           "crane"
         ],
-        "flake-compat": [
-          "flake-compat"
-        ],
-        "flake-parts": [
-          "flake-parts"
-        ],
         "nixpkgs": [
           "nixpkgs-stable"
         ],
-        "pre-commit-hooks-nix": [
+        "pre-commit": [
           "pre-commit-hooks"
         ],
         "rust-overlay": [
@@ -368,16 +327,16 @@
         ]
       },
       "locked": {
-        "lastModified": 1737639419,
-        "narHash": "sha256-AEEDktApTEZ5PZXNDkry2YV2k6t0dTgLPEmAZbnigXU=",
+        "lastModified": 1765382359,
+        "narHash": "sha256-RJmgVDzjRI18BWVogG6wpsl1UCuV6ui8qr4DJ1LfWZ8=",
         "owner": "nix-community",
         "repo": "lanzaboote",
-        "rev": "a65905a09e2c43ff63be8c0e86a93712361f871e",
+        "rev": "e8c096ade12ec9130ff931b0f0e25d2f1bc63607",
         "type": "github"
       },
       "original": {
         "owner": "nix-community",
-        "ref": "v0.4.2",
+        "ref": "v1.0.0",
         "repo": "lanzaboote",
         "type": "github"
       }
@@ -405,11 +364,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1744478979,
-        "narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
+        "lastModified": 1768561867,
+        "narHash": "sha256-prGOZ+w3pZfGTRxworKcJliCNsewF0L4HUPjgU/6eaw=",
         "owner": "lnl7",
         "repo": "nix-darwin",
-        "rev": "43975d782b418ebf4969e9ccba82466728c2851b",
+        "rev": "8b720b9662d4dd19048664b7e4216ce530591adc",
         "type": "github"
       },
       "original": {
@@ -421,16 +380,15 @@
     "nix-github-actions": {
       "inputs": {
         "nixpkgs": [
-          "poetry2nix",
           "nixpkgs"
         ]
       },
       "locked": {
-        "lastModified": 1729742964,
-        "narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
+        "lastModified": 1737420293,
+        "narHash": "sha256-F1G5ifvqTpJq7fdkT34e/Jy9VCyzd5XfJ9TO8fHhJWE=",
         "owner": "nix-community",
         "repo": "nix-github-actions",
-        "rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
+        "rev": "f4158fa080ef4503c8f4c820967d946c2af31ec9",
         "type": "github"
       },
       "original": {
@@ -446,11 +404,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1745120797,
-        "narHash": "sha256-owQ0VQ+7cSanTVPxaZMWEzI22Q4bGnuvhVjLAJBNQ3E=",
+        "lastModified": 1765267181,
+        "narHash": "sha256-d3NBA9zEtBu2JFMnTBqWj7Tmi7R5OikoU2ycrdhQEws=",
         "owner": "nix-community",
         "repo": "nix-index-database",
-        "rev": "69716041f881a2af935021c1182ed5b0cc04d40e",
+        "rev": "82befcf7dc77c909b0f2a09f5da910ec95c5b78f",
         "type": "github"
       },
       "original": {
@@ -459,32 +417,6 @@
         "type": "github"
       }
     },
-    "nixVim": {
-      "inputs": {
-        "flake-parts": [
-          "flake-parts"
-        ],
-        "nixpkgs": [
-          "nixpkgs"
-        ],
-        "nuschtosSearch": [
-          "nuschtosSearch"
-        ]
-      },
-      "locked": {
-        "lastModified": 1745538632,
-        "narHash": "sha256-f2BzxQNoMF+wb+7b5O5p3fQ5r7I9u0ezzGBq2f38kl8=",
-        "owner": "nix-community",
-        "repo": "nixvim",
-        "rev": "d86fe3df569c748b2632cfa5d27da0ea59709212",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-community",
-        "repo": "nixvim",
-        "type": "github"
-      }
-    },
     "nixos-generators": {
       "inputs": {
         "nixlib": [
@@ -495,11 +427,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1742568034,
-        "narHash": "sha256-QaMEhcnscfF2MqB7flZr+sLJMMYZPnvqO4NYf9B4G38=",
+        "lastModified": 1764234087,
+        "narHash": "sha256-NHF7QWa0ZPT8hsJrvijREW3+nifmF2rTXgS2v0tpcEA=",
         "owner": "nix-community",
         "repo": "nixos-generators",
-        "rev": "42ee229088490e3777ed7d1162cb9e9d8c3dbb11",
+        "rev": "032a1878682fafe829edfcf5fdfad635a2efe748",
         "type": "github"
       },
       "original": {
@@ -510,27 +442,27 @@
     },
     "nixpkgs": {
       "locked": {
-        "lastModified": 1745391562,
-        "narHash": "sha256-sPwcCYuiEopaafePqlG826tBhctuJsLx/mhKKM5Fmjo=",
+        "lastModified": 1768701115,
+        "narHash": "sha256-kkRg+hOTrRye6nDf6WBG8Ue7/ETUhfXdFSIVEXV2XXo=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "8a2f738d9d1f1d986b5a4cd2fd2061a7127237d7",
+        "rev": "a48c9dbce9a434f3647d4d9eab783eca11a242c4",
         "type": "github"
       },
       "original": {
         "owner": "NixOS",
-        "ref": "nixos-unstable",
+        "ref": "nixos-unstable-small",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
     "nixpkgs-lib": {
       "locked": {
-        "lastModified": 1745111456,
-        "narHash": "sha256-6k3oWdGcWOIzh3OQBkIf+HBU+xH5vbZtUhwzXEX4NWI=",
+        "lastModified": 1768699094,
+        "narHash": "sha256-uapeGJTPPbmqjdo5zlrWFEIys1XIOQ66sKP3A5UNEOk=",
         "owner": "nix-community",
         "repo": "nixpkgs.lib",
-        "rev": "eab2ba94b72a8664e0fb92912160151d99db850e",
+        "rev": "78975aaec5a67ea502e15836919b89d7df96ac27",
         "type": "github"
       },
       "original": {
@@ -541,20 +473,46 @@
     },
     "nixpkgs-stable": {
       "locked": {
-        "lastModified": 1745487689,
-        "narHash": "sha256-FQoi3R0NjQeBAsEOo49b5tbDPcJSMWc3QhhaIi9eddw=",
+        "lastModified": 1768621446,
+        "narHash": "sha256-6YwHV1cjv6arXdF/PQc365h1j+Qje3Pydk501Rm4Q+4=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "5630cf13cceac06cefe9fc607e8dfa8fb342dde3",
+        "rev": "72ac591e737060deab2b86d6952babd1f896d7c5",
         "type": "github"
       },
       "original": {
         "owner": "NixOS",
-        "ref": "nixos-24.11",
+        "ref": "nixos-25.11",
         "repo": "nixpkgs",
         "type": "github"
       }
     },
+    "nixvim": {
+      "inputs": {
+        "flake-parts": [
+          "flake-parts"
+        ],
+        "nixpkgs": [
+          "nixpkgs"
+        ],
+        "systems": [
+          "systems"
+        ]
+      },
+      "locked": {
+        "lastModified": 1768486009,
+        "narHash": "sha256-I7ymDe6UQooHy9I9wrafKCCDnRbox/EMWAgJgpm7fGs=",
+        "owner": "nix-community",
+        "repo": "nixvim",
+        "rev": "03a638205b5cb04ba9c2ed6c604e137b15f07fa1",
+        "type": "github"
+      },
+      "original": {
+        "owner": "nix-community",
+        "repo": "nixvim",
+        "type": "github"
+      }
+    },
     "nuschtosSearch": {
       "inputs": {
         "flake-utils": [
@@ -566,11 +524,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1745046075,
-        "narHash": "sha256-8v4y6k16Ra/fiecb4DxhsoOGtzLKgKlS+9/XJ9z0T2I=",
+        "lastModified": 1768249818,
+        "narHash": "sha256-ANfn5OqIxq3HONPIXZ6zuI5sLzX1sS+2qcf/Pa0kQEc=",
         "owner": "NuschtOS",
         "repo": "search",
-        "rev": "066afe8643274470f4a294442aadd988356a478f",
+        "rev": "b6f77b88e9009bfde28e2130e218e5123dc66796",
         "type": "github"
       },
       "original": {
@@ -584,7 +542,9 @@
         "flake-utils": [
           "flake-utils"
         ],
-        "nix-github-actions": "nix-github-actions",
+        "nix-github-actions": [
+          "nix-github-actions"
+        ],
         "nixpkgs": [
           "nixpkgs"
         ],
@@ -622,11 +582,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1742649964,
-        "narHash": "sha256-DwOTp7nvfi8mRfuL1escHDXabVXFGT1VlPD1JHrtrco=",
+        "lastModified": 1767281941,
+        "narHash": "sha256-6MkqajPICgugsuZ92OMoQcgSHnD6sJHwk8AxvMcIgTE=",
         "owner": "cachix",
         "repo": "pre-commit-hooks.nix",
-        "rev": "dcf5072734cb576d2b0c59b2ac44f5050b5eac82",
+        "rev": "f0927703b7b1c8d97511c4116eb9b4ec6645a0fa",
         "type": "github"
       },
       "original": {
@@ -635,72 +595,89 @@
         "type": "github"
       }
     },
-    "qmk_firmware": {
+    "pyproject-build-systems": {
       "inputs": {
-        "flake-utils": [
-          "flake-utils"
-        ],
         "nixpkgs": [
+          "beautysh",
           "nixpkgs"
         ],
-        "systems": [
-          "systems"
+        "pyproject-nix": [
+          "beautysh",
+          "pyproject-nix"
         ],
-        "treefmt-nix": [
-          "treefmt-nix"
+        "uv2nix": [
+          "beautysh",
+          "uv2nix"
         ]
       },
       "locked": {
-        "lastModified": 1738406121,
-        "narHash": "sha256-N3scpt+nwPbqzsRs4gjZpDiBivfPRQJ0D75bPeYhHME=",
-        "ref": "prime",
-        "rev": "2b6889092e5839c8987e800f1d3d847dd5b50153",
-        "revCount": 19,
-        "type": "git",
-        "url": "https://git.foss-syndicate.org/bpeetz/qmk_layout.git"
+        "lastModified": 1763662255,
+        "narHash": "sha256-4bocaOyLa3AfiS8KrWjZQYu+IAta05u3gYZzZ6zXbT0=",
+        "owner": "pyproject-nix",
+        "repo": "build-system-pkgs",
+        "rev": "042904167604c681a090c07eb6967b4dd4dae88c",
+        "type": "github"
       },
       "original": {
-        "ref": "prime",
-        "type": "git",
-        "url": "https://git.foss-syndicate.org/bpeetz/qmk_layout.git"
+        "owner": "pyproject-nix",
+        "repo": "build-system-pkgs",
+        "type": "github"
       }
     },
-    "ragenix": {
+    "pyproject-nix": {
+      "inputs": {
+        "nixpkgs": [
+          "beautysh",
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1764134915,
+        "narHash": "sha256-xaKvtPx6YAnA3HQVp5LwyYG1MaN4LLehpQI8xEdBvBY=",
+        "owner": "pyproject-nix",
+        "repo": "pyproject.nix",
+        "rev": "2c8df1383b32e5443c921f61224b198a2282a657",
+        "type": "github"
+      },
+      "original": {
+        "owner": "pyproject-nix",
+        "repo": "pyproject.nix",
+        "type": "github"
+      }
+    },
+    "qmk_firmware": {
       "inputs": {
-        "agenix": [
-          "agenix"
-        ],
-        "crane": [
-          "crane"
-        ],
         "flake-utils": [
           "flake-utils"
         ],
         "nixpkgs": [
           "nixpkgs"
         ],
-        "rust-overlay": [
-          "rust-overlay"
+        "systems": [
+          "systems"
+        ],
+        "treefmt-nix": [
+          "treefmt-nix"
         ]
       },
       "locked": {
-        "lastModified": 1744897914,
-        "narHash": "sha256-GIVU92o2TZBnKQXTb76zpQbWR4zjU2rFqWKNIIpXnqA=",
-        "owner": "yaxitech",
-        "repo": "ragenix",
-        "rev": "40f2e17ecaeab4d78ec323e96a04548c0aaa5223",
-        "type": "github"
+        "lastModified": 1753517111,
+        "narHash": "sha256-dv5P3ahDICDacdzEmcyxrtKgbRWhVFiKQaLEz+WniGM=",
+        "ref": "prime",
+        "rev": "4dff2e6ba5c9c80de3e3d2213ad28802814c3bba",
+        "revCount": 39,
+        "type": "git",
+        "url": "https://git.foss-syndicate.org/bpeetz/qmk_layout.git"
       },
       "original": {
-        "owner": "yaxitech",
-        "repo": "ragenix",
-        "type": "github"
+        "ref": "prime",
+        "type": "git",
+        "url": "https://git.foss-syndicate.org/bpeetz/qmk_layout.git"
       }
     },
     "root": {
       "inputs": {
         "agenix": "agenix",
-        "arkenfox-nixos": "arkenfox-nixos",
         "beautysh": "beautysh",
         "crane": "crane",
         "devshell": "devshell",
@@ -708,7 +685,6 @@
         "flake-compat": "flake-compat",
         "flake-parts": "flake-parts",
         "flake-utils": "flake-utils",
-        "flake_version_update": "flake_version_update",
         "git-hooks": "git-hooks",
         "gitignore": "gitignore",
         "haumea": "haumea",
@@ -717,20 +693,19 @@
         "lanzaboote": "lanzaboote",
         "library": "library",
         "nix-darwin": "nix-darwin",
+        "nix-github-actions": "nix-github-actions",
         "nix-index-database": "nix-index-database",
-        "nixVim": "nixVim",
         "nixos-generators": "nixos-generators",
         "nixpkgs": "nixpkgs",
         "nixpkgs-lib": "nixpkgs-lib",
         "nixpkgs-stable": "nixpkgs-stable",
+        "nixvim": "nixvim",
         "nuschtosSearch": "nuschtosSearch",
         "poetry2nix": "poetry2nix",
         "pre-commit-hooks": "pre-commit-hooks",
         "qmk_firmware": "qmk_firmware",
-        "ragenix": "ragenix",
         "rust-overlay": "rust-overlay",
         "serverphone": "serverphone",
-        "shell_library": "shell_library",
         "systems": "systems",
         "templates": "templates",
         "treefmt-nix": "treefmt-nix"
@@ -743,11 +718,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1745548521,
-        "narHash": "sha256-xyliq8oS5OnzXjHRGr92RtmrtYI/dflf2gSEo0wMFjc=",
+        "lastModified": 1768704795,
+        "narHash": "sha256-Y33TAp2BHEcuspYvcmBXXD0qdvjftv73PwyKTDOjoSY=",
         "owner": "oxalica",
         "repo": "rust-overlay",
-        "rev": "eb0afb4ac0720d55c29e88eb29432103d73ae11d",
+        "rev": "4b7472a78857ac789fb26616040f55cfcbd36c6e",
         "type": "github"
       },
       "original": {
@@ -791,35 +766,6 @@
         "url": "https://codeberg.org/vhack.eu/serverphone.git"
       }
     },
-    "shell_library": {
-      "inputs": {
-        "flake-utils": [
-          "flake-utils"
-        ],
-        "flake_version_update": [
-          "flake_version_update"
-        ],
-        "nixpkgs": [
-          "nixpkgs"
-        ],
-        "systems": [
-          "systems"
-        ]
-      },
-      "locked": {
-        "lastModified": 1710519017,
-        "narHash": "sha256-7C7onkhZiLwzrrf9XfzHEOjht9FmZfGABPbzE8XOYoI=",
-        "ref": "refs/heads/prime",
-        "rev": "24713f56f30e755553cac9497258ebc5d73036dc",
-        "revCount": 180,
-        "type": "git",
-        "url": "https://codeberg.org/soispha/shell_library.git"
-      },
-      "original": {
-        "type": "git",
-        "url": "https://codeberg.org/soispha/shell_library.git"
-      }
-    },
     "systems": {
       "locked": {
         "lastModified": 1680978846,
@@ -871,11 +817,11 @@
         ]
       },
       "locked": {
-        "lastModified": 1744961264,
-        "narHash": "sha256-aRmUh0AMwcbdjJHnytg1e5h5ECcaWtIFQa6d9gI85AI=",
+        "lastModified": 1768158989,
+        "narHash": "sha256-67vyT1+xClLldnumAzCTBvU0jLZ1YBcf4vANRWP3+Ak=",
         "owner": "numtide",
         "repo": "treefmt-nix",
-        "rev": "8d404a69efe76146368885110f29a2ca3700bee6",
+        "rev": "e96d59dff5c0d7fddb9d113ba108f03c3ef99eca",
         "type": "github"
       },
       "original": {
@@ -883,6 +829,31 @@
         "repo": "treefmt-nix",
         "type": "github"
       }
+    },
+    "uv2nix": {
+      "inputs": {
+        "nixpkgs": [
+          "beautysh",
+          "nixpkgs"
+        ],
+        "pyproject-nix": [
+          "beautysh",
+          "pyproject-nix"
+        ]
+      },
+      "locked": {
+        "lastModified": 1764546642,
+        "narHash": "sha256-pCzgOjGEZyH7xKmpckdJzWyO0kvTIlaTK+ed/wguv5Y=",
+        "owner": "pyproject-nix",
+        "repo": "uv2nix",
+        "rev": "0c56de7543459a23d0ebb7977fd555ced5d842ae",
+        "type": "github"
+      },
+      "original": {
+        "owner": "pyproject-nix",
+        "repo": "uv2nix",
+        "type": "github"
+      }
     }
   },
   "root": "root",
diff --git a/flake.nix b/flake.nix
index dd60b8dd..206a440f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -13,8 +13,8 @@
 
   inputs = {
     # base
-    nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.11";
-    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+    nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-25.11";
+    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small";
 
     # open nixpkgs prs
 
@@ -39,6 +39,12 @@
         nixpkgs.follows = "nixpkgs";
       };
     };
+    nix-github-actions = {
+      url = "github:nix-community/nix-github-actions";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+      };
+    };
     git-hooks = {
       url = "github:cachix/git-hooks.nix";
       inputs = {
@@ -54,6 +60,7 @@
         nixpkgs.follows = "nixpkgs";
         flake-utils.follows = "flake-utils";
         treefmt-nix.follows = "treefmt-nix";
+        nix-github-actions.follows = "nix-github-actions";
       };
     };
     flake-parts = {
@@ -81,8 +88,10 @@
       url = "github:lovesegfault/beautysh";
       inputs = {
         nixpkgs.follows = "nixpkgs";
-        poetry2nix.follows = "poetry2nix";
-        utils.follows = "flake-utils";
+        flake-parts.follows = "flake-parts";
+        git-hooks-nix.follows = "git-hooks";
+        treefmt-nix.follows = "treefmt-nix";
+        nix-github-actions.follows = "nix-github-actions";
       };
     };
     devshell = {
@@ -119,14 +128,6 @@
         nixpkgs.follows = "nixpkgs";
       };
     };
-    flake_version_update = {
-      url = "git+https://codeberg.org/soispha/flake_version_update.git";
-      inputs = {
-        systems.follows = "systems";
-        nixpkgs.follows = "nixpkgs";
-        flake-utils.follows = "flake-utils";
-      };
-    };
 
     # nixos modules
     home-manager = {
@@ -141,12 +142,12 @@
         nixpkgs.follows = "nixpkgs";
       };
     };
-    nixVim = {
+    nixvim = {
       url = "github:nix-community/nixvim";
       inputs = {
         flake-parts.follows = "flake-parts";
         nixpkgs.follows = "nixpkgs";
-        nuschtosSearch.follows = "nuschtosSearch";
+        systems.follows = "systems";
       };
     };
     agenix = {
@@ -158,19 +159,11 @@
         systems.follows = "systems";
       };
     };
-    ragenix = {
-      url = "github:yaxitech/ragenix";
-      inputs = {
-        nixpkgs.follows = "nixpkgs";
-        agenix.follows = "agenix";
-        flake-utils.follows = "flake-utils";
-        rust-overlay.follows = "rust-overlay";
-        crane.follows = "crane";
-      };
-    };
     impermanence = {
       url = "github:nix-community/impermanence";
       inputs = {
+        nixpkgs.follows = "nixpkgs";
+        home-manager.follows = "home-manager";
       };
     };
     nixos-generators = {
@@ -192,14 +185,12 @@
       };
     };
     lanzaboote = {
-      url = "github:nix-community/lanzaboote/v0.4.2";
+      url = "github:nix-community/lanzaboote/v1.0.0";
       inputs = {
         nixpkgs.follows = "nixpkgs-stable";
-        flake-compat.follows = "flake-compat";
-        flake-parts.follows = "flake-parts";
         crane.follows = "crane";
         rust-overlay.follows = "rust-overlay";
-        pre-commit-hooks-nix.follows = "pre-commit-hooks";
+        pre-commit.follows = "pre-commit-hooks";
       };
     };
     nix-index-database = {
@@ -208,14 +199,6 @@
         nixpkgs.follows = "nixpkgs";
       };
     };
-    arkenfox-nixos = {
-      url = "github:dwarfmaster/arkenfox-nixos";
-      inputs = {
-        nixpkgs.follows = "nixpkgs";
-        pre-commit.follows = "pre-commit-hooks";
-        flake-compat.follows = "flake-compat";
-      };
-    };
 
     # my configs
     templates = {
@@ -229,15 +212,6 @@
     };
 
     # my bins
-    shell_library = {
-      url = "git+https://codeberg.org/soispha/shell_library.git";
-      inputs = {
-        nixpkgs.follows = "nixpkgs";
-        flake-utils.follows = "flake-utils";
-        systems.follows = "systems";
-        flake_version_update.follows = "flake_version_update";
-      };
-    };
     qmk_firmware = {
       url = "git+https://git.foss-syndicate.org/bpeetz/qmk_layout.git?ref=prime";
       inputs = {
@@ -268,71 +242,77 @@
     nixos-generators,
     impermanence,
     agenix,
-    ragenix,
     serverphone,
     disko,
     lanzaboote,
-    nixVim,
+    nixvim,
     nix-index-database,
-    arkenfox-nixos,
     # external dependencies
     treefmt-nix,
     templates,
     # my binaries
-    shell_library,
     qmk_firmware,
     ...
   }: let
     system = "x86_64-linux";
-    sysLib = shell_library.lib.${system};
 
-    baseLib = import ./lib {inherit (pkgs) lib;};
+    packageSets = rec {
+      stable = nixpkgs-stable.legacyPackages.${system};
+      unstable = nixpkgs.legacyPackages.${system};
 
-    inherit (library) nixLib;
-
-    pkgsStable = nixpkgs-stable.legacyPackages.${system};
-    pkgs = nixpkgs.legacyPackages.${system};
-    myPkgs = import ./pkgs {
-      inherit pkgs nixLib;
+      soispha = import ./pkgs {
+        inherit libraries;
+        pkgs = unstable;
+      };
     };
 
-    nixpkgs_as_input = nixpkgs;
-    nixpkgs_open_prs = {
+    libraries = rec {
+      nix = packageSets.unstable.lib;
+      base = import ./lib {lib = nix;};
+      extra = library.nixLib;
     };
 
-    outputs = import ./flake {
+    modules = {
       inherit
-        # core
-        self
-        pkgs
-        pkgsStable
-        nixLib
-        myPkgs
-        system
-        sysLib
-        baseLib
-        nixpkgs_as_input
-        nixpkgs_open_prs
-        # modules
         home-manager
-        nixVim
+        nixvim
         nixos-generators
         impermanence
         agenix
-        ragenix
         serverphone
         disko
         lanzaboote
         nix-index-database
-        arkenfox-nixos
-        # external dependencies
+        ;
+    };
+
+    externalDependencies = {
+      inherit
         treefmt-nix
         templates
-        # my binaries
-        shell_library
+        ;
+    };
+
+    externalBinaries = {
+      inherit
         qmk_firmware
         ;
     };
+
+    openPRsNixpkgs = {};
+
+    outputs = import ./flake {
+      inherit
+        self
+        system
+        openPRsNixpkgs
+        packageSets
+        libraries
+        modules
+        externalDependencies
+        externalBinaries
+        ;
+    };
   in
     outputs;
 }
diff --git a/flake/apps/default.nix b/flake/apps/default.nix
deleted file mode 100644
index b9f4c255..00000000
--- a/flake/apps/default.nix
+++ /dev/null
@@ -1,32 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  self,
-  system,
-  ...
-}: {
-  install = {
-    type = "app";
-    program = "${self.packages."${system}".install}/bin/install";
-  };
-  activate = {
-    type = "app";
-    program = "${self.packages."${system}".activate}/bin/activate";
-  };
-  setup = {
-    type = "app";
-    program = "${self.packages."${system}".setup}/bin/setup";
-  };
-  config_setup = {
-    type = "app";
-    program = "${self.packages."${system}".config_setup}/bin/config_setup";
-  };
-  default = self.apps."${system}".activate;
-}
diff --git a/flake/default.nix b/flake/default.nix
index 646f9732..83138f32 100644
--- a/flake/default.nix
+++ b/flake/default.nix
@@ -8,82 +8,51 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
-  # core
   self,
-  pkgs,
-  pkgsStable,
-  nixLib,
-  baseLib,
-  myPkgs,
   system,
-  sysLib,
-  nixpkgs_as_input,
-  nixpkgs_open_prs,
-  # modules
-  home-manager,
-  nixVim,
-  nixos-generators,
-  impermanence,
-  agenix,
-  ragenix,
-  serverphone,
-  disko,
-  lanzaboote,
-  nix-index-database,
-  arkenfox-nixos,
-  # external dependencies
-  treefmt-nix,
-  templates,
-  # my binaries
-  shell_library,
-  qmk_firmware,
+  openPRsNixpkgs,
+  packageSets,
+  libraries,
+  modules,
+  externalDependencies,
+  externalBinaries,
 }: let
-  treefmtEval = import ./treefmt.nix {inherit treefmt-nix pkgs;};
+  # Unpack common stuff.
+  nixLib = libraries.extra;
+  pkgs = packageSets.unstable;
 
-  nixosConfigurations = import ./nixosConfigurations {
+  treefmtEval = import ./treefmt.nix {
+    inherit (externalDependencies) treefmt-nix;
+    inherit pkgs;
+  };
+
+  nixosConfigurations = import ../hosts {
     inherit
       self
-      pkgsStable
-      myPkgs
       system
-      nixpkgs_as_input
-      nixpkgs_open_prs
-      # my things
-      shell_library
-      sysLib
-      nixLib
-      baseLib
-      templates
-      # modules
-      home-manager
-      nixVim
-      nixos-generators
-      impermanence
-      agenix
-      ragenix
-      serverphone
-      disko
-      lanzaboote
-      nix-index-database
-      arkenfox-nixos
-      # bins
-      qmk_firmware
+      openPRsNixpkgs
+      packageSets
+      libraries
+      modules
+      externalDependencies
+      externalBinaries
       ;
   };
 
   tests = import ../tests {
-    inherit pkgs nixpkgs_as_input myPkgs sysLib nixLib nixpkgs_open_prs system;
+    inherit pkgs nixLib openPRsNixpkgs system;
+    myPkgs = packageSets.soispha;
     inherit (pkgs) lib;
     extraModules = {
       nixvim = {
-        homeManagerModule = nixVim.homeManagerModules.nixvim;
+        homeManagerModule = modules.nixVim.homeModules.nixvim;
       };
-      agenix = agenix.nixosModules.default;
-      disko = disko.nixosModules.default;
-      serverphone = serverphone.nixosModules.default;
-      inherit (home-manager.nixosModules) home-manager;
-      inherit (impermanence.nixosModules) impermanence;
-      inherit (lanzaboote.nixosModules) lanzaboote;
+      agenix = modules.agenix.nixosModules.default;
+      disko = modules.disko.nixosModules.default;
+      serverphone = modules.serverphone.nixosModules.default;
+      inherit (modules.home-manager.nixosModules) home-manager;
+      inherit (modules.impermanence.nixosModules) impermanence;
+      inherit (modules.lanzaboote.nixosModules) lanzaboote;
     };
   };
 in {
@@ -102,24 +71,15 @@ in {
 
   packages."${system}" = import ./packages {
     inherit
-      nixos-generators
       pkgs
-      pkgsStable
-      myPkgs
-      sysLib
-      system
-      nixVim
       self
-      shell_library
       ;
-    inherit (pkgs) lib;
+    myPkgs = packageSets.soispha;
   };
 
   formatter."${system}" = treefmtEval.config.build.wrapper;
 
-  baseLib."${system}" = baseLib;
-
-  apps."${system}" = import ./apps {inherit self system;};
+  baseLib."${system}" = libraries.base;
 
   devShells."${system}" = {
     default = pkgs.mkShell {
@@ -133,7 +93,7 @@ in {
         pkgs.reuse
 
         # secrets
-        ragenix.packages."${system}".default
+        pkgs.ragenix
         pkgs.rage
 
         # shell
@@ -146,10 +106,7 @@ in {
         # nix
         pkgs.alejandra
         pkgs.deadnix
-
-        # update
-        myPkgs.generate_moz_extension # needed for the firefox extension update script
-        myPkgs.lf-make-map # needed to generate the lf cd mappings
+        pkgs.nvd
       ];
     };
   };
diff --git a/flake/nixosConfigurations/default.nix b/flake/nixosConfigurations/default.nix
deleted file mode 100644
index c4fa2f40..00000000
--- a/flake/nixosConfigurations/default.nix
+++ /dev/null
@@ -1,95 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  self,
-  system,
-  pkgsStable,
-  myPkgs,
-  nixpkgs_as_input,
-  nixpkgs_open_prs,
-  # my things
-  shell_library,
-  sysLib,
-  nixLib,
-  baseLib,
-  templates,
-  # modules
-  home-manager,
-  nixVim,
-  nixos-generators,
-  impermanence,
-  agenix,
-  ragenix,
-  serverphone,
-  disko,
-  lanzaboote,
-  nix-index-database,
-  arkenfox-nixos,
-  # bins
-  qmk_firmware,
-}: let
-  modules = [
-    agenix.nixosModules.default
-    disko.nixosModules.default
-    home-manager.nixosModules.home-manager
-    impermanence.nixosModules.impermanence
-    lanzaboote.nixosModules.lanzaboote
-    serverphone.nixosModules.default
-
-    ../../modules
-    ../../modules/common
-  ];
-
-  specialArgs = {
-    inherit
-      # extra package sources
-      nixpkgs_open_prs
-      pkgsStable
-      myPkgs
-      shell_library
-      sysLib
-      nixLib
-      baseLib
-      # extra information
-      system
-      # modules
-      impermanence
-      nix-index-database
-      nixVim
-      arkenfox-nixos
-      # nix registry
-      nixpkgs_as_input
-      self
-      templates
-      # bins
-      # TODO: Integrate these into `pkgs/by-name` <2024-05-22>
-      qmk_firmware
-      serverphone
-      ;
-  };
-
-  generateHost = name: {
-    name = "${name}";
-    value = nixpkgs_as_input.lib.nixosSystem {
-      inherit specialArgs;
-      modules =
-        [
-          ../../hosts/${name}
-        ]
-        ++ modules;
-    };
-  };
-
-  # FIXME: These need to stay in this position for the install script
-  hosts = ["tiamat" "apzu"];
-
-  generatedHosts = builtins.listToAttrs (builtins.map generateHost hosts);
-in
-  generatedHosts
diff --git a/flake/packages/default.nix b/flake/packages/default.nix
index 7ea1b6cc..9c67eda3 100644
--- a/flake/packages/default.nix
+++ b/flake/packages/default.nix
@@ -8,18 +8,12 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
-  self,
-  nixos-generators,
   pkgs,
+  self,
   myPkgs,
-  pkgsStable,
-  sysLib,
-  system,
-  shell_library,
   ...
 }: let
   inherit (pkgs) lib;
-  output = import ../../bootstrap {inherit pkgs sysLib;};
 
   run_test_description = pkgs.callPackage ../../tests/infrastructure/run.nix {};
 
@@ -86,8 +80,6 @@ in
     #   format = "install-iso";
     # };
 
-    update_shell_lib = shell_library.packages."${system}".update_shell_library;
-
     # gpg-iso = nixos-generators.nixosGenerate {
     #   system = "x86_64-linux";
     #   specialArgs = defaultSpecialArgs;
@@ -101,6 +93,5 @@ in
     nvim = nvim.tiamat;
     inherit run_test_description;
   }
-  // output
   // output_neovim
   // myPkgsFlat
diff --git a/hosts/apzu/default.nix b/hosts/apzu/default.nix
deleted file mode 100644
index 96dd99e1..00000000
--- a/hosts/apzu/default.nix
+++ /dev/null
@@ -1,131 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  lib,
-  pkgs,
-  baseLib,
-  ...
-}: {
-  imports = [
-    ./hardware.nix
-  ];
-
-  soispha = {
-    bluetooth.enable = true;
-
-    laptop = {
-      backlight = "intel_backlight";
-      enable = true;
-    };
-    programs = {
-      yambar = {
-        laptop = true;
-        backlight = "intel_backlight";
-      };
-      river.init = {
-        mappings = {
-          layout = "dvorak-modified";
-          keymap =
-            {
-              # Focus change
-              "<Meta-T>" = {command = ["focus-view" "next"];};
-              "<Meta-N>" = {command = ["focus-view" "previous"];};
-              "<Meta+Ctrl-T>" = {command = ["focus-output" "next"];};
-              "<Meta+Ctrl-N>" = {command = ["focus-output" "previous"];};
-
-              # Standard programs
-              "<Meta-<ENTER>>" = {command = ["spawn" "${lib.getExe pkgs.alacritty}"];};
-              "<Meta+Shift-q>" = {command = ["exit"];};
-              "<Meta-L>" = {command = ["spawn" "${lib.getExe pkgs.lock}"];};
-
-              # Screenshot
-              "<PRINTSCREEN>" = {command = ["spawn" "${lib.getExe pkgs.screenshot_persistent}"];};
-
-              # Audio
-              "<MEDIA_RAISEVOLUME>" = {
-                command = ["spawn" "${lib.getExe' pkgs.wireplumber "wpctl"} set-volume @DEFAULT_SINK@ 5%+"];
-                modes = ["normal" "locked"];
-              };
-              "<MEDIA_LOWERVOLUME>" = {
-                command = ["spawn" "${lib.getExe' pkgs.wireplumber "wpctl"} set-volume @DEFAULT_SINK@ 5%-"];
-                modes = ["normal" "locked"];
-              };
-              "<MEDIA_MUTEVOLUME>" = {
-                command = ["spawn" "${lib.getExe pkgs.mpc} toggle"];
-                modes = ["normal" "locked"];
-              };
-
-              # Launcher
-              "<Meta-R>" = {command = ["spawn" "${lib.getExe pkgs.rofi} -show combi -modes combi -combi-modes 'window, drun, run' -show-icons"];};
-              "<Meta-<F1>>" = {command = ["spawn" "${lib.getExe pkgs.tskm} open select"];};
-              "<Meta-<F2>>" = {command = ["spawn" "${lib.getExe pkgs.keepassxc}"];};
-              "<Meta-<F3>>" = {command = ["spawn" "${lib.getExe pkgs.signal-desktop}"];};
-              # "<Meta-<F4>>" = {command = ["spawn" "${lib.getExe pkgs.steam}"];};
-
-              # Client
-              "<Meta-f>" = {command = ["toggle-fullscreen"];};
-              "<Meta+Shift-c>" = {command = ["close"];};
-              "<Meta+Ctrl- >" = {command = ["toggle-float"];};
-              "<Meta+Ctrl-<ENTER>>" = {command = ["zoom"];};
-              "<Meta-o>" = {command = ["send-to-output" "next"];};
-              "<Meta+Shift-T>" = {command = ["swap" "next"];};
-              "<Meta+Shift-N>" = {command = ["swap" "previous"];};
-
-              # Toggle all tags
-              "<Meta-0>" = {command = ["set-focused-tags" (builtins.toString ((baseLib.pow 2 32) - 1))];};
-              "<Meta+Shift-0>" = {command = ["set-view-tags" (builtins.toString ((baseLib.pow 2 32) - 1))];};
-
-              # Mouse
-              "<Meta-<MOUSE_LEFT>>" = {
-                command = ["move-view"];
-                map_mode = "MapMouse";
-              };
-              "<Meta-<MOUSE_RIGHT>>" = {
-                command = ["resize-view"];
-                map_mode = "MapMouse";
-              };
-            }
-            // (
-              builtins.foldl' (acc: elem: acc // elem) {} (
-                builtins.map (index: let
-                  num = builtins.toString index;
-                  index2tag = input: builtins.toString (baseLib.pow 2 (input - 1));
-                in {
-                  "<Meta-${num}>" = {command = ["set-focused-tags" (index2tag index)];};
-                  "<Meta+Shift-${num}>" = {command = ["set-view-tags" (index2tag index)];};
-                  "<Meta+Shift+Ctrl-${num}>" = {command = ["toggle-view-tags" (index2tag index)];};
-                }) (builtins.genList (i: i + 1) 9)
-              )
-            );
-        };
-        screenSetupCode = {};
-      };
-    };
-
-    locale.enable = true;
-    networking = {
-      enable = true;
-      hostName = "apzu";
-      mode = "NetworkManager";
-    };
-    services.unison.foreign.address = "tiamat.fritz.box";
-    nixpkgs = {
-      enable = true;
-      systemName = "x86_64-linux";
-    };
-    users = {
-      enable = true;
-      enableDeprecatedPlugdev = true;
-      hashedPassword = "$y$jFT$3qI9MYLDHPUdGKsVa8skV0$TOjX0SFHWuj52zd7/kmkNtG5EqQwYcqv0FKXWbLaro6";
-    };
-  };
-
-  system.stateVersion = "23.05";
-}
diff --git a/hosts/by-name/apzu/configuration.nix b/hosts/by-name/apzu/configuration.nix
new file mode 100644
index 00000000..a5b10e9f
--- /dev/null
+++ b/hosts/by-name/apzu/configuration.nix
@@ -0,0 +1,60 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{...}: {
+  imports = [
+    ./hardware.nix
+  ];
+
+  soispha = {
+    bluetooth.enable = true;
+
+    laptop = {
+      backlight = "intel_backlight";
+      enable = true;
+    };
+
+    impermanence.directories = [
+      "/var/log"
+    ];
+
+    programs = {
+      river.init = {
+        mappings = {
+          layout = "dvorak-modified";
+        };
+        screenSetupCode = {};
+      };
+    };
+
+    locale.enable = true;
+    networking = {
+      enable = true;
+      hostName = "apzu";
+      mode = "NetworkManager";
+    };
+
+    services = {
+      unison.foreign.address = "tiamat.fritz.box";
+      upower.enable = true;
+    };
+
+    nixpkgs = {
+      enable = true;
+      systemName = "x86_64-linux";
+    };
+    users = {
+      enable = true;
+      enableDeprecatedPlugdev = true;
+      hashedPassword = "$y$jFT$3qI9MYLDHPUdGKsVa8skV0$TOjX0SFHWuj52zd7/kmkNtG5EqQwYcqv0FKXWbLaro6";
+    };
+  };
+
+  system.stateVersion = "23.05";
+}
diff --git a/hosts/apzu/hardware.nix b/hosts/by-name/apzu/hardware.nix
index 8d481fa6..8d481fa6 100644
--- a/hosts/apzu/hardware.nix
+++ b/hosts/by-name/apzu/hardware.nix
diff --git a/hosts/by-name/tiamat/configuration.nix b/hosts/by-name/tiamat/configuration.nix
new file mode 100644
index 00000000..18393543
--- /dev/null
+++ b/hosts/by-name/tiamat/configuration.nix
@@ -0,0 +1,79 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  lib,
+  pkgs,
+  system,
+  libraries,
+  externalBinaries,
+  ...
+}: {
+  imports = [
+    ./hardware.nix
+  ];
+
+  soispha = {
+    bluetooth = {enable = true;};
+    networking = {
+      enable = true;
+      hostName = "tiamat";
+      mode = "systemd-networkd";
+    };
+    nixpkgs = {
+      enable = true;
+      systemName = "x86_64-linux";
+    };
+
+    # TODO: Hard-code all the uids/gids <2025-05-13>
+    impermanence.directories = [
+      "/var/lib/nixos"
+      "/var/log"
+    ];
+
+    services = {
+      unison.foreign.address = "apzu.fritz.box";
+    };
+    programs = {
+      river = {
+        unicodeInput.enable = true;
+        init = {
+          mappings = {
+            layout = "us";
+            keymap = {
+              # Support Unicode input
+              "<Alt+Ctrl+Meta+Shift-Z>" = [
+                "spawn"
+                "${lib.getExe externalBinaries.qmk_firmware.packages.${system}.qmk_unicode_type} 106 65377"
+              ];
+            };
+          };
+          screenSetupCode = {
+            "DP-2" = {pos = "2560,0";};
+            "DP-1" = {
+              scale = "1.5";
+              pos = "0,0";
+            };
+          };
+        };
+      };
+    };
+    locale = {
+      enable = true;
+      keyMap = "us";
+    };
+    users = {
+      enable = true;
+      enableDeprecatedPlugdev = true;
+      hashedPassword = "$y$jFT$qi3wS9njrMl2y55b3NOBI0$j40Qt6AAkMSfZ82KPhqMaUaPztWtPps1wOqaXaF/L.6";
+    };
+  };
+
+  system.stateVersion = "23.05";
+}
diff --git a/hosts/tiamat/hardware.nix b/hosts/by-name/tiamat/hardware.nix
index 2b18a662..2b18a662 100644
--- a/hosts/tiamat/hardware.nix
+++ b/hosts/by-name/tiamat/hardware.nix
diff --git a/hosts/default.nix b/hosts/default.nix
new file mode 100644
index 00000000..64768074
--- /dev/null
+++ b/hosts/default.nix
@@ -0,0 +1,61 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  self,
+  system,
+  openPRsNixpkgs,
+  packageSets,
+  libraries,
+  modules,
+  externalDependencies,
+  externalBinaries,
+}: let
+  hosts = libraries.extra.mkByName {
+    useShards = false;
+    baseDirectory = ./by-name;
+    fileName = "configuration.nix";
+  };
+
+  generateHost = _: path:
+    self.inputs.nixpkgs.lib.nixosSystem {
+      specialArgs = {
+        inherit
+          libraries
+          modules
+          self
+          ;
+      };
+      modules = [
+        {
+          _module.args = {
+            inherit
+              # extra package sources
+              openPRsNixpkgs
+              packageSets
+              # extra information
+              system
+              # nix registry
+              externalDependencies
+              # bins
+              # TODO: Integrate these into `pkgs/by-name` <2024-05-22>
+              externalBinaries
+              ;
+          };
+        }
+        path
+
+        ../modules
+        ../modules/common
+      ];
+    };
+
+  generatedHosts = builtins.mapAttrs generateHost hosts;
+in
+  generatedHosts
diff --git a/hosts/tiamat/default.nix b/hosts/tiamat/default.nix
deleted file mode 100644
index 794b8390..00000000
--- a/hosts/tiamat/default.nix
+++ /dev/null
@@ -1,144 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  lib,
-  pkgs,
-  baseLib,
-  qmk_firmware,
-  system,
-  ...
-}: {
-  imports = [
-    ./hardware.nix
-  ];
-
-  soispha = {
-    bluetooth = {enable = true;};
-    networking = {
-      enable = true;
-      hostName = "tiamat";
-      mode = "systemd-networkd";
-    };
-    nixpkgs = {
-      enable = true;
-      systemName = "x86_64-linux";
-    };
-    services = {
-      unison.foreign.address = "apzu.fritz.box";
-    };
-    programs = {
-      river = {
-        unicodeInput.enable = true;
-        init = {
-          mappings = {
-            layout = "us";
-            keymap = let
-              map = key: "<Alt+Ctrl+Meta+Shift-${key}>";
-            in
-              (lib.mapAttrs' (name: value: lib.nameValuePair (map name) value) {
-                # Movement
-                "A" = {command = ["exit"];};
-                "B" = {command = ["close"];};
-
-                "C" = {command = ["focus-view" "previous"];};
-                "D" = {command = ["focus-view" "next"];};
-
-                "E" = {command = ["swap" "previous"];};
-                "F" = {command = ["swap" "next"];};
-
-                "G" = {command = ["zoom"];};
-
-                "H" = {command = ["toggle-fullscreen"];};
-                "I" = {command = ["toggle-float"];};
-
-                "J" = {command = ["send-to-output" "next"];};
-
-                "K" = {command = ["spawn" "${lib.getExe pkgs.alacritty}"];};
-                "L" = {command = ["spawn" "${lib.getExe pkgs.screenshot_persistent}"];};
-
-                # Audio
-                # "M" = {command = ["spawn" "video-pause toggle"]; modes = ["normal" "locked"]; };
-                "N" = {
-                  command = ["spawn" "${lib.getExe pkgs.mpc} toggle"];
-                  modes = ["normal" "locked"];
-                };
-
-                # Launcher
-                "O" = {command = ["spawn" "${lib.getExe pkgs.rofi} -show combi -modes combi -combi-modes 'window,drun,run' -show-icons"];};
-                "P" = {command = ["spawn" "${lib.getExe pkgs.tskm} open select"];};
-                "Q" = {command = ["spawn" "${lib.getExe pkgs.keepassxc}"];};
-                # "R" = {command = ["spawn" "nheko"];};
-                "S" = {command = ["spawn" "${lib.getExe pkgs.signal-desktop}"];};
-                "T" = {command = ["spawn" "${lib.getExe pkgs.lock}"];};
-
-                "U" = {command = ["focus-output" "next"];};
-                "V" = {command = ["focus-previous-tags"];};
-                "W" = {command = ["send-to-previous-tags"];};
-                # "X" = {command = ["spawn" "bemenu-run"];};
-                # "Y" = {command = ["spawn" "bemenu-run"];};
-
-                # Toggle all tags
-                "0" = {command = ["set-focused-tags" "${builtins.toString ((baseLib.pow 2 32) - 1)}"];};
-
-                # Support Unicode input
-                "Z" = {command = ["spawn" "${lib.getExe qmk_firmware.packages.${system}.qmk_unicode_type} 106 65377"];};
-              })
-              // ({
-                  # TODO: add toggle-focus mapping
-
-                  # Toggle all tags
-                  "<Alt+Ctrl+Shift-0>" = {command = ["set-view-tags" "${builtins.toString ((baseLib.pow 2 32) - 1)}"];};
-
-                  # Mouse
-                  "<Meta-<MOUSE_LEFT>>" = {
-                    command = ["move-view"];
-                    map_mode = "MapMouse";
-                  };
-                  "<Meta-<MOUSE_RIGHT>>" = {
-                    command = ["resize-view"];
-                    map_mode = "MapMouse";
-                  };
-                }
-                // (
-                  builtins.foldl' (acc: elem: acc // elem) {} (
-                    builtins.map (index: let
-                      num = builtins.toString index;
-                      index2tag = input: builtins.toString (baseLib.pow 2 (input - 1));
-                    in {
-                      "${map num}" = {command = ["set-focused-tags" (index2tag index)];};
-                      "<Alt+Ctrl+Shift-${num}>" = {command = ["set-view-tags" (index2tag index)];};
-                      # "<Super+Shift+Ctrl-${num}>" = {command = ["toggle-view-tags" (index2tag index)];};
-                    }) (builtins.genList (i: i + 1) 9)
-                  )
-                ));
-          };
-          screenSetupCode = {
-            "DP-2" = {pos = "2560,0";};
-            "DP-1" = {
-              scale = "1.5";
-              pos = "0,0";
-            };
-          };
-        };
-      };
-    };
-    locale = {
-      enable = true;
-      keyMap = "us";
-    };
-    users = {
-      enable = true;
-      enableDeprecatedPlugdev = true;
-      hashedPassword = "$y$jFT$qi3wS9njrMl2y55b3NOBI0$j40Qt6AAkMSfZ82KPhqMaUaPztWtPps1wOqaXaF/L.6";
-    };
-  };
-
-  system.stateVersion = "23.05";
-}
diff --git a/lib/default.nix b/lib/default.nix
index d84ac5e2..1cdbf936 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -7,7 +7,7 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{lib}: let
+{lib}: rec {
   /*
   Converts `number` from a binary number to a decimal one.
 
@@ -101,6 +101,26 @@
     else if power > 0
     then (base * (pow base (power - 1)))
     else builtins.throw "Negative powers are not supported";
-in {
-  inherit binaryToDecimal idFromString pow;
+
+  options = {
+    /*
+    Generate an enable option definition, that defaults to true.
+
+    This conveniently allows the composition of a “common” module set.
+
+    # Type
+
+    mkEnable :: String -> AttrSet
+
+    # Arguments
+
+    name
+    : The name to use in the option description.
+    */
+    mkEnable = name:
+      (lib.mkEnableOption name)
+      // {
+        default = true;
+      };
+  };
 }
diff --git a/modules/by-name/ad/adb/module.nix b/modules/by-name/ad/adb/module.nix
index 71bd3c9b..89cb1439 100644
--- a/modules/by-name/ad/adb/module.nix
+++ b/modules/by-name/ad/adb/module.nix
@@ -10,6 +10,7 @@
 {
   lib,
   config,
+  pkgs,
   ...
 }: let
   cfg = config.soispha.services.adb;
@@ -25,7 +26,13 @@ in {
   };
 
   config = lib.mkIf cfg.enable {
-    programs.adb.enable = true;
-    users.users."${cfg.user}".extraGroups = ["adbusers"];
+    environment.systemPackages = [
+      pkgs.android-tools
+    ];
+
+    users = {
+      users."${cfg.user}".extraGroups = ["adbusers"];
+      groups.adbusers.gid = config.soispha.constants.ids.gids.adbusers;
+    };
   };
 }
diff --git a/modules/by-name/ag/age/module.nix b/modules/by-name/ag/age/module.nix
new file mode 100644
index 00000000..9a498ab6
--- /dev/null
+++ b/modules/by-name/ag/age/module.nix
@@ -0,0 +1,25 @@
+{
+  config,
+  lib,
+  modules,
+  pkgs,
+  ...
+}: let
+  cfg = config.soispha.age;
+in {
+  options.soispha.age = {
+    enable = lib.mkEnableOption "secret management with age";
+  };
+
+  imports = [
+    modules.agenix.nixosModules.default
+  ];
+
+  config = lib.mkIf cfg.enable {
+    age = {
+      # TODO(@bpeetz): Set once <https://github.com/ryantm/agenix/pull/317/files> is merged. <2025-05-16>
+      # enable = true;
+      ageBin = lib.getExe pkgs.rage;
+    };
+  };
+}
diff --git a/modules/by-name/al/alacritty/module.nix b/modules/by-name/al/alacritty/module.nix
new file mode 100644
index 00000000..73860a57
--- /dev/null
+++ b/modules/by-name/al/alacritty/module.nix
@@ -0,0 +1,468 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  config,
+  lib,
+  pkgs,
+  libraries,
+  ...
+}: let
+  cfg = config.soispha.programs.alacritty;
+in {
+  options.soispha.programs.alacritty = {
+    enable = libraries.base.options.mkEnable "alacritty";
+
+    package = lib.mkPackageOption pkgs "alacritty" {};
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      home.sessionVariables = {
+        # This is **not** the TERM variable but a special one to signify my favorite terminal.
+        TERMINAL = "alacritty";
+      };
+
+      programs.alacritty = {
+        enable = true;
+        inherit (cfg) package;
+
+        settings = {
+          bell = {
+            duration = 0;
+          };
+
+          colors = builtins.fromTOML (builtins.readFile ./theme.toml);
+
+          cursor = {
+            blink_interval = 750;
+            blink_timeout = 5;
+            style = {
+              blinking = "On";
+              shape = "Beam";
+            };
+            thickness = 0.15;
+            unfocused_hollow = true;
+            vi_mode_style = "None";
+          };
+
+          env = {
+            COLORTERM = "truecolor";
+            TERM = "alacritty";
+          };
+
+          font = {
+            builtin_box_drawing = true;
+            glyph_offset = {
+              x = -1;
+              y = -1;
+            };
+            normal = {
+              family = "SauceCodePro Nerd Font Mono";
+              style = "Regular";
+            };
+            offset = {
+              x = -1;
+              y = -1;
+            };
+            size = 12;
+          };
+
+          general = {
+            ipc_socket = true;
+            live_config_reload = true;
+          };
+
+          hints = {
+            alphabet = "jfkdls;ahgurieowpq";
+            enabled = [
+              {
+                binding = {
+                  key = "U";
+                  mods = "Control|Shift";
+                };
+                command = "xdg-open";
+                hyperlinks = true;
+                mouse = {
+                  enabled = true;
+                };
+                persist = false;
+                post_processing = true;
+                regex = "(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)[^\\u0000-\\u001F\\u007F-\\u009F<>\"\\\\s{-}\\\\^⟨⟩`]+";
+              }
+              {
+                action = "Paste";
+                binding = {
+                  key = "T";
+                  mods = "Control|Shift";
+                };
+                post_processing = false;
+                regex = "([^ '\"`=:\\\\[\\\\(]*/)([^/: '\"`\\\\)\\\\]]*)";
+              }
+              {
+                action = "Paste";
+                binding = {
+                  key = "H";
+                  mods = "Control|Shift";
+                };
+                post_processing = false;
+                regex = ''([a-z0-9]{7,40})\\s'';
+              }
+            ];
+          };
+
+          keyboard = {
+            bindings = [
+              {
+                action = "Paste";
+                key = "P";
+                mods = "Control";
+              }
+              {
+                action = "Paste";
+                key = "Insert";
+                mods = "Shift";
+              }
+              {
+                chars = "gc";
+                key = "Slash";
+                mods = "Control";
+              }
+              {
+                action = "Copy";
+                key = "Y";
+                mods = "Control";
+              }
+              {
+                action = "ResetFontSize";
+                key = "Key0";
+                mods = "Control";
+              }
+              {
+                action = "IncreaseFontSize";
+                key = "Equals";
+                mods = "Control";
+              }
+              {
+                action = "IncreaseFontSize";
+                key = "Plus";
+                mods = "Control";
+              }
+              {
+                action = "DecreaseFontSize";
+                key = "Minus";
+                mods = "Control";
+              }
+              {
+                action = "ToggleViMode";
+                key = "Space";
+                mods = "Control";
+              }
+              {
+                action = "ScrollToBottom";
+                key = "Space";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ScrollToBottom";
+                key = "I";
+                mode = "Vi";
+              }
+              {
+                action = "ToggleViMode";
+                key = "I";
+                mode = "Vi";
+              }
+              {
+                action = "ScrollToBottom";
+                key = "C";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ToggleViMode";
+                key = "C";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ClearSelection";
+                key = "Escape";
+                mode = "Vi";
+              }
+              {
+                action = "ScrollLineUp";
+                key = "Y";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ScrollLineDown";
+                key = "E";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ScrollToTop";
+                key = "G";
+                mode = "Vi";
+              }
+              {
+                action = "ScrollToBottom";
+                key = "G";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "ScrollPageUp";
+                key = "B";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ScrollPageDown";
+                key = "F";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ScrollHalfPageUp";
+                key = "U";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ScrollHalfPageDown";
+                key = "D";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "Copy";
+                key = "Y";
+                mode = "Vi";
+              }
+              {
+                action = "ClearSelection";
+                key = "Y";
+                mode = "Vi";
+              }
+              {
+                action = "ToggleNormalSelection";
+                key = "V";
+                mode = "Vi";
+              }
+              {
+                action = "ToggleLineSelection";
+                key = "V";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "ToggleBlockSelection";
+                key = "V";
+                mode = "Vi";
+                mods = "Control";
+              }
+              {
+                action = "ToggleSemanticSelection";
+                key = "V";
+                mode = "Vi";
+                mods = "Alt";
+              }
+              {
+                action = "Open";
+                key = "Return";
+                mode = "Vi";
+              }
+              {
+                action = "Up";
+                key = "K";
+                mode = "Vi";
+              }
+              {
+                action = "Down";
+                key = "J";
+                mode = "Vi";
+              }
+              {
+                action = "Left";
+                key = "H";
+                mode = "Vi";
+              }
+              {
+                action = "Right";
+                key = "L";
+                mode = "Vi";
+              }
+              {
+                action = "Up";
+                key = "Up";
+                mode = "Vi";
+              }
+              {
+                action = "Down";
+                key = "Down";
+                mode = "Vi";
+              }
+              {
+                action = "Left";
+                key = "Left";
+                mode = "Vi";
+              }
+              {
+                action = "Right";
+                key = "Right";
+                mode = "Vi";
+              }
+              {
+                action = "First";
+                key = "Key0";
+                mode = "Vi";
+              }
+              {
+                action = "Last";
+                key = "Key4";
+                mode = "Vi";
+              }
+              {
+                action = "FirstOccupied";
+                key = "Key6";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "High";
+                key = "H";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "Middle";
+                key = "M";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "Low";
+                key = "L";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "SemanticLeft";
+                key = "B";
+                mode = "Vi";
+              }
+              {
+                action = "SemanticRight";
+                key = "W";
+                mode = "Vi";
+              }
+              {
+                action = "SemanticRightEnd";
+                key = "E";
+                mode = "Vi";
+              }
+              {
+                action = "WordLeft";
+                key = "B";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "WordRight";
+                key = "W";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "WordRightEnd";
+                key = "E";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "Bracket";
+                key = "Key5";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "SearchForward";
+                key = "Slash";
+                mode = "Vi";
+              }
+              {
+                action = "SearchBackward";
+                key = "Slash";
+                mode = "Vi";
+                mods = "Shift";
+              }
+              {
+                action = "SearchNext";
+                key = "N";
+                mode = "Vi";
+              }
+              {
+                action = "SearchPrevious";
+                key = "N";
+                mode = "Vi";
+                mods = "Shift";
+              }
+            ];
+          };
+
+          mouse = {
+            bindings = [
+              {
+                action = "Copy";
+                mouse = "Middle";
+              }
+            ];
+            hide_when_typing =
+              false;
+          };
+
+          scrolling = {
+            history = 10000;
+            multiplier = 3;
+          };
+
+          selection = {
+            save_to_clipboard = false;
+            semantic_escape_chars = ",│`|:\"' ()[]{}<>\t";
+          };
+
+          window = {
+            class = {
+              general = "Alacritty";
+              instance = "Alacritty";
+            };
+            decorations = "none";
+            decorations_theme_variant = "None";
+            dimensions = {
+              columns = 0;
+              lines = 0;
+            };
+            dynamic_title = true;
+            opacity = 0.9;
+            padding = {
+              x = 5;
+              y = 5;
+            };
+            startup_mode = "Windowed";
+            title = "Alacritty";
+          };
+        };
+      };
+    };
+  };
+}
diff --git a/modules/home.legacy/conf/alacritty/toml/colorscheme.toml b/modules/by-name/al/alacritty/theme.toml
index 13c796c9..2b326e43 100644
--- a/modules/home.legacy/conf/alacritty/toml/colorscheme.toml
+++ b/modules/by-name/al/alacritty/theme.toml
@@ -12,45 +12,45 @@
 ## name: carbonfox
 ## upstream: https://github.com/edeneast/nightfox.nvim/raw/main/extra/carbonfox/alacritty.toml
 
-[colors.primary]
+[primary]
 background = "#161616"
 foreground = "#f2f4f8"
 dim_foreground = "#b6b8bb"
 bright_foreground = "#f9fbff"
 
-[colors.cursor]
+[cursor]
 text = "#f2f4f8"
 cursor = "#b6b8bb"
 
-[colors.vi_mode_cursor]
+[vi_mode_cursor]
 text = "#f2f4f8"
 cursor = "#33b1ff"
 
-[colors.search.matches]
+[search.matches]
 foreground = "#f2f4f8"
 background = "#525253"
 
-[colors.search.focused_match]
+[search.focused_match]
 foreground = "#f2f4f8"
 background = "#3ddbd9"
 
-[colors.footer_bar]
+[footer_bar]
 foreground = "#f2f4f8"
 background = "#353535"
 
-[colors.hints.start]
+[hints.start]
 foreground = "#f2f4f8"
 background = "#3ddbd9"
 
-[colors.hints.end]
+[hints.end]
 foreground = "#f2f4f8"
 background = "#353535"
 
-[colors.selection]
+[selection]
 text = "#f2f4f8"
 background = "#2a2a2a"
 
-[colors.normal]
+[normal]
 black = "#282828"
 red = "#ee5396"
 green = "#25be6a"
@@ -60,7 +60,7 @@ magenta = "#be95ff"
 cyan = "#33b1ff"
 white = "#dfdfe0"
 
-[colors.bright]
+[bright]
 black = "#484848"
 red = "#f16da6"
 green = "#46c880"
@@ -70,7 +70,7 @@ magenta = "#c8a5ff"
 cyan = "#52bdff"
 white = "#e4e4e5"
 
-[colors.dim]
+[dim]
 black = "#222222"
 red = "#ca4780"
 green = "#1fa25a"
@@ -80,10 +80,10 @@ magenta = "#a27fd9"
 cyan = "#2b96d9"
 white = "#bebebe"
 
-[[colors.indexed_colors]]
+[[indexed_colors]]
 index = 16
 color = "#3ddbd9"
 
-[[colors.indexed_colors]]
+[[indexed_colors]]
 index = 17
 color = "#ff7eb6"
diff --git a/modules/by-name/at/atuin/module.nix b/modules/by-name/at/atuin/module.nix
index 1aec2e74..700f50fb 100644
--- a/modules/by-name/at/atuin/module.nix
+++ b/modules/by-name/at/atuin/module.nix
@@ -17,10 +17,12 @@
 in {
   options.soispha.programs.atuin = {
     enable = lib.mkEnableOption "atuin";
+
+    enableAge = lib.mkEnableOption "atuin with age keys";
   };
 
   config = lib.mkIf cfg.enable {
-    age.secrets.atuin_encryption_key = {
+    age.secrets.atuin_encryption_key = lib.mkIf cfg.enableAge {
       file = ./secrets/encryption_key.age;
       mode = "700";
       owner = "soispha";
@@ -37,12 +39,18 @@ in {
         # We can do this on our own.
         enableZshIntegration = false;
         settings = {
-          key_path = "${config.age.secrets.atuin_encryption_key.path}";
+          key_path = lib.mkMerge [
+            (lib.mkIf cfg.enableAge "${config.age.secrets.atuin_encryption_key.path}")
+            (lib.mkIf (!cfg.enableAge)
+              "${config.home-manager.users.soispha.xdg.dataHome}/atuin/atuin_secret_key.key")
+          ];
 
-          # TODO: Setup a self-hosted sync server. <2024-10-18>
-          session_path = "";
-          auto_sync = false;
-          sync_address = "";
+          sync = lib.mkIf cfg.enableAge {
+            # The v2 sync API
+            records = true;
+          };
+          auto_sync = lib.mkIf cfg.enableAge true;
+          sync_address = lib.mkIf cfg.enableAge "https://atuin-sync.vhack.eu";
 
           # Use the rather reasonable syntax of `skim` to search.
           search_mode = "skim";
diff --git a/modules/by-name/ba/backup/module.nix b/modules/by-name/ba/backup/module.nix
index 3e07fbd1..7a788764 100644
--- a/modules/by-name/ba/backup/module.nix
+++ b/modules/by-name/ba/backup/module.nix
@@ -11,78 +11,177 @@
   lib,
   config,
   pkgs,
+  libraries,
   ...
 }: let
   cfg = config.soispha.services.backup;
+
+  snapshotDir = "/srv/last_snapshot";
 in {
   options.soispha.services.backup = {
-    enable = lib.mkEnableOption "backups via restic to a storagebox";
+    enable = libraries.base.options.mkEnable "backups via restic";
 
-    user = lib.mkOption {
-      type = lib.types.str;
-      description = "The storagebox-user to use";
-      example = "u384702-sub2";
-    };
-    privateSshKey = lib.mkOption {
-      type = lib.types.path;
-      description = "The age-encrypted ssh-key, passed to agenix";
+    storagebox = {
+      enable = lib.mkEnableOption "remote backups";
+      user = lib.mkOption {
+        type = lib.types.str;
+        description = "The storagebox-user to use";
+        example = "u384702-sub2";
+      };
+
+      sshKey = lib.mkOption {
+        type = lib.types.path;
+        description = "The age-encrypted ssh-key, passed to agenix";
+        default = ./secrets/storagebox/ssh_key.age;
+      };
+
+      repositoryPassword = lib.mkOption {
+        type = lib.types.path;
+        description = "The age-encrypted restic password, passed to agenix";
+        default = ./secrets/storagebox/repository_password.age;
+      };
     };
-    privatePassword = lib.mkOption {
-      type = lib.types.path;
-      description = "The age-encrypted restic password, passed to agenix";
+
+    local = {
+      enable = lib.mkEnableOption "local backups";
+
+      repositoryPassword = lib.mkOption {
+        type = lib.types.path;
+        description = "The age-encrypted restic password, passed to agenix";
+        default = ./secrets/local/repository_password.age;
+      };
+
+      backupMountPoint = lib.mkOption {
+        type = lib.types.path;
+        description = "The path where to expect the mounted backup disk";
+        default = "/mnt/backup";
+      };
     };
   };
 
   config = lib.mkIf cfg.enable {
+    soispha.impermanence.directories = lib.mkMerge [
+      (lib.mkIf cfg.storagebox.enable [
+        "/var/cache/restic-backups-storagebox"
+      ])
+      (lib.mkIf cfg.local.enable [
+        "/var/cache/restic-backups-local"
+      ])
+    ];
+
     age.secrets = {
-      resticpass = {
-        file = cfg.privatePassword;
+      resticStorageboxSshKey = lib.mkIf cfg.storagebox.enable {
+        file = cfg.storagebox.sshKey;
         mode = "0700";
         owner = "root";
         group = "root";
       };
-      resticssh = {
-        file = cfg.privateSshKey;
+      resticStorageboxRepositoryPassword = lib.mkIf cfg.storagebox.enable {
+        file = cfg.storagebox.repositoryPassword;
+        mode = "0700";
+        owner = "root";
+        group = "root";
+      };
+      resticLocalRepositoryPassword = lib.mkIf cfg.local.enable {
+        file = cfg.local.repositoryPassword;
         mode = "0700";
         owner = "root";
         group = "root";
       };
     };
 
-    soispha.programs.ssh = {
+    soispha.programs.ssh = lib.mkIf cfg.storagebox.enable {
       enable = true;
       rootKnownHosts = {
         "[u459143-sub1.your-storagebox.de]:23" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIICf9svRenC/PLKIL9nk6K/pxQgoiFC41wTNvoIncOxs";
       };
     };
 
+    systemd.services = {
+      prepare-backup = {
+        requires = [];
+        after = [];
+
+        description = "Prepare a backup by snapshotting the system.";
+
+        serviceConfig = {
+          ExecStart = lib.getExe (pkgs.writeShellApplication {
+            name = "prepareBackup";
+            text = ''
+              set -x
+
+              [ -d "${snapshotDir}" ] && btrfs subvolume delete "${snapshotDir}"
+
+              # -r := Make the snapshot read-only
+              btrfs subvolume snapshot -r /srv "${snapshotDir}";
+            '';
+
+            inheritPath = false;
+            runtimeInputs = [
+              pkgs.btrfs-progs
+            ];
+          });
+
+          Type = "oneshot";
+
+          User = "root";
+          Group = "root";
+
+          # TODO: Hardening <2025-05-04>
+        };
+      };
+
+      restic-backups-storagebox = lib.mkIf cfg.storagebox.enable {
+        requires = ["prepare-backup.service"];
+        after = ["prepare-backup.service"];
+      };
+
+      restic-backups-local = lib.mkIf cfg.local.enable {
+        requires = ["prepare-backup.service"];
+        after = ["prepare-backup.service"];
+
+        serviceConfig = {
+          ConditionPathIsDirectory = "${cfg.local.backupMountPoint}";
+        };
+      };
+    };
+
     services.restic.backups = let
-      snapshotDir = "/srv/last_snapshot";
       homeDir = "${snapshotDir}/home";
+
+      paths = [
+        snapshotDir
+      ];
+      exclude = [
+        "${homeDir}/soispha/.cache"
+      ];
+      extraBackupArgs = [
+        "--verbose=2"
+      ];
     in {
-      storagebox = {
+      local = lib.mkIf cfg.local.enable {
+        inhibitsSleep = true;
         initialize = true;
-        backupPrepareCommand =
-          # bash
-          ''
-            [ -d "${snapshotDir}" ] && ${lib.getExe' pkgs.btrfs-progs "btrfs"} subvolume delete "${snapshotDir}"
-
-            # -r := Make the snapshot read-only
-            ${lib.getExe' pkgs.btrfs-progs "btrfs"} subvolume snapshot -r /srv "${snapshotDir}";
-          '';
-        paths = [
-          snapshotDir
-        ];
-        exclude = [
-          "${homeDir}/soispha/.cache"
-        ];
-        extraBackupArgs = [
-          "--verbose=2"
-        ];
 
-        passwordFile = config.age.secrets.resticpass.path;
+        inherit paths exclude extraBackupArgs;
+
+        passwordFile = config.age.secrets.resticLocalRepositoryPassword.path;
+
+        repository = "${cfg.local.backupMountPoint}/restic-backup-data/";
+
+        # Start on demand.
+        timerConfig = null;
+      };
+
+      storagebox = lib.mkIf cfg.storagebox.enable {
+        inhibitsSleep = true;
+        initialize = true;
+
+        inherit paths exclude extraBackupArgs;
+
+        passwordFile = config.age.secrets.resticStorageboxRepositoryPassword.path;
         extraOptions = [
-          "rclone.program='ssh -p 23 ${cfg.user}@${cfg.user}.your-storagebox.de -i ${config.age.secrets.resticssh.path} command_forced_on_remote'"
+          "rclone.program='ssh -p 23 ${cfg.storagebox.user}@${cfg.storagebox.user}.your-storagebox.de -i ${config.age.secrets.resticStorageboxSshKey.path} command_forced_on_remote'"
         ];
 
         # This setting is normally passed to rclone, but we force
@@ -97,6 +196,24 @@ in {
           Persistent = true;
         };
       };
+
+      # This is only for listing, pruning and such stuff.
+      storagebox-admin = lib.mkIf cfg.storagebox.enable {
+        inhibitsSleep = false;
+        initialize = false;
+
+        passwordFile = config.age.secrets.resticStorageboxRepositoryPassword.path;
+        extraOptions = [
+          "rclone.program='ssh -p 23 ${cfg.storagebox.user}@${cfg.storagebox.user}.your-storagebox.de command_forced_on_remote'"
+        ];
+
+        # This setting is normally passed to rclone, but we force
+        # the command on the remote.
+        # As such, the value does not matter and must only be parseable by restic.
+        repository = "rclone: ";
+
+        timerConfig = null;
+      };
     };
   };
 }
diff --git a/modules/by-name/ba/backup/secrets/local/repository_password.age b/modules/by-name/ba/backup/secrets/local/repository_password.age
new file mode 100644
index 00000000..b1508e49
--- /dev/null
+++ b/modules/by-name/ba/backup/secrets/local/repository_password.age
@@ -0,0 +1,20 @@
+-----BEGIN AGE ENCRYPTED FILE-----
+YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqVCtBZzNBWFlxQnhlb3c2
+NG0xMjV3V2hQUWhNb01ROGpFbzM0c3NjRWlvCjRqMTdxNlNsY1lDM2VCUGRjcldZ
+SUhScGRSejY3TFlwVjlweTRERkU4ZTQKLT4gc3NoLWVkMjU1MTkgelpFb25nIGtj
+cVN4RzFseTJCVXhOc0tEWi96ckpGQjhNdUZrb1FVWnJ6TU1vSHZCMUkKc1JwM2Ir
+TzNzZEV5VEE4QUp4cDdTNWZvTFlZR0tUbUFZTnNEZE1McnhISQotPiBzc2gtZWQy
+NTUxOSA3SGZGVXcgYVQzRHdaa1NYUUpLODUyL0orV3d4Z1o1V2hhekZXVWFzNW50
+enhSYnlWbwpzbnZwK1dSczJ5SGZsRjNyRWZraUcreWlBakZOZkVyZ01CWml5V0E4
+TzY4Ci0+ICpMUC1ncmVhc2UgV0IKUTZVMzR1QTVGdWRyNWprVVpjaWhCTTFSRzY3
+bHVtdHpJQXlWQVFHZ3FzbkZncHRsQnJIaHlEekl5ZE15Sko0YQpSVEUKLS0tIGFy
+N1Y2OUREY1NOL2xPODd4Y3Y4Wk83NFJ5ZVBpNnJYelo3RmZPL1V4Q28KcA+6qt2d
+LrL0FS279XL1uqSeXiDdBBBh5i951dRx9ML33g7IoQxaGqSWU0yP/y7fcSp3B/rT
+/alQGRL/uYnCS2z8zCngr2YCQBXAI8bOgf+th7fzc15FXNB14WMGvrCVRB8Rr6JZ
+itTxcAebY192xeINJG269iL6Ef0YrmZLUufKQ9lcVob/G32tG0vxSbSBBx3asf7y
+toiNdlXpxJPrIpFx5mc3dnkaXCTSRuXjiAqnncW/HNxovCI90sY3dyL+XRC8iEOD
+sql7C7jUUvLubptk1gGW5pHmGvqeCLr+fJ6XrVqXE5VxOSbzvSUsdS84WOBInLiO
+V36aUtthEzdRXd81P/n7U26O93GWpIwzctu0WwSHHHsPKhxqFY4RuWa3mO4Zk6fu
+O6fsYnpAqYiCUd/k2zKrDtLosTnwuwc7Vm1glm4DEEtvteVibw47SR1LLfUds5XL
+j1OR7Z6/ljIEKPjE1a81pQjYRfHDUtceXUvrlL6iCID30zU=
+-----END AGE ENCRYPTED FILE-----
diff --git a/modules/common/secrets/backup/privatePassword.age b/modules/by-name/ba/backup/secrets/storagebox/repository_password.age
index a2aa984a..a2aa984a 100644
--- a/modules/common/secrets/backup/privatePassword.age
+++ b/modules/by-name/ba/backup/secrets/storagebox/repository_password.age
diff --git a/modules/common/secrets/backup/privateSshKey.age b/modules/by-name/ba/backup/secrets/storagebox/ssh_key.age
index a7f30c7c..a7f30c7c 100644
--- a/modules/common/secrets/backup/privateSshKey.age
+++ b/modules/by-name/ba/backup/secrets/storagebox/ssh_key.age
diff --git a/modules/by-name/bo/boot/module.nix b/modules/by-name/bo/boot/module.nix
index 8b9ca6dd..4b95aedf 100644
--- a/modules/by-name/bo/boot/module.nix
+++ b/modules/by-name/bo/boot/module.nix
@@ -11,6 +11,7 @@
   config,
   lib,
   pkgs,
+  modules,
   ...
 }: let
   cfg = config.soispha.boot;
@@ -21,6 +22,10 @@ in {
     # enableIsoEntry = lib.mkEnableOption "an tails iso boot entry";
   };
 
+  imports = [
+    modules.lanzaboote.nixosModules.lanzaboote
+  ];
+
   config = lib.mkIf cfg.enable (
     # let
     # cfg = config.boot.loader.systemd-boot;
@@ -41,7 +46,7 @@ in {
     # #    stay on disk forever) <2024-05-11>
     # copyExtraFiles = ''
     #   echo "[systemd-boot] copying files to ${bootMountPoint}"
-    #   empty_file=$(mktemp)
+    #   empty_file=$(mktemp boot_empty_file_XXX)
     #
     #   ${lib.concatStrings (lib.mapAttrsToList (n: v:
     #     /*
@@ -79,7 +84,7 @@ in {
       # This should only be necessary for `lanzaboote`, but that is the current default in
       # this module.
       soispha.impermanence.directories = [
-        "/etc/secureboot"
+        "/var/lib/sbctl"
       ];
 
       boot = {
@@ -91,7 +96,7 @@ in {
 
         lanzaboote = {
           enable = true;
-          pkiBundle = "/etc/secureboot";
+          pkiBundle = "/var/lib/sbctl";
 
           settings = {
             # Disable editing the kernel command line (which could allow someone to become root)
diff --git a/modules/by-name/co/constants/module.nix b/modules/by-name/co/constants/module.nix
new file mode 100644
index 00000000..493ead1f
--- /dev/null
+++ b/modules/by-name/co/constants/module.nix
@@ -0,0 +1,59 @@
+# This file is inspired by the `nixos/modules/misc/ids.nix`
+# file in nixpkgs.
+{lib, ...}: {
+  options.soispha.constants = {
+    ids.uids = lib.mkOption {
+      internal = true;
+      description = ''
+        The user IDs used in this nixos config.
+      '';
+      type = lib.types.attrsOf (lib.types.ints.between 0 1000);
+    };
+    ids.gids = lib.mkOption {
+      internal = true;
+      description = ''
+        The group IDs used in this nixos config.
+      '';
+      type = lib.types.attrsOf (lib.types.ints.between 0 1000);
+    };
+  };
+
+  config.soispha.constants = {
+    ids.uids = {
+      # Keep this sorted with `!sort --numeric-sort --key=2 --field-separator="="`
+
+      wpa_supplicant = 986;
+      dhcpcd = 992;
+      systemd-oom = 993;
+      sshd = 994;
+      rtkit = 995;
+      nscd = 996;
+      nm-iodine = 997;
+      fwupd-refresh = 998;
+      avahi = 999;
+
+      # As per the NixOS file, the uids should not be greater or equal to 400;
+    };
+    ids.gids = {
+      # Please add your groups to the users and inherit them here.
+      # This avoids having an user/group id mismatch.
+
+      wpa_supplicant = 986;
+      dhcpcd = 987;
+      lpadmin = 988;
+      resolvconf = 989;
+      systemd-oom = 990;
+      systemd-coredump = 991;
+      sshd = 992;
+      rtkit = 993;
+      polkituser = 994;
+      nscd = 995;
+      msr = 996;
+      fwupd-refresh = 997;
+      avahi = 998;
+      adbusers = 999;
+
+      # The gid should match the uid. Thus should not be >= 400;
+    };
+  };
+}
diff --git a/modules/by-name/co/coredump/module.nix b/modules/by-name/co/coredump/module.nix
new file mode 100644
index 00000000..79e764eb
--- /dev/null
+++ b/modules/by-name/co/coredump/module.nix
@@ -0,0 +1,17 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.systemd.coredump;
+in {
+  options.soispha.systemd.coredump = {
+    enable = (lib.mkEnableOption "oomd") // {default = config.systemd.coredump.enable;};
+  };
+
+  config = lib.mkIf cfg.enable {
+    users = {
+      groups.systemd-coredump.gid = config.soispha.constants.ids.gids.systemd-coredump;
+    };
+  };
+}
diff --git a/modules/by-name/dh/dhcpcd/module.nix b/modules/by-name/dh/dhcpcd/module.nix
new file mode 100644
index 00000000..5fee0100
--- /dev/null
+++ b/modules/by-name/dh/dhcpcd/module.nix
@@ -0,0 +1,21 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.dhcpcd;
+in {
+  options.soispha.dhcpcd = {
+    enable = (lib.mkEnableOption "dhcpcd") // {default = config.networking.dhcpcd.enable;};
+  };
+
+  config = lib.mkIf cfg.enable {
+    users = {
+      users.dhcpcd = {
+        uid = config.soispha.constants.ids.uids.dhcpcd;
+        group = "dhcpcd";
+      };
+      groups.dhcpcd.gid = config.soispha.constants.ids.gids.dhcpcd;
+    };
+  };
+}
diff --git a/modules/by-name/di/disks/module.nix b/modules/by-name/di/disks/module.nix
index 7d5cb9bf..3e9d4614 100644
--- a/modules/by-name/di/disks/module.nix
+++ b/modules/by-name/di/disks/module.nix
@@ -11,12 +11,13 @@
   config,
   lib,
   pkgs,
+  modules,
   ...
 }: let
   # FIXME: The iso redeploy requires a bigger efi partition  <2024-05-12>
   cfg = config.soispha.disks;
   defaultMountOptions = [
-    "compress-force=zstd:15" # This saves disk space, at a performance cost
+    "compress=zstd:3" # This saves disk space, at a performance cost
     "noatime" # should have some performance upsides, and I don't use it anyways
     "lazytime" # make time changes in memory
   ];
@@ -46,6 +47,10 @@ in {
     };
   };
 
+  imports = [
+    modules.disko.nixosModules.default
+  ];
+
   config = lib.mkIf cfg.enable {
     systemd = lib.recursiveUpdate (import ./hibernate.nix {inherit pkgs;}) (import ./fstrim.nix {inherit pkgs lib cfg;});
 
@@ -81,7 +86,10 @@ in {
                       };
                       "swap" = {
                         mountpoint = "/swap";
-                        mountOptions = defaultMountOptions;
+                        mountOptions = [
+                          "noatime" # should have some performance upsides, and I don't use it anyways
+                          "lazytime" # make time changes in memory
+                        ];
                       };
                     };
                   };
@@ -104,11 +112,20 @@ in {
       nodev = {
         "/" = {
           fsType = "tmpfs";
-          mountOptions = ["defaults" "size=4G" "mode=755"];
+          mountOptions = ["defaults" "size=25%" "mode=0755"];
         };
         "/tmp" = {
           fsType = "tmpfs";
-          mountOptions = ["defaults" "size=16G" "mode=755"];
+          mountOptions = ["defaults" "size=50%" "mode=0755"];
+        };
+        "/nix/var/nix/b" = {
+          fsType = "tmpfs";
+          mountOptions = [
+            "defaults"
+            "noswap" # Otherwise, we might run into io-based slowdowns
+            "size=80%"
+            "mode=0755"
+          ];
         };
       };
     };
diff --git a/modules/by-name/fi/firefox/extensions.json b/modules/by-name/fi/firefox/extensions.json
deleted file mode 100644
index 062f1a5e..00000000
--- a/modules/by-name/fi/firefox/extensions.json
+++ /dev/null
@@ -1,50 +0,0 @@
-{
-  "darkreader": {
-    "addonId": "addon@darkreader.org",
-    "default_area": "navbar",
-    "pname": "darkreader",
-    "sha256": "sha256:f565b2263a71626a0310380915b7aef90be8cc6fe16ea43ac1a0846efedc2e4c",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4439735/darkreader-4.9.103.xpi",
-    "version": "4.9.103"
-  },
-  "keepassxc-browser": {
-    "addonId": "keepassxc-browser@keepassxc.org",
-    "default_area": "navbar",
-    "pname": "keepassxc-browser",
-    "sha256": "sha256:f4ecad9cabe70511fbff42fe4fe831c560cc3a0b6da10a740ce670f4f6597f42",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4441759/keepassxc_browser-1.9.7.xpi",
-    "version": "1.9.7"
-  },
-  "torproject-snowflake": {
-    "addonId": "{b11bea1f-a888-4332-8d8a-cec2be7d24b9}",
-    "default_area": "navbar",
-    "pname": "torproject-snowflake",
-    "sha256": "sha256:615c0d570f41e721a91fc4f334377a61732171b65eb1a4429d78681e85bc8878",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4458115/torproject_snowflake-0.9.3.xpi",
-    "version": "0.9.3"
-  },
-  "tridactyl-vim": {
-    "addonId": "tridactyl.vim@cmcaine.co.uk",
-    "default_area": "menupanel",
-    "pname": "tridactyl-vim",
-    "sha256": "sha256:807925f26aab56ab19a28e663ade73743a033e3b77aa09edd3f77bf92e5fb36e",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4405615/tridactyl_vim-1.24.2.xpi",
-    "version": "1.24.2"
-  },
-  "ublock-origin": {
-    "addonId": "uBlock0@raymondhill.net",
-    "default_area": "menupanel",
-    "pname": "ublock-origin",
-    "sha256": "sha256:d93176cef4dc042e41ba500aa2a90e5d57b5be77449cbd522111585e3a0cd158",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4458450/ublock_origin-1.63.2.xpi",
-    "version": "1.63.2"
-  },
-  "vhack-libredirect": {
-    "addonId": "vhack-libredirect@addons.vhack.eu",
-    "default_area": "navbar",
-    "pname": "vhack-libredirect",
-    "sha256": "sha256:08ccfd4b32ba15b357252208da7f383099ed5aefb9e92ffb5b9ae33f9146caf6",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4427811/vhack_libredirect-3.0.2.xpi",
-    "version": "3.0.2"
-  }
-}
diff --git a/modules/by-name/fi/firefox/extensions.json.license b/modules/by-name/fi/firefox/extensions.json.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/fi/firefox/extensions.json.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/fi/firefox/module.nix b/modules/by-name/fi/firefox/module.nix
deleted file mode 100644
index 9290f60a..00000000
--- a/modules/by-name/fi/firefox/module.nix
+++ /dev/null
@@ -1,243 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  lib,
-  config,
-  pkgs,
-  ...
-}: let
-  cfg = config.soispha.programs.firefox;
-
-  mkAllowedExtension = extension:
-    lib.attrsets.nameValuePair extension.addonId {
-      installation_mode = "normal_installed";
-      updates_disabled = true;
-      inherit (extension) default_area;
-      install_url = "file://${builtins.fetchurl {
-        inherit
-          (extension)
-          url
-          sha256
-          ;
-      }}";
-    };
-
-  allowedExtensions =
-    builtins.listToAttrs
-    (builtins.map mkAllowedExtension (builtins.attrValues
-        cfg.extensions));
-
-  mkBlockedExtension = id:
-    lib.attrsets.nameValuePair id {
-      install_mode = "blocked";
-    };
-  blockedExtensions = builtins.listToAttrs (builtins.map mkBlockedExtension [
-    # these are the default search engines
-    "addons-search-detection@mozilla.com"
-    "amazon@search.mozilla.org"
-    "bing@search.mozilla.org"
-    "ddg@search.mozilla.org"
-    "google@search.mozilla.org"
-    "wikipedia@search.mozilla.org"
-  ]);
-
-  mkProfile = import ./profile.nix {inherit config pkgs;};
-in {
-  options.soispha.programs.firefox = {
-    enable = lib.mkEnableOption "firefox";
-
-    profiles = lib.mkOption {
-      type = lib.types.attrsOf (lib.types.submodule {
-        options = {
-          id = lib.mkOption {
-            type = lib.types.int;
-            description = "The id of this profile.";
-          };
-          name = lib.mkOption {
-            type = lib.types.str;
-            description = "The name of this profile";
-          };
-        };
-      });
-      description = "A list of profies to create besides the default `default` profile.";
-      default = {};
-      apply = value:
-        lib.attrsets.mapAttrs' (name: value: lib.attrsets.nameValuePair name (mkProfile value))
-        value;
-    };
-
-    extensions = lib.mkOption {
-      type = lib.types.attrsOf (
-        lib.types.submodule {
-          options = {
-            addonId = lib.mkOption {
-              type = lib.types.str;
-              example = "addon@darkreader.org";
-              description = "The addon id of this extension";
-            };
-            default_area = lib.mkOption {
-              type = lib.types.enum ["navbar" "menupanel"];
-              example = "navbar";
-              description = ''
-                Where to put this extension by default.
-                `navbar` means into the top-left bar as icon.
-                `menupanel` means hidden behind a “all extensions” button.
-              '';
-            };
-            pname = lib.mkOption {
-              type = lib.types.str;
-              example = "darkreader";
-              description = "The package name of this extension";
-            };
-            sha256 = lib.mkOption {
-              type = lib.types.str;
-              example = "sha256:f565b2263a71626a0310380915b7aef90be8cc6fe16ea43ac1a0846efedc2e4c";
-              description = "The fetchurl copatible hash of this extension";
-            };
-            url = lib.mkOption {
-              type = lib.types.str;
-              example = "https://addons.mozilla.org/firefox/downloads/file/4439735/darkreader-4.9.103.xpi";
-              description = "The download url of this extension.";
-            };
-            version = lib.mkOption {
-              type = lib.types.str;
-              example = "4.9.103";
-              description = "The version of this extension";
-            };
-          };
-        }
-      );
-
-      default = builtins.fromJSON (builtins.readFile ./extensions.json);
-
-      description = ''
-        A list of the extensions that should be installed.
-        You can use a tool like `generate_extensions` to generate this config.
-      '';
-    };
-  };
-
-  config = lib.mkIf cfg.enable {
-    programs.firefox = {
-      enable = true;
-      preferencesStatus = "locked";
-
-      languagePacks = ["en-CA" "de" "sv-SE"];
-
-      nativeMessagingHosts.packages = [
-        pkgs.tridactyl-native
-        pkgs.keepassxc
-      ];
-
-      # NOTE: See https://mozilla.github.io/policy-templates for documentation <2023-10-21>
-      policies = {
-        # NixOS manages this already
-        DisableAppUpdate = true;
-
-        DisableFirefoxAccounts = true;
-        DisableFirefoxScreenshots = true;
-
-        # KeepassXC does this for me
-        DisableMasterPasswordCreation = true;
-
-        # I use a self-hosted services for that
-        DisablePocket = true;
-
-        # I don't want to lose my data
-        DisableProfileRefresh = true;
-
-        DisableDeveloperTools = false;
-
-        DisplayBookmarksToolbar = "newtab";
-        DisplayMenuBar = "default-off";
-
-        DNSOverHTTPS = {
-          Enabled = true;
-          Locked = false;
-        };
-        # The concept of a "default browser" does not apply to my NixOS config
-        DontCheckDefaultBrowser = true;
-
-        ExtensionSettings =
-          {
-            "*" = {
-              # Blocking the extension install here, also blocks the 'about:debugging' page
-
-              # blocked_install_message = ''
-              #   You can't install a extension manually,
-              #   please specify it in your NixOS configuration
-              # '';
-              installation_mode = "allowed";
-            };
-          }
-          // allowedExtensions
-          // blockedExtensions;
-        RequestedLocales = config.programs.firefox.languagePacks;
-
-        ExtensionUpdate = false;
-
-        HardwareAcceleration = true;
-
-        # KeepassXC and such things
-        OfferToSaveLogins = false;
-        PasswordManagerEnabled = false;
-
-        PDFjs = {
-          Enabled = true;
-          # Don't honor documents right to be un-copy-able
-          EnablePermissions = false;
-        };
-
-        SearchBar = "unified";
-      };
-
-      # Beware, that we already set them per-profile in the home-manager config.
-      preferences = {};
-    };
-
-    home-manager.users.soispha = {
-      home.sessionVariables = {
-        # Improve touch input and make scrolling smother
-        MOZ_USE_XINPUT2 = "1";
-
-        # Tell Firefox to use Wayland
-        MOZ_ENABLE_WAYLAND = 1;
-
-        # Tell GTK to use portals
-        GTK_USE_PORTAL = 1;
-
-        BROWSER = "firefox";
-      };
-
-      programs.firefox = {
-        enable = true;
-        arkenfox = {
-          enable = true;
-          version = "133.0";
-        };
-
-        # We use the NixOS module to provide us a package.
-        # HACK: Extract the package from the system-path to get a version for
-        # arkenfox-nixos to compare to. <2025-04-02>
-        package = lib.lists.findSingle (x: builtins.hasAttr "pname" x && x.pname == "firefox") "none" "multiple" config.environment.systemPackages;
-
-        profiles =
-          {
-            default = mkProfile {
-              isDefault = true;
-              id = 0;
-              name = "default";
-            };
-          }
-          // cfg.profiles;
-      };
-    };
-  };
-}
diff --git a/modules/by-name/fi/firefox/profile.nix b/modules/by-name/fi/firefox/profile.nix
deleted file mode 100644
index d82bfafa..00000000
--- a/modules/by-name/fi/firefox/profile.nix
+++ /dev/null
@@ -1,189 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  config,
-  pkgs,
-}: preConfig: ({
-    userChrome = ./userChrome.css;
-
-    bookmarks = {
-      force = true;
-      settings = [];
-    };
-
-    search = {
-      default = "brave-search";
-      privateDefault = "brave-search";
-      force = true;
-      engines = import ./search_engines {inherit pkgs;};
-
-      order = [
-        # DEFAULT
-        "brave-search"
-
-        # NIX
-        "nix-packages"
-        "nix-options"
-        "nixpkgs-issues"
-        "homemanager-options"
-        "nixos-wiki"
-        "nixpkgs-pull-request-tracker"
-
-        # RUST
-        "rust-std"
-        "rust-tokio"
-
-        # OTHER
-        "google-scholar"
-        "wikipedia"
-        "arch-wiki"
-      ];
-    };
-
-    settings = {
-      "browser.download.dir" = "${config.home-manager.users.soispha.xdg.userDirs.download}";
-      # "browser.download.useDownloadDir" = true;
-      # "browser.download.folderList" = 2;
-
-      # QoL
-      "general.autoScroll" = false;
-      "browser.tabs.insertAfterCurrent" = true;
-      "browser.tabs.loadInBackground" = true;
-      "browser.ctrlTab.recentlyUsedOrder" = false;
-      "browser.search.widget.inNavBar" = true;
-      "findbar.highlightAll" = true;
-
-      "devtools.toolbox.host" = "right";
-      "devtools.toolsidebar-width.inspector" = 700;
-
-      # Keep translations useful
-      "browser.translations.automaticallyPopup" = true;
-      "browser.translations.neverTranslateLanguages" = "de";
-
-      # Improve Tab UI
-      "browser.tabs.inTitlebar" = 1;
-      "browser.toolbars.bookmarks.visibility" = "never";
-      "browser.places.importBookmarksHTML" = true;
-
-      # Theme
-      "extensions.activeThemeID" = "firefox-alpenglow@mozilla.org";
-      "extensions.extensions.activeThemeID" = "firefox-alpenglow@mozilla.org";
-
-      # disable updates (pretty pointless with nix)
-      "extensions.update.autoUpdateDefault" = false;
-      "extensions.update.enabled" = false;
-      "app.update.channel" = "default";
-      "browser.shell.checkDefaultBrowser" = false;
-
-      # Allow my custom css
-      "toolkit.legacyUserProfileCustomizations.stylesheets" = true;
-    };
-
-    arkenfox = {
-      enable = true;
-      "0000".enable = true;
-      "0100" = {
-        enable = true;
-        "0102"."browser.startup.page".value = 3;
-        "0103"."browser.startup.homepage".value = "file:///home/dt/home.html";
-        "0104"."browser.newtabpage.enabled".value = true;
-      };
-      "0200" = {
-        enable = true;
-      };
-      "0300" = {
-        enable = true;
-      };
-      "0400" = {
-        enable = false;
-      };
-      "0600" = {
-        enable = true;
-      };
-      "0700" = {
-        enable = true;
-        "0710"."network.trr.mode" = {
-          enable = true;
-          value = 3;
-        };
-      };
-      "0800" = {
-        enable = true;
-      };
-      "0900" = {
-        enable = true;
-      };
-      "1000" = {
-        enable = true;
-        "1001"."browser.cache.disk.enable".value = true;
-        "1003"."browser.sessionstore.privacy_level".value = 0;
-      };
-      "1200" = {
-        enable = true;
-        "1241"."security.mixed_content.block_display_content".enable = true;
-      };
-      "1600" = {
-        enable = true;
-      };
-      "1700" = {
-        enable = true;
-      };
-      "2000" = {
-        enable = true;
-      };
-      "2400" = {
-        enable = true;
-      };
-      "2600" = {
-        enable = true;
-        "2603" = {
-          "browser.download.start_downloads_in_tmp_dir".value = false;
-          "browser.helperApps.deleteTempFileOnExit".value = false;
-        };
-        "2615"."permissions.default.shortcuts" = {
-          value = 2;
-          enable = true;
-        };
-      };
-      "2700" = {
-        enable = true;
-      };
-      "2800" = {
-        enable = false;
-        "2810"."privacy.sanitize.sanitizeOnShutdown".value = false;
-      };
-      "4000" = {
-        enable = true;
-      };
-      "4500" = {
-        enable = true;
-      };
-      "5000" = {
-        enable = true;
-        "5003"."signon.rememberSignons" = {
-          enable = true;
-          value = false;
-        };
-      };
-      "6000" = {
-        enable = true;
-      };
-      "7000" = {
-        enable = true;
-      };
-      "8000" = {
-        enable = true;
-      };
-      "9000" = {
-        enable = true;
-      };
-    };
-  }
-  // preConfig)
diff --git a/modules/by-name/fi/firefox/search_engines/default.nix b/modules/by-name/fi/firefox/search_engines/default.nix
deleted file mode 100644
index f36be0a7..00000000
--- a/modules/by-name/fi/firefox/search_engines/default.nix
+++ /dev/null
@@ -1,113 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{pkgs, ...}: {
-  # DEFAULT
-  brave-search = {
-    name = "Brave Search";
-    urls = [{template = "https://search.brave.com/search?q={searchTerms}";}];
-    icon = ./logos/brave.svg;
-    definedAliases = ["@bs"];
-  };
-
-  # NIX
-  nix-packages = {
-    name = "Nix packages";
-    urls = [{template = "https://search.nixos.org/packages?type=packages&query={searchTerms}";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@np"];
-  };
-
-  nix-functions = {
-    name = "Nix functions";
-    urls = [{template = "https://noogle.dev/q?term={searchTerms}";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@ng"];
-  };
-
-  nixos-options = {
-    name = "NixOS options";
-    urls = [{template = "https://search.nixos.org/options?type=options&query={searchTerms}";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@no"];
-  };
-  homemanager-options = {
-    name = "Home-Manager options";
-    urls = [{template = "https://home-manager-options.extranix.com/?query={searchTerms}&release=master";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@nh"];
-  };
-
-  nixpkgs-issues = {
-    name = "Nixpkgs issues";
-    urls = [{template = "https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+{searchTerms}";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@ni"];
-  };
-  nixpkgs-pull-requests = {
-    name = "Nixpkgs pull requests";
-    urls = [{template = "https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+{searchTerms}";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@nr"];
-  };
-
-  nixpkgs-pull-requests-tracker = {
-    name = "Nixpkgs pull requests tracker";
-    urls = [{template = "https://nixpk.gs/pr-tracker.html?pr={searchTerms}";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@nt"];
-  };
-  nixos-wiki = {
-    name = "NixOS Wiki";
-    urls = [{template = "https://wiki.nixos.org/w/index.php?search={searchTerms}";}];
-    icon = "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
-    definedAliases = ["@nw"];
-  };
-
-  # RUST
-  rust-std = {
-    name = "Rust std";
-    urls = [{template = "https://doc.rust-lang.org/std/?search={searchTerms}";}];
-    icon = ./logos/rust_std.svg;
-    definedAliases = ["@rs"];
-  };
-  rust-tokio = {
-    name = "Rust tokio";
-    urls = [{template = "https://docs.rs/tokio/latest/tokio/index.html?search={searchTerms}";}];
-    icon = ./logos/rust_tokio.png;
-    definedAliases = ["@rt"];
-  };
-
-  # OTHER
-  google-scholar = {
-    name = "Google Scholar";
-    urls = [{template = "https://scholar.google.com/scholar?hl=en&q={searchTerms}";}];
-    icon = ./logos/google_scholar.ico;
-    definedAliases = ["@gs"];
-  };
-  wikipedia = {
-    name = "Wikipedia";
-    urls = [{template = "https://en.wikipedia.org/wiki/{searchTerms}";}];
-    icon = ./logos/wikipedia.svg;
-    definedAliases = ["@wp"];
-  };
-  arch-wiki = {
-    name = "Arch Wiki";
-    urls = [{template = "https://wiki.archlinux.org/index.php?search={searchTerms}";}];
-    icon = ./logos/arch_linux.svg;
-    definedAliases = ["@aw"];
-  };
-
-  "wikipedia".metaData.hidden = true;
-  "ddg".metaData.hidden = true;
-  "bing".metaData.hidden = true;
-  "google".metaData.hidden = true;
-  "Amazon.de".metaData.hidden = true;
-  "ebay".metaData.hidden = true;
-}
diff --git a/modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg b/modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg
deleted file mode 100644
index 949b5c5f..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><path d="M31.994-.006c-2.85 6.985-4.568 11.554-7.74 18.332 1.945 2.062 4.332 4.462 8.2 7.174-4.168-1.715-7-3.437-9.136-5.224-4.06 8.47-10.42 20.538-23.327 43.73C10.145 58.15 18 54.54 25.338 53.16c-.315-1.354-.494-2.818-.48-4.345l.012-.325c.16-6.5 3.542-11.498 7.547-11.158s7.118 5.886 6.957 12.386a18.36 18.36 0 0 1-.409 3.491c7.25 1.418 15.03 5.02 25.037 10.797l-5.42-10.026c-2.65-2.053-5.413-4.726-11.05-7.62 3.875 1.007 6.65 2.168 8.8 3.467-17.1-31.84-18.486-36.07-24.35-49.833z" fill="#1793d1" fill-rule="evenodd"/></svg>
\ No newline at end of file
diff --git a/modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg.license b/modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/arch_linux.svg.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/fi/firefox/search_engines/logos/brave.svg b/modules/by-name/fi/firefox/search_engines/logos/brave.svg
deleted file mode 100644
index 09dd2e42..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/brave.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-<svg width='100' height='129' xmlns='http://www.w3.org/2000/svg'>
-  <style>
-    @keyframes bounce{to{transform:translateY(5%)}}
-  </style>
-  <defs>
-    <linearGradient x1='0%' y1='50.706%' y2='50.706%' id='a'>
-      <stop stop-color='#F50' offset='0%'/>
-      <stop stop-color='#FF2000' offset='100%'/>
-    </linearGradient>
-    <linearGradient x1='2.148%' y1='50.706%' y2='50.706%' id='b'>
-      <stop stop-color='#FA3F2E' offset='0%'/>
-      <stop stop-color='#FF2000' offset='46.132%'/>
-      <stop stop-color='#FF2000' offset='100%'/>
-    </linearGradient>
-    <linearGradient x1='50%' y1='100%' x2='96.767%' y2='100%' id='c'>
-      <stop stop-color='#FFF' offset='0%'/>
-      <stop stop-color='#F4F4F4' offset='100%'/>
-    </linearGradient>
-  </defs>
-  <g fill='none' fill-rule='evenodd' style='animation:bounce 1s infinite alternate ease-in-out'>
-    <path d='M99.914 37.337l-3.616-9.848 2.512-5.657a1.941 1.941 0 0 0-.391-2.148l-6.835-6.936a11.014 11.014 0 0 0-11.464-2.676l-1.91.665L68.226.014H31.524L21.67 10.876l-1.858-.656a11.04 11.04 0 0 0-11.574 2.7l-6.956 7.067a1.541 1.541 0 0 0-.309 1.711l2.625 5.872L0 37.413l2.329 8.875 10.605 40.45a20.6 20.6 0 0 0 7.949 11.545s12.876 9.11 25.583 17.384c1.117.729 2.286 1.26 3.54 1.241 1.254.017 2.422-.512 3.537-1.244 14.271-9.384 25.562-17.417 25.562-17.417a20.61 20.61 0 0 0 7.936-11.556l10.555-40.467 2.318-8.887z' fill='url(#a)'/>
-    <path d='M31.565.033l-9.73 10.987-.803-.554c-6.463-2.01-9.277-.647-13.447 3.23l-.923.996 5.093-.996c1.407 0 5.342.133 6.167.416 3.473 1.195 4.437 2.593 6.662 4.059l1.069.359 10.385 2.083a4.21 4.21 0 0 0 1.96-.096l4.879-1.602c4.416-1.711 9.227-1.79 14.238 0l4.786 1.622a4.645 4.645 0 0 0 2.272.14l.859-.162 10.493-2.344.17-.422.723-.583c4.463-3.249 8.017-4.822 14.867-4.152h.527l-.315-.424c-5.711-4.543-9.193-3.178-12.401-2.124l-.877.3L68.281.033H31.565z' fill='url(#b)'/>
-    <path d='M53.472 72.856l1.388.576c1.496.62 3.903 1.73 5.346 2.464l4.096 2.085c1.444.733 1.548 2.106.23 3.05l-3.493 2.505a73.241 73.241 0 0 0-4.602 3.644l-4.406 3.853c-1.21 1.059-3.17 1.064-4.356.014a605.63 605.63 0 0 0-4.368-3.823 71.635 71.635 0 0 0-4.614-3.612l-3.481-2.465c-1.324-.937-1.23-2.317.207-3.066l4.118-2.148a80.664 80.664 0 0 1 5.33-2.495l1.388-.579c1.495-.621 2.835-1.131 2.979-1.131h1.258c.142 0 1.484.506 2.98 1.128zm34.992-33.039l-.263.946c-.703.878-2.184 2.563-3.293 3.746L74.713 55.38c-1.11 1.182-1.735 2.665-1.102 4.159l1.375 3.399c.632 1.492.694 3.962.088 5.62a10.013 10.013 0 0 1-3.065 4.315l-1.064.87c-1.255 1.026-3.478 1.296-4.941.598l-4.696-2.234c-1.462-.695-3.643-2.153-4.848-3.24l-4.443-4.005a2.07 2.07 0 0 1-.109-2.968l10.82-7.32c1.342-.908 2.052-2.587 1.29-4.018l-3.847-7.02c-.763-1.432-1.068-3.334-.679-4.228.39-.894 1.948-2.095 3.464-2.67l12.559-4.68c1.514-.575 1.433-1.169-.179-1.32l-8.025-.6c-1.613-.151-2.796.084-4.355.52l-6.074 1.508c-1.56.436-1.89 2.1-1.597 3.695l2.506 13.626c.294 1.596.437 3.202.32 3.571-.118.37-1.506.964-3.086 1.323l-2.077.473c-1.58.359-4.167.375-5.75.038l-2.514-.537c-1.584-.339-2.976-.918-3.094-1.286-.118-.369.024-1.978.317-3.572l2.49-13.629c.292-1.595-.04-3.257-1.6-3.692l-6.076-1.5c-1.56-.436-2.743-.666-4.355-.514l-8.025.606c-1.613.153-1.692.747-.178 1.32l12.567 4.665c1.514.574 3.074 1.774 3.464 2.668.392.892.088 2.794-.672 4.227l-3.84 7.021c-.76 1.433-.048 3.112 1.295 4.018l10.83 7.31a2.07 2.07 0 0 1-.106 2.967l-4.439 4.012c-1.202 1.087-3.382 2.547-4.844 3.246l-4.693 2.24c-1.461.698-3.686.432-4.94-.592L27.72 72.9c-1.392-1.136-2.455-2.626-3.122-4.447-.558-1.524-.5-3.992.13-5.486l1.372-3.4c.63-1.494.003-2.977-1.108-4.158L14.786 44.552c-1.11-1.18-2.593-2.864-3.296-3.74l-.265-.947-.166-.527c-.015-.607.201-2.542.447-3.066.246-.521 1.189-2.049 2.096-3.393l2.184-3.239a91.717 91.717 0 0 1 3.484-4.75l3.201-4.023c1.01-1.268 1.87-2.3 2-2.292.006-.008 1.312.236 2.902.541l4.85.933c1.59.306 3.344.642 3.898.746.554.105 2.267-.218 3.809-.719l3.487-1.131c1.54-.502 3.879-1.162 5.195-1.468l1.219.018 1.22-.02c1.315.305 3.654.962 5.195 1.46l3.49 1.13c1.541.498 3.255.82 3.808.714.555-.105 2.308-.445 3.898-.753l4.848-.937c1.59-.308 2.897-.553 2.99-.545.042-.008.903 1.021 1.914 2.29l3.206 4.019a90.663 90.663 0 0 1 3.49 4.746l2.188 3.235c.909 1.342 2.328 3.786 2.416 4.342.09.556.15 1.507.136 2.114l-.166.527z' fill='url(#c)'/>
-  </g>
-</svg>
diff --git a/modules/by-name/fi/firefox/search_engines/logos/brave.svg.license b/modules/by-name/fi/firefox/search_engines/logos/brave.svg.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/brave.svg.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/fi/firefox/search_engines/logos/google_scholar.ico b/modules/by-name/fi/firefox/search_engines/logos/google_scholar.ico
deleted file mode 100644
index 85d0c664..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/google_scholar.ico
+++ /dev/null
Binary files differdiff --git a/modules/by-name/fi/firefox/search_engines/logos/google_scholar.ico.license b/modules/by-name/fi/firefox/search_engines/logos/google_scholar.ico.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/google_scholar.ico.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/fi/firefox/search_engines/logos/rust_std.svg b/modules/by-name/fi/firefox/search_engines/logos/rust_std.svg
deleted file mode 100644
index 0091b5a8..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/rust_std.svg
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg width="100%" height="100%" viewBox="0 0 1200 800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;">
-    <g id="Layer-1" serif:id="Layer 1">
-        <g transform="matrix(1,0,0,1,597.344,637.02)">
-            <path d="M0,-279.559C-121.238,-279.559 -231.39,-264.983 -312.939,-241.23L-312.939,-38.329C-231.39,-14.575 -121.238,0 0,0C138.76,0 262.987,-19.092 346.431,-49.186L346.431,-230.37C262.987,-260.465 138.76,-279.559 0,-279.559" style="fill:rgb(165,43,0);fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,1068.75,575.642)">
-            <path d="M0,-53.32L-14.211,-82.761C-14.138,-83.879 -14.08,-84.998 -14.08,-86.121C-14.08,-119.496 -48.786,-150.256 -107.177,-174.883L-107.177,2.643C-79.932,-8.849 -57.829,-21.674 -42.021,-35.482C-46.673,-16.775 -62.585,21.071 -75.271,47.686C-96.121,85.752 -103.671,118.889 -102.703,120.53C-102.086,121.563 -94.973,110.59 -84.484,92.809C-60.074,58.028 -13.82,-8.373 -4.575,-25.287C5.897,-44.461 0,-53.32 0,-53.32" style="fill:rgb(165,43,0);fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,149.064,591.421)">
-            <path d="M0,-99.954C0,-93.526 1.293,-87.194 3.788,-80.985L-4.723,-65.835C-4.723,-65.835 -11.541,-56.989 0.465,-38.327C11.055,-21.872 64.1,42.54 92.097,76.271C104.123,93.564 112.276,104.216 112.99,103.187C114.114,101.554 105.514,69.087 81.631,32.046C70.487,12.151 57.177,-14.206 49.189,-33.675C71.492,-19.559 100.672,-6.755 135.341,4.265L135.341,-204.17C51.797,-177.622 0,-140.737 0,-99.954" style="fill:rgb(165,43,0);fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(-65.8097,-752.207,-752.207,65.8097,621.707,796.312)">
-            <path d="M0.991,-0.034L0.933,0.008C0.933,0.014 0.933,0.02 0.933,0.026L0.99,0.069C0.996,0.073 0.999,0.08 0.998,0.087C0.997,0.094 0.992,0.1 0.986,0.103L0.92,0.133C0.919,0.139 0.918,0.145 0.916,0.15L0.964,0.203C0.968,0.208 0.97,0.216 0.968,0.222C0.965,0.229 0.96,0.234 0.953,0.236L0.882,0.254C0.88,0.259 0.877,0.264 0.875,0.27L0.91,0.33C0.914,0.336 0.914,0.344 0.91,0.35C0.907,0.356 0.9,0.36 0.893,0.361L0.82,0.365C0.817,0.369 0.813,0.374 0.81,0.379L0.832,0.445C0.835,0.452 0.833,0.459 0.828,0.465C0.824,0.47 0.816,0.473 0.809,0.472L0.737,0.462C0.733,0.466 0.729,0.47 0.724,0.474L0.733,0.544C0.734,0.551 0.731,0.558 0.725,0.562C0.719,0.566 0.711,0.568 0.704,0.565L0.636,0.542C0.631,0.546 0.626,0.549 0.621,0.552L0.615,0.621C0.615,0.629 0.61,0.635 0.604,0.638C0.597,0.641 0.589,0.641 0.583,0.638L0.521,0.602C0.52,0.603 0.519,0.603 0.518,0.603L0.406,0.729C0.406,0.729 0.394,0.747 0.359,0.725C0.329,0.705 0.206,0.599 0.141,0.543C0.109,0.52 0.089,0.504 0.09,0.502C0.093,0.499 0.149,0.509 0.217,0.554C0.278,0.588 0.371,0.631 0.38,0.619C0.38,0.619 0.396,0.604 0.406,0.575C0.406,0.575 0.406,0.575 0.406,0.575C0.407,0.576 0.407,0.576 0.406,0.575C0.406,0.575 0.091,0.024 0.305,-0.531C0.311,-0.593 0.275,-0.627 0.275,-0.627C0.266,-0.639 0.178,-0.598 0.12,-0.566C0.055,-0.523 0.002,-0.513 0,-0.516C-0.001,-0.518 0.018,-0.533 0.049,-0.555C0.11,-0.608 0.227,-0.707 0.256,-0.726C0.289,-0.748 0.301,-0.73 0.301,-0.73L0.402,-0.615C0.406,-0.614 0.41,-0.613 0.415,-0.613L0.47,-0.658C0.475,-0.663 0.483,-0.664 0.49,-0.662C0.497,-0.66 0.502,-0.655 0.504,-0.648L0.522,-0.58C0.527,-0.578 0.533,-0.576 0.538,-0.574L0.602,-0.608C0.608,-0.612 0.616,-0.612 0.623,-0.608C0.629,-0.605 0.633,-0.599 0.633,-0.592L0.637,-0.522C0.642,-0.519 0.647,-0.515 0.652,-0.512L0.721,-0.534C0.728,-0.536 0.736,-0.535 0.741,-0.531C0.747,-0.526 0.75,-0.519 0.749,-0.512L0.738,-0.443C0.742,-0.439 0.746,-0.435 0.751,-0.431L0.823,-0.439C0.83,-0.44 0.837,-0.437 0.842,-0.432C0.847,-0.426 0.848,-0.419 0.845,-0.412L0.821,-0.347C0.824,-0.342 0.828,-0.337 0.831,-0.332L0.903,-0.327C0.911,-0.327 0.917,-0.322 0.92,-0.316C0.924,-0.31 0.924,-0.302 0.92,-0.296L0.883,-0.236C0.885,-0.231 0.887,-0.226 0.889,-0.22L0.959,-0.202C0.966,-0.2 0.972,-0.195 0.974,-0.188C0.976,-0.181 0.974,-0.174 0.969,-0.168L0.92,-0.116C0.921,-0.111 0.923,-0.105 0.924,-0.099L0.988,-0.068C0.995,-0.065 0.999,-0.059 1,-0.052C1.001,-0.045 0.997,-0.038 0.991,-0.034ZM0.406,0.575C0.406,0.575 0.406,0.575 0.406,0.575C0.406,0.575 0.406,0.575 0.406,0.575Z" style="fill:url(#_Linear1);fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,450.328,483.629)">
-            <path d="M0,167.33C-1.664,165.91 -2.536,165.068 -2.536,165.068L140.006,153.391C23.733,0 -69.418,122.193 -79.333,135.855L-79.333,167.33L0,167.33Z" style="fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,747.12,477.333)">
-            <path d="M0,171.974C1.663,170.554 2.536,169.71 2.536,169.71L-134.448,159.687C-18.12,0 69.421,126.835 79.335,140.497L79.335,171.974L0,171.974Z" style="fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(-1.53e-05,-267.211,-267.211,1.53e-05,809.465,764.23)">
-            <path d="M1,-0.586C1,-0.586 0.768,-0.528 0.524,-0.165L0.5,-0.064C0.5,-0.064 1.1,0.265 0.424,0.731C0.424,0.731 0.508,0.586 0.405,0.197C0.405,0.197 0.131,0.376 0.14,0.736C0.14,0.736 -0.275,0.391 0.324,-0.135C0.324,-0.135 0.539,-0.691 1,-0.736L1,-0.586Z" style="fill:url(#_Linear2);fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,677.392,509.61)">
-            <path d="M0,-92.063C0,-92.063 43.486,-139.678 86.974,-92.063C86.974,-92.063 121.144,-28.571 86.974,3.171C86.974,3.171 31.062,47.615 0,3.171C0,3.171 -37.275,-31.75 0,-92.063" style="fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,727.738,435.209)">
-            <path d="M0,0.002C0,18.543 -10.93,33.574 -24.408,33.574C-37.885,33.574 -48.814,18.543 -48.814,0.002C-48.814,-18.539 -37.885,-33.572 -24.408,-33.572C-10.93,-33.572 0,-18.539 0,0.002" style="fill:white;fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,483.3,502.984)">
-            <path d="M0,-98.439C0,-98.439 74.596,-131.467 94.956,-57.748C94.956,-57.748 116.283,28.178 33.697,33.028C33.697,33.028 -71.613,12.745 0,-98.439" style="fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(1,0,0,1,520.766,436.428)">
-            <path d="M0,0C0,19.119 -11.27,34.627 -25.173,34.627C-39.071,34.627 -50.344,19.119 -50.344,0C-50.344,-19.124 -39.071,-34.627 -25.173,-34.627C-11.27,-34.627 0,-19.124 0,0" style="fill:white;fill-rule:nonzero;"/>
-        </g>
-        <g transform="matrix(-1.53e-05,-239.021,-239.021,1.53e-05,402.161,775.388)">
-            <path d="M0.367,0.129C-0.364,-0.441 0.223,-0.711 0.223,-0.711C0.259,-0.391 0.472,-0.164 0.472,-0.164C0.521,-0.548 0.525,-0.77 0.525,-0.77C1.203,-0.256 0.589,0.161 0.589,0.161C0.627,0.265 0.772,0.372 0.906,0.451L1,0.77C0.376,0.403 0.367,0.129 0.367,0.129Z" style="fill:url(#_Linear3);fill-rule:nonzero;"/>
-        </g>
-    </g>
-    <defs>
-        <linearGradient id="_Linear1" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,1.38778e-17,-1,0,-0.000650515)"><stop offset="0" style="stop-color:rgb(247,76,0);stop-opacity:1"/><stop offset="0.33" style="stop-color:rgb(247,76,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(244,150,0);stop-opacity:1"/></linearGradient>
-        <linearGradient id="_Linear2" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,0,0,-1,0,1.23438e-06)"><stop offset="0" style="stop-color:rgb(204,58,0);stop-opacity:1"/><stop offset="0.15" style="stop-color:rgb(204,58,0);stop-opacity:1"/><stop offset="0.74" style="stop-color:rgb(247,76,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(247,76,0);stop-opacity:1"/></linearGradient>
-        <linearGradient id="_Linear3" x1="0" y1="0" x2="1" y2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1,1.32349e-23,1.32349e-23,-1,0,-9.1568e-07)"><stop offset="0" style="stop-color:rgb(204,58,0);stop-opacity:1"/><stop offset="0.15" style="stop-color:rgb(204,58,0);stop-opacity:1"/><stop offset="0.74" style="stop-color:rgb(247,76,0);stop-opacity:1"/><stop offset="1" style="stop-color:rgb(247,76,0);stop-opacity:1"/></linearGradient>
-    </defs>
-</svg>
diff --git a/modules/by-name/fi/firefox/search_engines/logos/rust_std.svg.license b/modules/by-name/fi/firefox/search_engines/logos/rust_std.svg.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/rust_std.svg.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/fi/firefox/search_engines/logos/rust_tokio.png b/modules/by-name/fi/firefox/search_engines/logos/rust_tokio.png
deleted file mode 100644
index f1de55ff..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/rust_tokio.png
+++ /dev/null
Binary files differdiff --git a/modules/by-name/fi/firefox/search_engines/logos/rust_tokio.png.license b/modules/by-name/fi/firefox/search_engines/logos/rust_tokio.png.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/rust_tokio.png.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg b/modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg
deleted file mode 100644
index dc32f984..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [<!ENTITY st0 "opacity:.22;fill:#231F20;"><!ENTITY st1 "opacity:.34;fill:url(#SVGID_25_);"><!ENTITY st2 "opacity:.19;fill:#231F20;"><!ENTITY st3 "opacity:.18;fill:url(#SVGID_42_);"><!ENTITY st4 "opacity:.73;fill:#FFF;"><!ENTITY st5 "opacity:.35;fill:url(#SVGID_6_);"><!ENTITY st6 "opacity:.53;fill:#FFF;"><!ENTITY st7 "opacity:.43;fill:url(#SVGID_23_);"><!ENTITY st8 "opacity:.25;fill:#231F20;"><!ENTITY st9 "opacity:.53;fill:url(#SVGID_9_);"><!ENTITY st10 "opacity:.88;fill:#231F20;"><!ENTITY st11 "opacity:.31;fill:url(#SVGID_24_);"><!ENTITY st12 "fill:#232323;"><!ENTITY st13 "opacity:.68;fill:url(#SVGID_22_);"><!ENTITY st14 "opacity:.28;fill:#231F20;"><!ENTITY st15 "opacity:.38;fill:url(#SVGID_43_);"><!ENTITY st16 "fill:url(#SVGID_1_);"><!ENTITY st17 "fill:url(#SVGID_2_);"><!ENTITY st18 "fill:url(#SVGID_4_);"><!ENTITY st19 "opacity:.45;fill:url(#SVGID_5_);"><!ENTITY st20 "opacity:.17;fill:#FFF;"><!ENTITY st21 "opacity:.3;fill:#505050;"><!ENTITY st22 "fill:#616161;"><!ENTITY st23 "fill:#FFF;"><!ENTITY st24 "opacity:.2;fill:url(#SVGID_41_);"><!ENTITY st25 "opacity:.69;fill:url(#SVGID_3_);"><!ENTITY st26 "opacity:.45;fill:url(#SVGID_39_);"><!ENTITY st27 "opacity:.96;fill:url(#SVGID_10_);"><!ENTITY st28 "opacity:.3;fill:#FFF;"><!ENTITY st29 "fill:#9FA2A3;"><!ENTITY st30 "opacity:.73;fill:url(#SVGID_8_);"><!ENTITY st31 "fill:#6B6B6B;"><!ENTITY st32 "opacity:.36;fill:#231F20;"><!ENTITY st33 "opacity:.5;fill:url(#SVGID_7_);"><!ENTITY st34 "opacity:.1;fill:#232323;"><!ENTITY st35 "fill:url(#SVGID_11_);"><!ENTITY st36 "fill:url(#SVGID_12_);"><!ENTITY st37 "fill:url(#SVGID_13_);"><!ENTITY st38 "fill:url(#SVGID_14_);"><!ENTITY st39 "fill:url(#SVGID_15_);"><!ENTITY st40 "fill:url(#SVGID_16_);"><!ENTITY st41 "fill:url(#SVGID_17_);"><!ENTITY st42 "fill:url(#SVGID_18_);"><!ENTITY st43 "fill:url(#SVGID_19_);"><!ENTITY st44 "fill:url(#SVGID_20_);"><!ENTITY st45 "fill:url(#SVGID_21_);"><!ENTITY st46 "fill:url(#SVGID_26_);"><!ENTITY st47 "fill:url(#SVGID_27_);"><!ENTITY st48 "fill:url(#SVGID_28_);"><!ENTITY st49 "fill:url(#SVGID_29_);"><!ENTITY st50 "fill:url(#SVGID_30_);"><!ENTITY st51 "fill:url(#SVGID_31_);"><!ENTITY st52 "fill:url(#SVGID_33_);"><!ENTITY st53 "fill:url(#SVGID_34_);"><!ENTITY st54 "fill:url(#SVGID_35_);"><!ENTITY st55 "fill:url(#SVGID_36_);"><!ENTITY st56 "fill:url(#SVGID_37_);"><!ENTITY st57 "fill:url(#SVGID_38_);"><!ENTITY st58 "fill:url(#SVGID_40_);"><!ENTITY st59 "opacity:.1;fill:#231F20;"><!ENTITY st60 "opacity:.5;fill:#141414;"><!ENTITY st61 "opacity:.38;fill:#231F20;"><!ENTITY st62 "opacity:.83;fill:url(#SVGID_32_);">]><svg version="1.1" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="103px" height="94px" viewBox="0 0 103 94"><title>Wikipedia logo version 2</title><radialGradient id="SVGID_1_" cx="244.5713" cy="-427.1392" r="68.6868" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#FFF"/><stop offset=".4835" stop-color="#EAEAEB"/><stop offset=".9451" stop-color="#A9ABAE"/><stop offset="1" stop-color="#999B9E"/></radialGradient><path style="&st16;" d="M49.85,17.003c0.014-0.606-0.392-1.27-0.392-1.27l-0.025-0.058c0,0-0.487-0.949-1.301-1.228c-0.815-0.278-1.478,0.342-1.478,0.342s-0.114,0.131-0.428,0.494c-0.313,0.364-0.507,0.666-1.198,0.938c-0.692,0.271-1.379,0.204-1.743,0.033c-0.365-0.172-0.457-0.537-0.457-0.537s-0.229-0.722-0.313-1.049c-0.086-0.331-0.308-1.694-0.308-1.694s-0.492-2.747-0.535-3.304c0,0,1.475-0.126,3.686-0.775c2.3-0.673,3.043-1.206,3.043-1.206s-0.432-0.156-0.484-0.662c-0.051-0.507-0.089-1.19-0.089-1.19s-0.089-0.5,0.483-1.139c0.572-0.64,1.354-0.863,1.763-0.953c0.41-0.089,1.281-0.17,2.092-0.134c0.813,0.038,1.266,0.112,1.594,0.291c0.327,0.178,0.356,0.61,0.356,0.61l-0.009,1.146c0,0-0.035,0.402,0.262,0.529c0,0,0.505,0.305,2.197,0.133c0,0,0.719-0.126,1.845-0.46c1.125-0.335,4.129-1.229,4.554-1.341c0.426-0.111,0.953-0.291,1.645-0.469c0.693-0.179,2.041-0.626,2.309-0.73c0.27-0.104,1.811-0.618,2.928-0.81c1.114-0.195,2.226-0.186,2.813,0.149c0,0,0.357,0.304,0.521,0.662c0.162,0.358,0.476,0.863,0.92,1.088c0.457,0.227,0.754,0.371,1.877,0.273c0,0,0.021-0.096-0.396-0.37c-0.417-0.277-0.991-0.701-0.991-0.701s-0.334-0.245-0.408-0.447c-0.072-0.202-0.043-0.306-0.043-0.306l0.877-1.406c0,0,0-0.172,0.506-0.238c0.506-0.067,1.074-0.134,1.742-0.313c0.67-0.178,0.789-0.312,0.789-0.312l0.578,0.178c0,0,3.547,2.853,4.655,3.583l0.198-0.239c0,0,0.437,0.018,0.828,0.172c0.393,0.154,0.979,0.562,0.979,0.562s1.613,1.31,2.072,2.2l0.222,0.679l-0.102,0.161c0,0,0.919,1.307,2.096,2.602c0,0,1.229,1.664,1.689,2.09c0,0-0.108-0.399-0.203-0.849l0.339-0.226l0.2-0.144l0.617,0.259c3.575,4.811,6.435,10.424,8.144,16.328l-0.121,0.484l0.396,0.501c1.129,4.212,1.729,8.643,1.729,13.211c0,1.122-0.038,2.236-0.109,3.339l-0.304,0.511l0.226,0.555C99.95,72.645,78.057,93.131,51.38,93.131c-18.502,0-34.702-9.854-43.637-24.601l-0.102-0.365l-0.205-0.151c-3.387-5.742-5.682-12.205-6.595-19.104l0.212-0.524l-0.336-0.482c-0.213-1.892-0.322-3.812-0.322-5.758c0-2.985,0.255-5.909,0.748-8.755l0.25-0.562l-0.087-0.328C2.463,26.451,4.689,20.783,7.78,15.7l0.684-0.384l0.081,0.032c0,0,0.233-0.169,0.354-0.217l0.076-0.023c0,0,1.179-1.971,1.625-2.601c0,0,0.542-0.348,0.745-0.407c0,0,0.124-0.016,0.189,0.076c0,0,0.496-0.432,1.699-2.054c0.004-0.005,0.007-0.011,0.012-0.017c0,0-0.114-0.076-0.131-0.174c-0.018-0.097,0.108-0.591,0.173-0.717s0.108-0.156,0.108-0.156s1.722-2.032,3.151-3.238c0,0,0.26-0.202,0.678-0.25c0,0,1.472-0.613,3.264-2.184c0,0,0.051-0.289,0.478-0.858c0.428-0.57,1.456-1.163,2.222-1.337c0.764-0.174,0.896-0.038,0.896-0.038l0.064,0.065l0.515,0.766c0,0,0.565-0.316,1.413-0.604c0.847-0.289,0.979-0.262,0.979-0.262l0.823,1.336l-0.987,2c0,0-0.644,1.421-1.655,2.185c0,0-0.472,0.284-1.12,0.127c-0.648-0.157-1.072,0.333-1.072,0.333l-0.17,0.14c0,0,0.14-0.024,0.346-0.103c0,0,0.158,0.065,0.274,0.223c0.114,0.158,0.913,1.175,0.913,1.175s0.005,0.837-0.415,1.938c-0.419,1.1-1.467,2.891-1.467,2.891s-0.733,1.424-1.075,2.253c-0.342,0.829-0.515,1.765-0.488,2.262c0,0,0.187,0.062,0.707-0.202c0.655-0.332,1.083,0.027,1.083,0.027s0.719,0.53,1.041,0.881c0.262,0.289,0.802,1.765,0.209,3.224c0,0-0.402,1.008-1.377,1.724c0,0-0.216,0.332-1.529,0.174c-0.368-0.043-0.585-0.276-1.372-0.2c-0.785,0.077-1.231,0.815-1.231,0.815l0.013-0.024c-0.692,0.999-1.154,2.458-1.154,2.458l-0.057,0.165c0,0-0.241,0.509-0.292,1.752c-0.053,1.284,0.284,3.109,0.284,3.109s7.876-1.387,9.88-0.055l0.58,0.532c0,0,0.046,0.174-0.031,0.376c-0.08,0.204-0.375,0.673-0.987,1.113c-0.611,0.438-1.222,1.583-0.313,2.304c1.034,0.818,1.691,0.766,3.43,0.468c1.74-0.297,2.898-1.269,2.898-1.269s0.972-0.72,0.783-1.628c-0.188-0.908-1.017-1.189-1.017-1.189s-0.658-0.423-0.141-1.238c0,0,0.141-0.689,2.553-1.316c2.414-0.626,6.812-1.52,10.557-1.989c0,0-2.539-8.223-0.738-9.289c0,0,0.438-0.296,1.224-0.408l0.72-0.037c0.131-0.027,0.343,0.005,0.796,0.045c0.453,0.038,1.001,0.076,1.678-0.441c0.676-0.519,0.697-0.819,0.697-0.819"/><radialGradient id="SVGID_2_" cx="197.6416" cy="-371.8613" r="0" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#FFF"/><stop offset=".4835" stop-color="#EAEAEB"/><stop offset=".9451" stop-color="#A9ABAE"/><stop offset="1" stop-color="#999B9E"/></radialGradient><path style="&st17;" d="M-16.122-14.641"/><linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="456.2744" y1="510.1602" x2="502.7757" y2="582.9122" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#8A8A8A"/><stop offset=".5687" stop-color="#606060"/><stop offset=".5914" stop-color="#FFF"/><stop offset=".6116" stop-color="#585858"/><stop offset="1" stop-color="#303030"/></linearGradient><path style="&st25;" d="M82.447,79.307l0.451,0.168c-0.032,0.061-0.067,0.119-0.101,0.179c-0.864,1.573-0.936,1.927-1.36,2.253c-0.424,0.326-0.58,0.539-1.443,0.695c-0.865,0.156-1.771,1.175-1.771,1.175s-0.875,0.835-0.48,0.866c0.396,0.025,1.177-0.609,1.177-0.609s0.497-0.354,0.625-0.255c0.125,0.099-0.539,0.751-0.539,0.751s-1.161,1.176-2.479,1.982l-0.396,0.213c0,0,1.869-1.392,2.764-2.395c0,0,0.185-0.271-0.185,0.057c-0.369,0.325-1.332,0.821-1.741,0.821c-0.41,0,0.016-0.563,0.016-0.563s0.596-0.768,1.812-1.758c1.22-0.994,2.239-0.922,2.239-0.922s0.227,0.043,0.253-0.271c0.028-0.313,0.312-0.863,0.312-0.863s0.453-1.032,1.674-2.749c1.218-1.714,1.77-2.195,1.77-2.195s1.588-1.629,2.423-3.259c0,0,0.581-1.006-0.364-0.255c-0.951,0.753-2.211,1.7-3.44,2.014c-1.233,0.312-1.349-0.836-1.349-0.836s-0.271-1.884,1.049-3.344c1.188-1.316,2.492-1.273,3.684-1.415c1.188-0.144,2.21-1.571,2.21-1.571s0.82-0.922,1.289-3.797c0.218-1.337,0.067-2.244-0.144-2.818l0.021-0.647l-0.368-0.021c-0.078-0.106-0.135-0.153-0.135-0.153s-0.297-0.299-0.607-0.524c-0.313-0.227-0.692-0.649-1.063-1.457c0,0-1.019-2.11-0.792-5.156c0.227-3.047,2.762-2.762,2.762-2.762s1.475,0.143,1.76-0.298c0.283-0.438,0.553-0.993,0.649-2.223c0.101-1.233-0.396-2.408-0.396-2.408s-0.186-0.609-1.049-0.708c-0.863-0.1-1.051,0.169-1.051,0.169s-0.255,0.072-0.723,1.09c-0.471,1.021-0.75,1.488-1.602,1.702c-0.849,0.211-2.023,0.099-2.549-0.992c-0.515-1.072-1.757-3.693-2.351-5.772l0.084-0.735l-0.325-0.471c-0.063-0.396-0.117-0.846-0.13-1.236c-0.026-0.992-0.312-2.097-0.638-3.2c-0.326-1.106-1.459-2.972-1.672-3.399c-0.324-0.667-0.621-0.949-1.021-0.893c-0.396,0.056-0.339,0.056-0.513,0.056c-0.168,0-0.266,0.212-0.311,0.425c-0.042,0.212-0.375,1.315-1.104,1.812c-0.752,0.51-1.147,0.737-2.438,0.85c0,0-1.487,0.099-2.661-2.097C71,29.36,71.301,27.96,71.398,27.45c0.099-0.51,0.539-1.247,1.229-1.388c0.693-0.141,1.119-0.184,1.119-0.184s1.122-0.01,1.603-0.071c0.551-0.071,0.283-1.006,0.283-1.006s-0.361-2.371-2.348-4.318l-0.096-0.487l-0.756-0.381c-1.881-2.04-4.354-5.354-4.354-5.354s-1.105-1.048-0.17-2.493c0,0,0.438-0.963,1.742-0.792c0.419,0.081,0.457,0.123,0.818,0.199c0.481,0.099,1.008,0.225,1.478-0.398c0,0,0.438-0.792-0.271-1.812s-0.923-1.742-1.785-1.687c0,0-0.397-0.055-0.793,0.384C68.702,8.1,67.682,8.378,67.086,8.44c-0.679,0.071-2.252-0.528-3.156-2.082c-0.513-0.874-0.752-1.35-0.865-1.595l0.231-0.34l0.72,0.08c0.186,0.358,0.549,1.056,0.978,1.812c0.552,0.978,1.048,1.118,1.373,1.261c0.325,0.141,1.049-0.071,1.431-0.283c0.385-0.213,0.766-0.695,1.43-0.738c0.668-0.043,1.629,0.071,2.311,0.793c0.682,0.723,1.531,2.224,1.459,2.932c-0.068,0.708-0.111,1.403-1.035,1.699c-0.921,0.298-1.303,0.043-1.884-0.084c-0.581-0.128-0.864-0.072-1.104,0.211c-0.242,0.284-0.512,0.892-0.412,1.162c0.102,0.27,0.186,0.454,0.75,1.262c0.566,0.806,3.474,4.25,4.031,4.766l-0.152,0.698l0.968,0.176c0.625,0.724,1.358,1.668,1.687,2.263c0.493,0.907,0.752,2.337,0.779,3.002c0.025,0.666-0.299,0.963-0.299,0.963s-0.313,0.524-2.012,0.524c-1.517,0-1.614,0.297-1.614,0.297s-0.47,0.467-0.369,1.615c0.103,1.146,0.616,2.344,1.56,3.37c0.778,0.851,2.252-0.006,2.748-0.295c0.51-0.299,0.822-1.264,0.822-1.264s0.102-1.217,1.432-1.217c1.377,0,1.969,1.318,1.969,1.318s0.963,1.295,1.941,4.121c0.481,1.389,0.566,2.281,0.566,2.281l0.126,1.668l-0.513,0.892l0.732,0.312c0.135,0.541,0.348,1.24,0.686,2.044c0,0,1.008,2.381,1.443,3.286c0.44,0.906,0.896,0.766,1.264,0.808c0,0,0.85,0.113,1.16-0.282c0.313-0.398,0.61-1.092,0.61-1.092s0.663-1.812,2.138-1.657c1.475,0.156,1.84,1.092,2.096,2.168c0.256,1.074,0.313,3.229-0.479,4.545c-0.798,1.318-1.688,1.135-1.688,1.135s-1.813-0.17-2.225,0.213c-0.41,0.382-0.623,0.724-0.681,1.613c-0.058,0.894,0.026,2.336,0.751,4.08c0.631,1.523,1.146,1.361,1.432,1.728c0.284,0.368,1.188,1.204,1.104,3.272c-0.082,2.067-0.791,4.149-1.586,5.439c-0.793,1.288-1.997,2.053-1.997,2.053s-0.338,0.211-1.076,0.311c-0.735,0.102-1.784,0.086-2.534,0.513c-0.75,0.426-0.992,1.501-1.063,1.971c-0.069,0.468-0.112,1.529,0.921,1.413c1.034-0.109,2.577-1.4,2.577-1.4s1.486-1.104,1.685-0.752c0.199,0.354-0.636,1.784-0.636,1.784s-1.035,1.562-1.898,2.523c-0.709,0.791-1.641,1.868-2.431,3.102L82.447,79.307L82.447,79.307z"/><linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="425.2861" y1="502.9512" x2="445.7861" y2="598.6606" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#A8A9AB"/><stop offset="1" stop-color="#636668"/></linearGradient><path style="&st18;" d="M23.441,22.732c-0.007,0.008-0.013,0.018-0.021,0.025C23.428,22.75,23.434,22.74,23.441,22.732z"/><linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="421.0684" y1="504.3701" x2="441.068" y2="597.7433" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#A8A9AB"/><stop offset="1" stop-color="#636668"/></linearGradient><path style="&st19;" d="M38.188,89.707l0.163,0.01c-0.163-0.147-0.37-0.281-0.62-0.414c-0.699-0.371-3.731-2.375-4.669-3.009c-0.936-0.633-2.575-1.7-3.297-1.478c-0.554,0.172-0.475,0.394-0.804,0.556c-0.331,0.157-0.687,0.052-1.504-0.384c-0.818-0.434-1.424-0.725-3.02-2.239c-1.245-1.185,1.595-0.118,1.595-0.118s0.619,0.262,0.343-0.385c-0.277-0.646-1.676-2.333-2.994-3.691c-1.068-1.098-1.674-1.86-2.435-2.97l-0.566-0.661l0.007-0.166c-0.018-0.024-0.035-0.054-0.052-0.078c0,0-1.874-3.377-1.676-4.617c0,0,0.068-0.828,1.241-1.188c0.817-0.251,0.71,0.542,3.112,0.975c0,0,2.07,0.559,2.611-0.945c0.539-1.505-0.567-3.393-0.567-3.393s-1.449-2.656-3.244-2.758c-0.95-0.053-0.692,0.586-2.125,0.926c0,0-1.913,0.184-2.519-0.963c-0.734-1.389-1.04-2.969-1.015-4.022c0.022-1,0.054-1.079,0.119-1.371c0.045-0.206,0.192-0.582,0.254-1.128l-0.134-0.667l0.204-0.501c0.002-0.26-0.004-0.535-0.021-0.83c-0.091-1.66-0.213-4.221-0.437-5.71c-0.223-1.491-0.633-3.798-1.991-3.866c0,0-0.671-0.051-1.634,0.885c-0.884,0.856-1.684-0.708-1.728-1.663c-0.053-1.121,0.131-2.254,0.409-2.795c0.277-0.541,1.042-0.567,1.186-0.555c0.146,0.013,0.555,0.171,1.043,0.474c0.488,0.305,1.16,0.305,1.557-0.092c0.395-0.394,0.947-0.856,1.173-2.598c0.224-1.741,0.224-3.547,0.013-5.71l-0.225-0.484l1.339-0.289c-0.001-0.017-0.021-0.126-0.032-0.193c0-0.002,0-0.003,0-0.005c-0.002-0.017-0.005-0.032-0.007-0.049c-0.001-0.003-0.001-0.005-0.001-0.007c-0.003-0.019-0.007-0.038-0.009-0.057c0-0.001-0.001-0.001-0.001-0.003c-0.003-0.02-0.006-0.042-0.009-0.062c0-0.001,0-0.001,0-0.001c-0.004-0.023-0.007-0.045-0.011-0.068c0-0.004-0.001-0.006-0.001-0.008c-0.002-0.022-0.006-0.045-0.008-0.066c-0.001-0.006-0.001-0.01-0.003-0.017c-0.002-0.023-0.005-0.046-0.009-0.069c-0.001-0.004-0.001-0.007-0.002-0.014c-0.003-0.026-0.007-0.05-0.011-0.076c0-0.002,0-0.004,0-0.005c-0.004-0.024-0.008-0.05-0.011-0.076c-0.001-0.007-0.001-0.01-0.003-0.017c-0.002-0.025-0.006-0.052-0.009-0.08c-0.001-0.005-0.001-0.011-0.002-0.021c-0.005-0.027-0.007-0.053-0.011-0.081c-0.001-0.006-0.002-0.013-0.002-0.019c-0.002-0.029-0.006-0.058-0.01-0.087c0-0.004-0.001-0.008-0.003-0.014c-0.002-0.028-0.005-0.056-0.009-0.082c-0.001-0.006-0.001-0.011-0.002-0.016c-0.002-0.031-0.006-0.06-0.01-0.09c0-0.006-0.001-0.015-0.002-0.021c-0.004-0.03-0.006-0.061-0.011-0.09c0-0.007-0.001-0.015-0.002-0.022c-0.003-0.03-0.006-0.062-0.01-0.093c0-0.006-0.002-0.012-0.002-0.019c-0.003-0.032-0.005-0.063-0.009-0.094c0-0.002,0-0.005,0-0.009c-0.004-0.032-0.005-0.066-0.01-0.1c0-0.005,0-0.012-0.001-0.02c-0.002-0.033-0.005-0.065-0.007-0.098c-0.001-0.007-0.001-0.014-0.001-0.021c-0.004-0.033-0.006-0.067-0.008-0.099c0-0.005,0-0.012-0.001-0.02c-0.002-0.033-0.006-0.069-0.007-0.102c0-0.003,0-0.007-0.001-0.01c-0.002-0.033-0.004-0.066-0.006-0.1c-0.001-0.006-0.001-0.011-0.001-0.017c-0.001-0.032-0.003-0.068-0.005-0.1c0-0.008,0-0.014-0.001-0.021c-0.001-0.031-0.002-0.065-0.003-0.099c-0.001-0.006-0.001-0.013-0.001-0.021c-0.002-0.033-0.003-0.066-0.004-0.1c0-0.005,0-0.009,0-0.014c-0.001-0.032-0.001-0.066-0.002-0.099c0-0.003,0-0.005,0-0.009c0-0.034,0-0.067-0.001-0.101c0-0.005,0-0.013,0-0.017c0-0.033,0-0.067,0-0.098c0-0.005,0.001-0.012,0.001-0.019c0-0.032,0-0.065,0.001-0.095c0-0.005,0-0.009,0-0.015c0.001-0.033,0.001-0.065,0.003-0.099c0.052-1.244,0.292-1.752,0.292-1.752l0.057-0.164c0,0,0.46-1.459,1.154-2.459l-0.013,0.024c0,0,0.446-0.738,1.231-0.814c0.785-0.079,1.004,0.156,1.371,0.2c0.04,0.004,0.078,0.008,0.115,0.013c0.013,0.002,0.025,0.002,0.037,0.004c0.025,0.002,0.051,0.004,0.075,0.006c0.014,0.001,0.027,0.003,0.041,0.003c0.021,0.001,0.043,0.003,0.064,0.004c0.014,0.001,0.028,0.002,0.041,0.003c0.02,0.001,0.04,0.001,0.058,0.003c0.014,0,0.026,0,0.042,0c0.019,0.001,0.036,0.002,0.055,0.002c0.013,0.001,0.026,0.001,0.038,0.002c0.017,0,0.034,0,0.051,0c0.011,0,0.023,0,0.034,0c0.017,0,0.033,0,0.05,0c0.011,0,0.02-0.001,0.032-0.001c0.016-0.001,0.031-0.001,0.046-0.001c0.011-0.001,0.02-0.001,0.03-0.002c0.016,0,0.03-0.002,0.045-0.002c0.009,0,0.019,0,0.026-0.001c0.016-0.001,0.03-0.002,0.044-0.004c0.006,0,0.016-0.001,0.023-0.002c0.015-0.001,0.029-0.001,0.044-0.003c0.006-0.001,0.013-0.002,0.02-0.002c0.016-0.002,0.03-0.004,0.045-0.008c0.004,0,0.008,0,0.013-0.001c0.019-0.002,0.036-0.005,0.052-0.008l0,0c0.035-0.006,0.068-0.014,0.098-0.021c0,0,0,0,0.002-0.002c0.012-0.002,0.026-0.005,0.039-0.01c0.002,0,0.004,0,0.008-0.001c0.009-0.003,0.019-0.006,0.028-0.009c0.004,0,0.007-0.002,0.01-0.003c0.009-0.003,0.019-0.007,0.026-0.009c0.002-0.001,0.005-0.002,0.008-0.003c0.008-0.003,0.015-0.006,0.021-0.009c0.004-0.001,0.006-0.003,0.009-0.003c0.007-0.004,0.014-0.005,0.02-0.009c0.003-0.001,0.006-0.003,0.008-0.004c0.005-0.002,0.012-0.005,0.019-0.007c0.001-0.001,0.003-0.002,0.005-0.004c0.005-0.003,0.01-0.005,0.016-0.007c0.002-0.002,0.003-0.002,0.006-0.004c0.004-0.001,0.008-0.005,0.012-0.007c0.002-0.001,0.004-0.001,0.005-0.003c0.004-0.002,0.008-0.006,0.012-0.008c0.001,0,0.003-0.002,0.004-0.003c0.003-0.003,0.007-0.004,0.011-0.007c0.001-0.001,0.001-0.001,0.002-0.003c0.004-0.001,0.006-0.005,0.008-0.008h0.002c0.003-0.002,0.005-0.005,0.008-0.007l0.001-0.001c0.002-0.002,0.004-0.004,0.006-0.006s0.002-0.002,0.003-0.003c0.001,0,0.002-0.002,0.002-0.002c0.001-0.003,0.001-0.003,0.003-0.005c0.003-0.001,0.003-0.004,0.003-0.004c0.328-0.241,0.593-0.516,0.797-0.775c0.014-0.017,0.026-0.033,0.04-0.05c0.002-0.004,0.005-0.009,0.008-0.012c0.013-0.015,0.026-0.031,0.038-0.048c0.002-0.004,0.006-0.008,0.007-0.011c0.012-0.018,0.025-0.033,0.038-0.05c0.001,0,0.001,0,0.001-0.001c0.039-0.054,0.075-0.109,0.109-0.159c0-0.002,0.002-0.004,0.003-0.007c0.01-0.016,0.02-0.029,0.03-0.044c0.001-0.004,0.005-0.007,0.007-0.011c0.008-0.014,0.017-0.029,0.024-0.042c0.003-0.004,0.005-0.009,0.009-0.013c0.008-0.014,0.017-0.028,0.024-0.042l0.001-0.002c0.017-0.027,0.032-0.055,0.046-0.079c0.002-0.003,0.004-0.008,0.007-0.012c0.005-0.009,0.01-0.021,0.016-0.03c0.003-0.007,0.007-0.014,0.012-0.02c0.004-0.008,0.01-0.017,0.014-0.024c0.002-0.008,0.006-0.017,0.011-0.023c0.004-0.007,0.009-0.016,0.012-0.022c0.004-0.007,0.007-0.014,0.011-0.021c0.002-0.006,0.007-0.011,0.01-0.018c0.066-0.13,0.097-0.207,0.097-0.207c0.594-1.459,0.052-2.935-0.21-3.224c-0.32-0.354-1.041-0.883-1.041-0.883s-0.426-0.357-1.08-0.025c-0.521,0.264-0.711,0.201-0.711,0.201c-0.024-0.498,0.149-1.432,0.491-2.263c0.341-0.829,1.075-2.253,1.075-2.253s1.047-1.792,1.467-2.89c0.418-1.102,0.415-1.94,0.415-1.94s-0.795-1.019-0.91-1.177c-0.115-0.158-0.272-0.223-0.272-0.223c-0.205,0.078-0.345,0.103-0.345,0.103l0.169-0.14c0,0,0.424-0.492,1.073-0.334c0.648,0.158,1.119-0.126,1.119-0.126c1.011-0.764,1.654-2.187,1.654-2.187l0.988-1.997L27.059,1.12c0,0-0.131-0.028-0.979,0.259c0,0-0.773,1.905-1.725,3.087c0,0-0.374,0.552-0.664,0.416c-0.289-0.134-0.629-0.144-0.91-0.085c-0.281,0.06-1.156,0.349-1.948,1.413c-0.79,1.064-0.883,1.863-0.458,2.101c0.425,0.238,1.045-0.076,1.42-0.407c0.375-0.333,0.638-0.485,0.757-0.47c0.118,0.02,0.093,0.315,0.068,0.41c-0.026,0.094-0.154,1.364-1.625,3.913c-0.369,0.64-0.845,1.589-1.069,2.046l0.608,0.447l-0.999,0.503c-0.266,0.758-0.605,1.945-0.471,2.61c0.204,1.011,1.158,1.011,1.158,1.011s0.621,0.027,1.344-0.348c0.722-0.375,0.892,1.242,0.892,1.505c0,0.264-0.007,1.726-1.02,2.442c0,0-0.409,0.313-0.985,0.313c-0.579,0-0.954-0.169-0.954-0.169s-0.984-0.272-1.59,0.083c-0.604,0.358-1.326,1.098-1.897,2.17c-0.569,1.072-1.045,2.986-1.019,4.397c0.02,1.111,0.18,2.162,0.291,2.879l0.667,0.435l-0.543,0.623c0.079,1.136,0.168,3.363,0.155,4.109c-0.018,0.911-0.154,2.84-1.115,3.292c0,0-0.324,0.171-0.868-0.238s-1.132-0.426-1.37-0.435c-0.238-0.007-1.285,0.162-1.692,1.311c-0.408,1.145-0.375,2.688-0.29,3.597c0.086,0.91,0.876,2.458,1.872,2.458c0,0,0.484,0.035,1.055-0.553c0.568-0.586,0.902-0.637,1.156-0.629c0.255,0.009,0.749,0.272,1.072,2.851c0.307,2.442,0.437,4.442,0.414,6.668l0.605,0.392l-0.758,0.768c-0.042,0.199-0.089,0.417-0.142,0.626c-0.169,0.682-0.187,1.364-0.024,2.569c0.161,1.21,0.811,3.72,1.754,4.375c1.252,0.871,2.071,0.856,2.916,0.791c0.842-0.067,1.424-0.712,1.424-0.712s0.331-0.342,0.685-0.237c0.356,0.104,1.346,0.66,2.058,2.084c0.713,1.425,0.871,2.992-0.316,3.272c-1.187,0.272-3.231-0.846-3.231-0.846s-1.161-0.647-2.109,0.064c-0.951,0.713-0.977,1.807-0.502,3.15c0.261,0.738,0.782,1.938,1.513,3.188l0.721,0.302l-0.193,0.551c0.492,0.748,1.055,1.479,1.678,2.105c0,0,2.466,2.729,3.838,4.457c0,0,0.08,0.157-0.158,0.016c-0.238-0.146-1.266-0.621-1.82-0.566c-0.555,0.054-0.45,0.395-0.45,0.395s0.238,1.254,4.01,3.365c0,0,1.359,0.766,2.216,0.766c0,0,0.277,0.039,0.619-0.346c0.346-0.381,0.45-0.341,0.688-0.262c0.237,0.076,0.553,0.249,1.741,1.105c1.188,0.857,3.496,2.176,4.325,2.731c0.83,0.555,0.793,0.657,0.621,1.054c-0.171,0.396,0.593,0.619,0.593,0.619s1.899,0.855,2.928,0.846c1.029-0.016,1.464-0.119,2.097,0.012c0.632,0.133,1.28,0.291,1.345,0.346c0.066,0.053-0.315,0.038-0.315,0.038s-2.362-0.276-2.494-0.21c-0.13,0.066,0.014,0.184,0.99,0.436v0.006c1.245,0.217,2.507,0.387,3.782,0.51c-0.489-0.061-2.52-0.322-3.823-0.713c0,0-0.131-0.078,0.173-0.014c0.303,0.065,2.018,0.225,2.466,0.157c0.448-0.065-0.092-0.274-0.092-0.274s-0.897-0.425-2.889-0.582c0,0-0.803-0.055-1.503,0.014c-0.699,0.066-1.41-0.264-1.41-0.264s-1.028-0.317-0.78-0.646c0.126-0.165,0.137-0.336,0.065-0.502L38.188,89.707L38.188,89.707z"/><linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="444.7598" y1="550.8145" x2="473.8418" y2="550.8145" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#231F20"/><stop offset="1" stop-color="#474747"/></linearGradient><path style="&st5;" d="M62.342,86.16l-0.438,0.646c0.096,0.655-0.104,0.875-0.254,1.119c-0.156,0.26-0.59,0.592-0.375,1.185c0.218,0.59,1.687,0.401,2.535,0.144c0.852-0.26,1.569-0.49,2.134-0.693c0.562-0.198,0.719,0.086,0.719,0.086s0.246,0.175-0.574,0.606c-0.821,0.433-2.336,0.634-3.055,0.72c-0.724,0.086-0.506-0.043-1.586,0.33c-1.082,0.377-0.07,0.707-0.07,0.707c2.435,0.635,4.188,0.115,4.188,0.115l0.332-0.097c0.27-0.077,0.535-0.161,0.803-0.244c-2.021,0.456-3.326,0.149-3.739,0.095c-0.431-0.058-0.778-0.145-0.88-0.361c-0.102-0.215,0.479-0.2,0.479-0.2s1.683-0.188,3.24-0.69c1.557-0.506,1.932-0.98,1.871-1.341c-0.057-0.358-0.848-0.332-1.785-0.028c-0.937,0.305-2.334,0.75-2.662,0.821c-0.334,0.07-0.691,0.06-0.812-0.146c-0.114-0.203-0.216-0.53,0.146-0.905c0.36-0.376,0.402-0.694,0.402-0.694c0.055-0.254,0.057-0.523,0.021-0.8L62.342,86.16l0.545-0.118c-0.298-1.124-1.052-2.218-1.279-2.577c-0.314-0.507-0.836-0.793-2.393-0.535c-1.556,0.26-3.386,1.035-3.386,1.035s-1.888,0.997-3.298,0.812c-1.413-0.188-1.703-1.614-1.688-2.063c0.015-0.447,0.304-0.835,1.039-1.123c0.735-0.289,2.465-0.678,4.985-0.808s3.458-1.771,3.458-1.771c0.33-0.478,0.922-1.543-0.489-2.336c-1.41-0.791-1.441-0.593-2.119-1.107c-0.678-0.52-1.412-1.153-1.701-2.033c-0.025-0.084-0.066-0.197-0.104-0.292l-0.849-0.558l0.41-0.371c-0.34-0.67-0.693-1.271-0.693-1.271s-1.281-1.902-0.246-3.703c1.038-1.803,2.736-2.348,2.736-2.348s1.5-0.332,2.996,0.016c1.418,0.324,2.133-0.219,2.133-0.219s0.865-0.374,1.123-2.102c0.264-1.729-0.014-4.943-2.316-5.578c-2.307-0.633-3.527,0.563-3.527,0.563s-1.24,1.369-1.644,1.57c-0.404,0.201-1.022,0.563-1.022,0.563s-0.867,0.519-1.453,0.648c-0.393,0.086-1.791-1.771-1.933-3.201c-0.133-1.316-0.401-2.388-0.306-5.096l-0.485-0.63l0.537-0.533c0.101-2.999-0.417-5.116-1.188-6.461c-0.807-1.412-2.119-2.161-2.766-2.478c-0.648-0.318-2.147-0.462-3.17-0.086c-1.023,0.374-1.239,0.678-1.613,1.326c-0.376,0.648-0.836,0.605-0.836,0.605s-1.427,0.043-1.888-2.133c-0.646-3.049,0.359-4.035,0.359-4.035s0.318-0.476,1.369-0.619c1.053-0.144,1.73,0.115,2.537,0.315c0.806,0.202,1.41,0.116,2.419-0.374c1.008-0.491,1.442-1.297,1.238-2.739c-0.195-1.393-0.255-1.742-1.483-5.964l-0.875-0.46l0.583-0.579C44.87,23.032,44.8,20.35,44.8,20.35c-0.106-0.977,0.049-1.292,0.598-1.54c0.576-0.259,1.116-0.175,1.934-0.123c0.818,0.053,1.425-0.079,1.847-0.316c0.422-0.237,1.581-0.87,1.504-2.162c-0.08-1.292-1.109-2.824-1.953-3.351c-0.843-0.528-1.953-0.316-2.558,0.131c-0.606,0.45-0.845,1.029-1.214,1.214c-0.369,0.183-0.895,0.605-1.45,0.474c-0.554-0.132-0.581-1.371-0.818-2.77c-0.153-0.907-0.271-1.611-0.338-1.989l-0.678-0.254c0.044,0.557,0.535,3.304,0.535,3.304s0.223,1.364,0.308,1.692c0.086,0.329,0.314,1.05,0.314,1.05s0.092,0.364,0.456,0.535c0.365,0.172,1.052,0.24,1.743-0.032c0.692-0.271,0.886-0.572,1.199-0.938c0.315-0.364,0.429-0.493,0.429-0.493s0.663-0.622,1.478-0.343c0.813,0.278,1.299,1.228,1.299,1.228l0.028,0.06c0,0,0.403,0.661,0.392,1.269v-0.057c0,0-0.022,0.301-0.697,0.818c-0.676,0.519-1.226,0.479-1.678,0.442c-0.454-0.04-0.666-0.072-0.797-0.045l-0.719,0.038C45.178,18.303,44.74,18.6,44.74,18.6c-1.8,1.064,0.736,9.288,0.736,9.288l0,0L45.2,28.501c0,0,0.514,2.052,0.904,3.378c0.388,1.326,0.562,2.637,0.62,2.91c0.058,0.274,0.044,0.762-0.317,1.051c-0.359,0.289-1.239,0.534-1.425,0.562c-0.187,0.029-0.535-0.042-0.996-0.201c-0.462-0.158-0.922-0.187-0.922-0.187s-1.11-0.188-2.291,0.173c-1.182,0.359-2.076,1.569-2.148,3.083c-0.071,1.513-0.057,2.278,0.535,3.617c0.59,1.34,1.657,2.104,2.463,2.118c0.808,0.014,1.469-0.403,1.931-1.051c0.459-0.65,0.59-0.751,0.59-0.751c0.548-0.302,1.944-0.433,2.651-0.172c0.708,0.258,2.007,1.073,2.723,2.679c0.579,1.298,0.76,2.75,0.729,5.363l0.584,0.448l-0.61,0.703c-0.007,0.246-0.016,0.498-0.026,0.761c-0.143,3.876,0.72,5.864,0.72,5.864c0.491,1.065,1.023,1.83,1.745,2.318c0.719,0.489,1.699,0.156,2.018,0c0.315-0.158,1.194-0.563,1.943-1.037c0.749-0.477,0.725-0.679,1.629-1.515c0.907-0.833,2.076-0.604,2.076-0.604s1.107,0.028,1.74,1.313c0.637,1.283,0.509,3.109,0.347,3.773c-0.158,0.662-0.444,1.097-1.063,0.979c-0.621-0.114-1.645-0.217-2.019-0.231c-0.375-0.014-1.433-0.049-2.394,0.203c-0.938,0.244-2.205,0.92-3.414,2.883c-0.938,1.52-0.478,3.013-0.262,3.603c0.17,0.462,0.635,1.104,1.043,1.896l0.756,0.252l-0.35,0.656c0.398,0.963,0.701,1.493,1.305,2.151c0.648,0.705,1.672,1.251,2.881,1.714c1.213,0.462,0.662,1.282,0.662,1.282c-0.69,1.497-2.75,1.557-3.354,1.628c-0.604,0.07-1.872,0.188-3.058,0.447c-1.182,0.261-2.291,0.418-2.954,1.182c-0.661,0.764-0.402,1.557-0.013,2.393c0.388,0.834,1.427,1.28,2.853,1.226c1.426-0.058,2.35-0.476,3.214-0.851s2.362-0.809,2.81-0.937c0.445-0.129,1.051-0.39,1.498,0.26c0.482,0.701,0.994,1.697,1.229,2.45L62.342,86.16L62.342,86.16z"/><path style="&st34;" d="M101.566,51.162c0,0,0.347-3.236,0.457-4.392c0.018-0.173,0.031-0.343,0.045-0.513l-0.098-0.241c-0.459,5.815-0.938,7.727-0.938,7.727s0.013-0.037,0.031-0.101c0.189-0.817,0.357-1.646,0.51-2.48C101.568,51.162,101.566,51.162,101.566,51.162L101.566,51.162z"/><path style="&st34;" d="M91.268,12.579l0.328,0.413l0.279,0.5c1.021,1.648,2.846,4.295,2.846,4.295s0.739,0.958,0.905,0.968c0.164,0.01-0.084-0.741-0.084-0.741s-0.271-0.979,0.517,0.298c0.73,1.19,1.207,2.359,1.317,2.72c0.114,0.361,0.042,0.411,0.042,0.411s-0.146,0.072-0.146,0.33c0,0.505,0.496,1.659,0.496,1.659s1.545,3.926,2.07,5.563c0.526,1.641,1.133,4.368,1.133,4.368s0.187,0.804,0.207,1.174c0.021,0.371-0.063,0.381-0.229,0.186c-0.164-0.196-0.329-0.072-0.329-0.072s-0.175,0.072-0.175,0.773c0,0.7,0.085,2.346,0.217,3.615c0.152,1.505,0.616,2.133,0.616,2.133s0.413,0.618,0.526-0.577c0.096-1.028,0.185-0.228,0.185-0.228c0.196,1.557,0.062,4.544,0.03,4.955c-0.019,0.218-0.032,0.433-0.049,0.64l0.133-0.221c0.201-2.971,0.06-5.359,0.06-5.359s-0.144-1.323-0.3-1.311c-0.155,0.01-0.211,0.701-0.211,0.701s-0.065,0.467-0.156,0.456c-0.088-0.011-0.369,0.022-0.566-1.412c-0.199-1.436-0.156-2.949-0.156-2.949s-0.043-0.155,0.048-0.189c0.09-0.034,0.188,0.1,0.188,0.1s0.133,0.189,0.287,0.033c0.156-0.154,0.19-0.622-0.301-3.08c-0.288-1.454-0.711-2.896-1.006-3.832l-0.294-0.333l-0.058-0.718c0,0-0.311-0.913-1.033-2.737c-0.723-1.824-0.846-2.458-0.846-2.458s-0.045-0.2,0.066-0.234c0.111-0.032,0.091-0.178,0.091-0.178s-0.013-0.245-0.278-0.99c-0.268-0.746-0.426-1.281-1.356-2.86c-0.869-1.468-1.124-1.558-1.124-1.558s-0.426-0.234-0.112,0.591c0.313,0.823-0.075,0.232-0.075,0.232c-0.925-1.177-2.838-4.292-2.838-4.292l-0.537-0.373l-0.508-1.261l-0.015,0.01"/><path style="&st34;" d="M1.547,32.696l-0.183,0.37c-0.472,2.495-0.625,5.135-0.62,5.31c0.01,0.208-0.036,0.211-0.075,0.178c-0.042-0.035,0.03-0.16-0.048-0.16c-0.079,0-0.108,0.211-0.108,0.211L0.512,38.6c-0.021,0.288-0.038,0.574-0.053,0.861l0.016-0.003c0.068-0.098,0.097-0.028,0.097-0.028s-0.029,0.126,0.097,0.056c0.126-0.07,0.21-1.379,0.21-1.379s0.014-2.813,0.836-6.14c0.819-3.327,1.281-4.259,1.281-4.259s0.154-0.418,0.138-0.083C3.12,27.958,3.33,27.986,3.33,27.986c0.375-0.054,0.821-1.125,1.267-2.493c0.445-1.363,0.668-2.589,0.668-2.7c0-0.11-0.055-0.194-0.152-0.138c-0.098,0.056-0.125,0.014-0.125,0.014c-0.014-0.208,0.361-1.127,0.361-1.127c1.253-3.202,3.104-5.694,3.104-5.694l0.09-0.504c-0.164,0.254-0.27,0.419-0.421,0.661c-0.056,0.089-0.042,0.297-0.001,0.32c-0.201,0.191-0.365,0.35-0.476,0.456c-2.707,4.473-3.059,6.556-3.059,6.556c-0.017,0.214,0.004,0.311,0.111,0.306c0.065-0.003,0.251-0.349,0.116,0.354c-0.09,0.468-0.524,1.708-0.693,2.212c-0.171,0.505-0.358,0.85-0.495,0.826C3.49,27.01,3.49,26.801,3.49,26.801s-0.042-0.546-0.398,0.245c-0.356,0.791-0.713,1.859-1.425,4.65c-0.031,0.125-0.063,0.251-0.092,0.38L1.547,32.696L1.547,32.696z"/><path style="&st34;" d="M4.841,62.626c-0.15-0.401-0.264-0.722-0.179-0.581c0.085,0.143,0.198,0.432,0.462,0.725c0.263,0.291,0.442-0.226-0.622-3.104s-1.354-3.04-1.402-3.095c-0.046-0.058-0.215-0.237-0.167,0.167c0.045,0.404,0.018,0.656-0.51-1.146c-0.528-1.806-0.996-4.844-1.025-5.089c-0.027-0.243-0.169-1.778-0.396-3.594c-0.226-1.814-0.246-3.743-0.207-4.28c0.039-0.537-0.066-0.828-0.123-0.837c-0.056-0.008-0.094,0.047-0.131,0.284c-0.038,0.234-0.01,0.395-0.067,0.385c-0.057-0.009-0.076-0.471-0.076-0.471H0.391c0,0.05,0,0.1,0,0.151c0,0.174,0.001,0.345,0.002,0.519l0.039,0.402c0.033,0.597,0.129,0.354,0.135,0.246c0.006-0.109,0.03-0.329,0.03-0.329s0.103-0.884,0.084,0.02c-0.019,0.904,0.236,4.563,0.236,4.563c0.019,0.236,0.041,0.479,0.068,0.729l0.063,0.092l-0.042,0.104c0.265,2.425,0.795,5.086,0.795,5.086c0.507,2.417,1.11,3.846,1.308,4.25c0.198,0.405,0.236,0.085,0.17-0.271c-0.066-0.357,0.546,0.688,0.873,1.674c0.332,0.99,0.556,1.815,0.556,1.815s0.254,0.781,0.142,0.828c-0.113,0.046-0.292-0.293-0.292-0.293s-0.473-0.835-0.274-0.228c0.398,1.231,1.6,3.822,1.6,3.822l1.396,2.471C6.282,65.836,4.982,63.004,4.841,62.626L4.841,62.626z"/><path style="&st34;" d="M7.281,67.639c0.069,0.125,0.136,0.246,0.202,0.359L7.281,67.639z"/><path style="&st34;" d="M20.722,2.874C20.51,3.216,20.48,3.388,20.48,3.388s0.112-0.118,0.183-0.237C20.733,3.033,20.722,2.874,20.722,2.874z"/><path style="&st34;" d="M17.216,5.572c-0.417,0.048-0.677,0.25-0.677,0.25S16.889,5.761,17.216,5.572z"/><path style="&st34;" d="M84.005,4.909c0,0,0.247-0.03,0.347,0.02c0.101,0.049,0.066-0.158,0.066-0.158s-0.287-0.406-0.322-0.556c-0.32-0.089-0.611-0.1-0.611-0.1l-0.028,0.034c-0.01,0.075-0.036,0.188-0.012,0.297C83.441,4.448,83.917,4.811,84.005,4.909L84.005,4.909z"/><path style="&st34;" d="M87.487,7.88l0.095-0.152l-0.223-0.679c-0.004-0.012-0.012-0.022-0.021-0.036c-0.007,0.066-0.049,0.125-0.172,0.115c0,0-0.099-0.03-0.011,0.198C87.219,7.469,87.355,7.699,87.487,7.88L87.487,7.88z"/><path style="&st34;" d="M101.566,51.162c0,0,0.347-3.236,0.457-4.392c0.018-0.173,0.031-0.343,0.045-0.513l-0.098-0.241c-0.459,5.815-0.938,7.727-0.938,7.727s0.013-0.037,0.031-0.101c0.189-0.817,0.357-1.646,0.51-2.48C101.568,51.162,101.566,51.162,101.566,51.162L101.566,51.162z"/><linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="266.4922" y1="-395.2783" x2="295.9644" y2="-485.0349" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset=".0094" stop-color="#FCFCFC"/><stop offset=".0655" stop-color="#EEEEEE"/><stop offset=".1342" stop-color="#E5E5E5"/><stop offset=".2515" stop-color="#E3E3E3"/><stop offset=".3357" stop-color="#8A8A8A"/><stop offset=".4422" stop-color="#B8B8B8"/><stop offset="1" stop-color="#3B3B3B"/></linearGradient><path style="&st33;" d="M79.003,84.528c0,0,0.667-0.653,0.539-0.752c-0.128-0.101-0.623,0.256-0.623,0.256s-0.073,0.062-0.185,0.142l0.393-0.252c0,0-0.038,0.238-0.355,0.555c0,0-0.094,0.094-0.258,0.248c-0.957,0.938-2.386,1.998-2.386,1.998l0.396-0.211C77.844,85.703,79.003,84.528,79.003,84.528z"/><linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="460.4629" y1="512.5557" x2="509.5884" y2="573.3062" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EFF0F0"/><stop offset=".5914" stop-color="#F0F1F2"/><stop offset=".599" stop-color="#787878"/><stop offset=".6456" stop-color="#EEEFF0"/><stop offset="1" stop-color="#D8D9DB"/></linearGradient><path style="&st30;" d="M82.984,39.705l0.51-0.891l-0.127-1.667c0,0-0.085-0.893-0.566-2.28c-0.979-2.828-1.941-4.122-1.941-4.122s-0.592-1.318-1.969-1.318c-1.33,0-1.431,1.219-1.431,1.219s-0.312,0.963-0.821,1.261c-0.5,0.29-1.972,1.146-2.748,0.296c-0.941-1.026-1.461-2.225-1.56-3.372c-0.101-1.146,0.367-1.615,0.367-1.615s0.1-0.296,1.614-0.296c1.703,0,2.014-0.525,2.014-0.525s0.324-0.296,0.297-0.963s-0.284-2.097-0.779-3.001c-0.324-0.596-1.058-1.537-1.684-2.261l-0.967-0.178l0.15-0.699c-0.56-0.514-3.465-3.959-4.031-4.766c-0.564-0.808-0.65-0.993-0.75-1.262c-0.099-0.269,0.17-0.877,0.412-1.161c0.238-0.283,0.521-0.341,1.104-0.212c0.58,0.127,0.961,0.381,1.886,0.084c0.919-0.297,0.962-0.992,1.033-1.699c0.071-0.708-0.78-2.209-1.458-2.932c-0.684-0.721-1.645-0.836-2.311-0.792c-0.664,0.042-1.047,0.523-1.433,0.737c-0.382,0.213-1.103,0.425-1.429,0.284c-0.326-0.142-0.823-0.284-1.375-1.261c-0.43-0.76-0.794-1.459-0.979-1.817L63.299,4.42v0.012c0,0,0.633,1.654,1.633,2.811c0.998,1.157,2.266,0.919,2.266,0.919s0.82-0.089,1.533-0.772c0.711-0.683,1.761-0.148,2.024,0.04c0.269,0.189,0.853,0.911,1.478,2.127c0.621,1.216-0.355,2.058-0.355,2.058s-0.555,0.535-1.691,0.088c-1.14-0.443-1.813,0.259-1.986,0.614c-0.182,0.357-0.508,0.99,0.076,1.73c0.584,0.742,3.178,4.273,4.916,5.945c1.74,1.672,2.314,3.047,2.682,4.342c0.365,1.297,0.079,1.899-0.521,2.018c-0.604,0.118-1.148,0.021-2.086,0.187c-0.94,0.17-1.349,0.367-1.543,1.653c-0.199,1.286,0.562,3.373,1.67,4.361c1.106,0.989,2.334,0.386,2.76,0.228c0.427-0.159,1.352-0.653,1.681-2.027c0.188-0.783,0.851-0.721,0.851-0.721s0.563-0.071,0.854,0.117c0.287,0.19,0.633,0.525,1.402,1.87c0.772,1.346,1.453,3.146,1.724,4.738C82.924,38.35,82.729,38.576,82.984,39.705c0.256,1.128,1.078,3.245,1.466,4.074c0.383,0.832,0.78,1.662,0.989,2.107c0.205,0.445,0.531,0.782,1.443,0.802c0.908,0.02,1.273-0.228,1.541-0.662c0.27-0.435,0.612-1.088,0.713-1.316c0.1-0.228,0.467-0.911,1.146-1.02c0.685-0.108,1.762,0.01,2.106,1.198c0.313,1.071,0.76,2.622-0.158,4.5c-0.65,1.334-1.129,0.859-2.451,0.948c0,0-1.165-0.01-1.781,0.921c-0.611,0.93-0.416,2.61-0.286,3.877s0.988,3.113,1.621,3.563c0.636,0.443,0.86,0.849,1.08,1.256c0.216,0.404,0.534,1.205,0.216,3.313c-0.313,2.106-0.979,3.74-1.867,4.521c-0.024,0.021-0.05,0.043-0.07,0.063c-0.067,0.065-0.141,0.135-0.219,0.201c-0.537,0.521-0.371,0.543-0.889,0.793c-0.594,0.289-0.988,0.207-1.958,0.365c-0.97,0.16-1.583,0.327-2.088,0.821c-0.503,0.495-1.243,1.409-0.979,3.187c0.148,0.986,1.318,0.584,2.229,0.111c-0.274,0.125-0.553,0.221-0.798,0.246c-1.033,0.113-0.991-0.949-0.921-1.415c0.069-0.47,0.313-1.544,1.063-1.97s1.799-0.41,2.533-0.512c0.738-0.101,1.076-0.313,1.076-0.313s1.205-0.766,1.997-2.055c0.793-1.289,1.502-3.371,1.587-5.438c0.084-2.068-0.821-2.902-1.104-3.271c-0.283-0.366-0.799-0.203-1.431-1.729c-0.724-1.74-0.81-3.188-0.751-4.079c0.057-0.892,0.27-1.231,0.682-1.612c0.41-0.383,2.223-0.213,2.223-0.213s0.893,0.185,1.686-1.134c0.793-1.317,0.738-3.471,0.481-4.546c-0.253-1.076-0.623-2.013-2.097-2.168c-1.471-0.152-2.138,1.66-2.138,1.66s-0.297,0.693-0.608,1.092c-0.312,0.395-1.16,0.285-1.16,0.285c-0.37-0.044-0.821,0.099-1.264-0.81c-0.438-0.906-1.442-3.286-1.442-3.286c-0.339-0.809-0.556-1.512-0.688-2.055L82.984,39.705L82.984,39.705z"/><linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="272.8721" y1="-392.8257" x2="302.4699" y2="-482.9646" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st9;" d="M82.487,79.313l0.801-0.479c0.788-1.231,1.72-2.31,2.431-3.103c0.863-0.961,1.896-2.522,1.896-2.522s0.835-1.431,0.638-1.784c-0.13-0.23-0.704,0.02-1.687,0.752c-3.674,2.746-3.971,1.246-3.971,1.246c0.422,2.438,4.729-1.633,5.108-1.375c-0.063,0.563-0.457,1.172-1.25,2.25c0,0-0.388,0.555-0.78,0.953c-0.369,0.432-0.578,0.641-0.578,0.641s-0.088,0.09-0.125,0.125c-0.471,0.541-1.024,1.242-1.595,2.018c-0.019,0.021-0.104,0.113-0.125,0.143c-0.295,0.416-0.491,0.73-0.702,1.062c-0.014,0.022-0.064,0.011-0.076,0.034c0-0.002-0.013,0.014-0.025,0.037c-0.245,0.39-0.373,0.713-0.508,0.959c-0.012,0.029-0.021,0.065-0.03,0.095c0,0-0.319,0.665-0.457,1.067c-0.14,0.405-0.12,0.547-0.623,0.625c-0.504,0.078-0.276-0.053-1.021,0.196c0,0-0.403,0.199-0.938,0.571c-0.027,0.021-0.057,0.042-0.082,0.063c-0.736,0.604-1.247,1.119-1.534,1.436c-0.051,0.063-0.099,0.13-0.146,0.195c0,0-0.157,0.168,0.051,0.188c0.206,0.021,0.633-0.01,1.008-0.169l0.088-0.057c-0.186,0.103-0.373,0.174-0.513,0.162c-0.396-0.026,0.479-0.864,0.479-0.864s0.906-1.019,1.771-1.175c0.862-0.156,1.021-0.371,1.444-0.693c0.426-0.327,0.494-0.682,1.359-2.254c0.03-0.059,0.064-0.115,0.098-0.176L82.487,79.313L82.487,79.313z"/><linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="444.6943" y1="510.9561" x2="469.7246" y2="592.0699" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#FFF"/><stop offset=".7473" stop-color="#F9F9F9"/><stop offset="1" stop-color="#D5D7D8"/></linearGradient><path style="&st27;" d="M55.064,72.686l0.408-0.377c-0.34-0.668-0.693-1.269-0.693-1.269s-1.282-1.901-0.245-3.703c1.036-1.803,2.737-2.348,2.737-2.348s1.5-0.332,2.996,0.017c1.418,0.323,2.133-0.22,2.133-0.22s0.865-0.376,1.123-2.104c0.261-1.729-0.014-4.94-2.317-5.576c-2.306-0.633-3.528,0.563-3.528,0.563s-1.242,1.369-1.644,1.57c-0.404,0.2-1.024,0.562-1.024,0.562s-0.865,0.52-1.453,0.648c-0.39,0.087-1.788-1.771-1.931-3.2c-0.133-1.313-0.4-2.385-0.305-5.084c0-0.005,0-0.01,0-0.017l-0.486-0.629l0.537-0.526c0.102-3-0.418-5.119-1.188-6.463c-0.805-1.414-2.118-2.163-2.766-2.479c-0.647-0.317-2.146-0.461-3.169-0.086c-1.022,0.375-1.237,0.677-1.613,1.325c-0.376,0.65-0.835,0.606-0.835,0.606s-1.427,0.044-1.89-2.132c-0.644-3.049,0.36-4.036,0.36-4.036s0.318-0.475,1.369-0.619c1.053-0.144,1.73,0.115,2.536,0.317c0.807,0.2,1.41,0.114,2.42-0.374c1.009-0.49,1.442-1.298,1.24-2.738c-0.196-1.397-0.249-1.727-1.484-5.966l-0.874-0.458l0.582-0.579c-1.182-4.271-1.257-6.961-1.257-6.961c-0.105-0.975,0.049-1.29,0.598-1.537c0.576-0.261,1.117-0.177,1.934-0.125c0.819,0.052,1.425-0.079,1.847-0.316c0.423-0.236,1.583-0.87,1.503-2.163c-0.078-1.292-1.108-2.823-1.951-3.35c-0.844-0.528-1.952-0.317-2.56,0.132c-0.606,0.447-0.843,1.028-1.213,1.212c-0.368,0.185-0.896,0.607-1.45,0.474c-0.554-0.132-0.581-1.372-0.818-2.77c-0.155-0.915-0.276-1.614-0.342-1.989l-0.674-0.254c0.043,0.557,0.535,3.304,0.535,3.304l0.294,1.624c0,0,0,0.007,0,0.02c0.006,0.018,0.009,0.036,0.013,0.05c0.019,0.079,0.049,0.18,0.082,0.289c0.114,0.215,0.37,0.456,0.942,0.502c1.076,0.089,1.772-0.468,2.025-0.709c0.254-0.239,0.86-0.911,0.86-0.911s0.329-0.632,1.253-0.494c0.922,0.14,1.238,0.773,1.403,1.013c0.167,0.242,1.57,1.961,0.672,2.861c-0.039,0.039-0.093,0.089-0.152,0.146c-0.104,0.111-0.245,0.246-0.446,0.399c-0.675,0.517-1.226,0.48-1.678,0.442c-0.453-0.039-0.665-0.07-0.795-0.043l-0.72,0.038c-0.787,0.11-1.224,0.408-1.224,0.408c-1.8,1.065,0.735,9.287,0.735,9.287s0.671,2.029,0.973,2.979c0.301,0.949,0.496,1.625,0.791,3.264c0.295,1.639-0.231,2.092-0.525,2.251c-0.294,0.158-0.984,0.568-1.77,0.604c-0.783,0.034-1.027-0.368-2.371-0.432c-1.345-0.065-2.246,0.345-2.661,0.906c-0.417,0.561-0.913,1.862-0.675,3.4c0.237,1.541,0.504,2.064,1.092,2.748c0.59,0.681,1.165,0.97,1.978,0.696c0.792-0.266,0.764-0.756,1.173-1.164c0.517-0.519,0.855-0.792,2.063-0.821c1.208-0.029,1.979,0.288,2.594,0.784c0.619,0.496,1.934,1.646,2.294,3.356c0.359,1.713,0.424,2.268,0.424,3.676s-0.101,2.978-0.064,4.381c0.036,1.4,0.187,2.841,0.577,3.795c0.386,0.955,0.926,1.755,1.4,2.18c0.475,0.426,0.896,0.438,1.373,0.252c0.475-0.188,1.511-0.771,2.373-1.324c0.861-0.555,0.797-0.99,1.576-1.502c0.875-0.576,1.799-0.605,2.457-0.486c0.661,0.112,1.676,0.631,2.092,1.889C63.059,60.58,63,61.998,63,61.998s0.035,1.186-0.445,1.876c-0.48,0.688-1.272,0.616-1.625,0.545c-0.354-0.071-1.094-0.136-1.094-0.136s-1.451-0.165-2.563,0.094c-1.105,0.258-2.077,1.085-2.73,1.896c-0.652,0.813-0.941,1.57-0.984,2.158c-0.043,0.59,0.027,1.595,0.642,2.572c0.612,0.979,0.712,1.432,1.409,2.827c0.695,1.396,2.15,2.17,2.201,2.206c0.05,0.037,1.388,0.523,1.89,0.949c0.505,0.425,0.555,0.826,0.411,1.208c-0.145,0.381-0.438,1.094-1.604,1.604c-1.166,0.512-2.591,0.523-3.496,0.617c-0.906,0.094-2.651,0.332-3.697,0.834c-1.043,0.503-0.97,1.454-0.97,1.454s-0.028,1.556,1.337,1.983c1.365,0.434,2.64,0,3.201-0.237c0.562-0.238,1.487-0.583,1.487-0.583s1.791-0.631,2.752-0.848c0.965-0.217,1.533-0.323,2.188,0.832c0.652,1.158,1.014,1.886,1.078,2.625c0.064,0.74-0.209,1.148-0.461,1.432c-0.25,0.279-0.217,0.46-0.217,0.46c-0.105,0.873,1.182,0.763,1.182,0.763s0.041-0.004,0.11-0.018c-0.26,0.021-0.499-0.021-0.59-0.178c-0.116-0.202-0.217-0.531,0.146-0.906c0.359-0.374,0.402-0.693,0.402-0.693c0.305-1.439-1.038-3.371-1.354-3.875c-0.315-0.503-0.836-0.791-2.394-0.531c-1.556,0.26-3.386,1.037-3.386,1.037s-1.891,0.995-3.299,0.809c-1.413-0.188-1.701-1.614-1.687-2.063c0.016-0.444,0.304-0.836,1.038-1.122c0.733-0.289,2.464-0.679,4.984-0.809c2.522-0.128,3.458-1.771,3.458-1.771c0.331-0.478,0.923-1.543-0.489-2.338c-1.412-0.789-1.44-0.589-2.116-1.104c-0.68-0.521-1.412-1.153-1.701-2.034c-0.026-0.084-0.07-0.198-0.108-0.291L55.064,72.686L55.064,72.686z"/><linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="390.042" y1="485.6797" x2="390.042" y2="485.6797" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#FFF"/><stop offset=".7473" stop-color="#F9F9F9"/><stop offset="1" stop-color="#D5D7D8"/></linearGradient><path style="&st35;" d="M-16.122-14.641"/><linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="390.042" y1="485.6797" x2="390.042" y2="485.6797" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#FFF"/><stop offset=".7473" stop-color="#F9F9F9"/><stop offset="1" stop-color="#D5D7D8"/></linearGradient><path style="&st36;" d="M-16.122-14.641"/><path style="&st34;" d="M92.002,13.363c1.021,1.649,2.844,4.295,2.844,4.295s0.256,0.332,0.5,0.605l0.01-0.011c0.011-0.375-0.051-0.571-0.06-0.621l-0.091-0.274c-0.021-0.367,0.438,0.095,0.611,0.288c-0.498-0.754-0.659-0.811-0.659-0.811s-0.423-0.234-0.111,0.59c0.312,0.824-0.075,0.233-0.075,0.233c-0.924-1.177-2.838-4.293-2.838-4.293l-0.553-0.383L92.002,13.363L92.002,13.363z"/><path style="&st34;" d="M101.539,51.352c0.014-0.063,0.023-0.125,0.034-0.188c-0.004,0-0.009,0-0.009,0s0.005-0.03,0.013-0.089C101.563,51.17,101.551,51.262,101.539,51.352L101.539,51.352z"/><path style="&st34;" d="M100.822,35.679c0.088-0.033,0.188,0.1,0.188,0.1s0.135,0.189,0.289,0.033c0.107-0.104,0.155-0.353,0.025-1.257c-0.004,0.229-0.053,0.409-0.137,0.59c-0.139,0.296-0.314,0.02-0.441-0.081c-0.129-0.098-0.168,0.07-0.168,0.07l-0.004,0.162c0,0.7,0.087,2.346,0.217,3.617c0.063,0.605,0.173,1.071,0.287,1.408l0.041,0.076c0.089,0.148,0.188,0.343,0.307,0.255c0.116-0.089,0.274-0.582,0.274-0.582l0.128-0.591c0.191,0.113,0.291,0.529,0.341,0.962c-0.002-0.037-0.004-0.056-0.004-0.056s-0.144-1.324-0.3-1.313c-0.155,0.01-0.21,0.701-0.21,0.701s-0.066,0.468-0.157,0.456c-0.088-0.011-0.365,0.022-0.564-1.412c-0.201-1.436-0.158-2.949-0.158-2.949S100.732,35.713,100.822,35.679L100.822,35.679z"/><path style="&st34;" d="M99.696,28.566l0.298,0.341c0.479,1.494,0.996,3.843,1.092,4.264c-0.027-0.139-0.056-0.286-0.088-0.441c-0.288-1.454-0.711-2.896-1.006-3.832L99.696,28.566l-0.05-0.702c-0.004-0.01-0.006-0.016-0.006-0.016s-0.312-0.913-1.033-2.737c-0.725-1.824-0.848-2.458-0.848-2.458s-0.043-0.2,0.066-0.234c0.109-0.032,0.09-0.178,0.09-0.178s-0.013-0.245-0.277-0.99c-0.182-0.503-0.312-0.911-0.662-1.607c0.281,0.585,0.463,1.052,0.524,1.259l0.028,0.068c0,0,0.099,0.148,0.066,0.552c-0.027,0.403-0.146,0.452-0.146,0.452l0.022,0.14c0.141,0.538,0.418,1.187,0.418,1.187s1.065,2.709,1.748,4.54L99.696,28.566L99.696,28.566z"/><linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="274.5342" y1="-396.1577" x2="255.2091" y2="-490.1944" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st37;" d="M42.958,91.536c0.938,0.177,1.723,0.358,1.889,0.396C44.514,91.822,43.895,91.653,42.958,91.536z"/><linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="422.5586" y1="518.7568" x2="427.2878" y2="578.1768" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset=".2198" stop-color="#989A9C"/><stop offset=".2527" stop-color="#FFF"/></linearGradient><path style="&st38;" d="M20.381,74.92l0.007-0.164l-0.052-0.08c0,0-1.874-3.375-1.676-4.615c0,0,0.069-0.827,1.241-1.187c0.817-0.25,0.71,0.538,3.112,0.976c0,0,2.07,0.557,2.611-0.946c0.539-1.507-0.566-3.394-0.566-3.394s-1.45-2.656-3.244-2.756c-0.95-0.055-0.692,0.583-2.125,0.924c0,0-1.913,0.185-2.519-0.963c-0.733-1.389-1.015-2.968-1.015-4.021c0-1.058,0.045-1.001,0.126-1.405c0.045-0.219,0.186-0.548,0.248-1.09l-0.134-0.675l0.204-0.499c0.002-0.26-0.004-0.535-0.021-0.83c-0.092-1.661-0.211-4.221-0.436-5.711c-0.223-1.491-0.633-3.799-1.991-3.865c0,0-0.671-0.052-1.636,0.885c-0.882,0.856-1.682-0.708-1.726-1.663c-0.052-1.121,0.131-2.255,0.409-2.795c0.277-0.541,1.042-0.566,1.186-0.554c0.146,0.012,0.555,0.17,1.042,0.474c0.489,0.304,1.161,0.304,1.558-0.092c0.395-0.395,0.948-0.856,1.173-2.598c0.225-1.741,0.225-3.547,0.013-5.71l-0.224-0.485l1.339-0.288c-0.001-0.016-0.021-0.125-0.032-0.195c0,0,0-0.001-0.001-0.002c-0.001-0.017-0.004-0.033-0.007-0.052c0-0.002,0-0.004,0-0.005c-0.003-0.019-0.007-0.038-0.009-0.057c-0.001-0.001-0.001-0.001-0.001-0.003c-0.003-0.022-0.006-0.042-0.009-0.062c0-0.001,0-0.001,0-0.001c-0.004-0.022-0.006-0.045-0.011-0.067c0-0.003-0.001-0.006-0.001-0.007c-0.002-0.022-0.006-0.045-0.008-0.068c-0.001-0.005-0.001-0.01-0.003-0.015c-0.002-0.023-0.005-0.047-0.009-0.069c-0.001-0.004-0.002-0.01-0.002-0.014c-0.003-0.026-0.007-0.05-0.012-0.076c0-0.002,0-0.005,0-0.005c-0.004-0.025-0.008-0.05-0.012-0.076c0-0.007-0.001-0.012-0.002-0.018c-0.002-0.024-0.006-0.052-0.009-0.079c-0.001-0.005-0.001-0.011-0.003-0.021c-0.004-0.027-0.006-0.053-0.01-0.081c-0.001-0.007-0.002-0.013-0.003-0.02c-0.003-0.028-0.005-0.057-0.009-0.087c-0.001-0.003-0.001-0.008-0.003-0.013c-0.003-0.028-0.005-0.056-0.009-0.082c-0.001-0.006-0.001-0.011-0.002-0.017c-0.003-0.031-0.006-0.06-0.01-0.091c-0.001-0.007-0.001-0.014-0.002-0.02c-0.004-0.03-0.006-0.062-0.011-0.09c0-0.007-0.001-0.015-0.002-0.022c-0.003-0.031-0.006-0.063-0.01-0.094c-0.001-0.006-0.002-0.011-0.002-0.018c-0.003-0.032-0.005-0.063-0.009-0.094c0-0.003,0-0.005-0.001-0.009c-0.003-0.033-0.004-0.068-0.009-0.1c0-0.005,0-0.013-0.001-0.02c-0.002-0.035-0.005-0.065-0.007-0.099c-0.001-0.008-0.001-0.015-0.002-0.021c-0.003-0.032-0.005-0.066-0.007-0.099c0-0.005-0.001-0.011-0.001-0.02c-0.002-0.033-0.006-0.068-0.007-0.101c0-0.003-0.001-0.008-0.001-0.009c-0.002-0.033-0.004-0.066-0.007-0.1c0-0.006,0-0.012,0-0.017c-0.001-0.032-0.003-0.068-0.005-0.1c0-0.008,0-0.014-0.001-0.022c-0.001-0.033-0.004-0.067-0.005-0.098c0-0.006,0-0.013,0-0.021c-0.002-0.033-0.003-0.066-0.004-0.101c0-0.005,0-0.008,0-0.013c-0.001-0.032-0.002-0.066-0.002-0.099c0-0.003,0-0.005,0-0.009c0-0.034-0.001-0.067-0.001-0.102c0-0.005,0-0.012,0-0.016c0-0.033,0-0.067,0-0.098c0-0.005,0-0.012,0-0.019c0.001-0.032,0.001-0.065,0.001-0.096c0-0.004,0.001-0.009,0.001-0.014c0-0.033,0.001-0.066,0.003-0.1c0.052-1.243,0.291-1.751,0.291-1.751l0.058-0.166c0,0,0.46-1.458,1.152-2.458l-0.011,0.024c0,0,0.446-0.738,1.231-0.816c0.785-0.077,1.003,0.158,1.371,0.202c0.04,0.004,0.078,0.008,0.115,0.013c0.013,0.001,0.025,0.002,0.037,0.004c0.025,0.002,0.051,0.003,0.074,0.006c0.014,0.001,0.028,0.002,0.042,0.003c0.021,0.001,0.043,0.002,0.064,0.004c0.014,0.001,0.028,0.001,0.041,0.002c0.02,0.001,0.04,0.002,0.058,0.002c0.013,0.002,0.026,0.002,0.04,0.002c0.021,0.001,0.037,0.002,0.055,0.002c0.014,0,0.026,0.001,0.039,0.001c0.016,0,0.034,0.001,0.051,0.001c0.011,0,0.023,0,0.034,0c0.017,0,0.032,0,0.05-0.001c0.01,0,0.02,0,0.032-0.001c0.016,0,0.031,0,0.046-0.001c0.011,0,0.02-0.001,0.03-0.001c0.015,0,0.03-0.002,0.045-0.002c0.009,0,0.017-0.001,0.026-0.001c0.015-0.001,0.03-0.003,0.044-0.004c0.006-0.001,0.016-0.002,0.022-0.002c0.016-0.001,0.03-0.002,0.044-0.004c0.007-0.001,0.014-0.001,0.019-0.002c0.016-0.002,0.03-0.004,0.045-0.007c0.006,0,0.009,0,0.014-0.001c0.019-0.002,0.036-0.006,0.052-0.008l0,0c0.035-0.008,0.068-0.014,0.098-0.021c0,0,0-0.002,0.002-0.002c0.012-0.002,0.025-0.005,0.039-0.01c0.002,0,0.004-0.001,0.007-0.001c0.01-0.003,0.02-0.006,0.029-0.009c0.003-0.001,0.007-0.002,0.01-0.004c0.009-0.002,0.018-0.006,0.026-0.008c0.002-0.002,0.005-0.003,0.008-0.003c0.008-0.003,0.015-0.006,0.021-0.009c0.003-0.001,0.006-0.003,0.009-0.004c0.006-0.003,0.014-0.004,0.02-0.009c0.003-0.001,0.006-0.002,0.008-0.003c0.005-0.002,0.012-0.005,0.019-0.007c0.001-0.002,0.003-0.003,0.005-0.004c0.005-0.004,0.01-0.005,0.015-0.008c0.003-0.001,0.004-0.003,0.008-0.003c0.004-0.002,0.008-0.005,0.012-0.008c0,0,0.004,0,0.005-0.002c0.004-0.003,0.008-0.006,0.012-0.008c0.001-0.002,0.002-0.002,0.004-0.003c0.003-0.003,0.007-0.004,0.01-0.008c0.002,0,0.002,0,0.002-0.002c0.003-0.001,0.007-0.005,0.011-0.008c0,0,0.001,0,0.001-0.001c0.004-0.002,0.005-0.004,0.009-0.007h0.001c0.002-0.002,0.004-0.004,0.006-0.007c0.001-0.001,0.002-0.001,0.003-0.002s0.002-0.002,0.002-0.002c0.001-0.003,0.001-0.003,0.003-0.005c0.002-0.002,0.004-0.004,0.004-0.004c0.328-0.241,0.591-0.516,0.797-0.775c0.014-0.017,0.026-0.034,0.04-0.05c0.002-0.004,0.005-0.009,0.008-0.012c0.013-0.016,0.026-0.032,0.038-0.05c0.002-0.003,0.006-0.006,0.007-0.01c0.012-0.018,0.025-0.032,0.038-0.05c0,0,0,0,0.001,0c0.039-0.055,0.075-0.109,0.109-0.159c0-0.003,0.002-0.006,0.003-0.008c0.01-0.015,0.021-0.028,0.03-0.044c0.001-0.003,0.004-0.007,0.007-0.01c0.008-0.016,0.017-0.029,0.024-0.042c0.002-0.004,0.005-0.009,0.009-0.013c0.008-0.014,0.017-0.028,0.023-0.042c0.001-0.001,0.001-0.002,0.002-0.002c0.017-0.028,0.032-0.055,0.046-0.079c0.002-0.003,0.004-0.008,0.006-0.013c0.006-0.01,0.01-0.021,0.017-0.029c0.003-0.007,0.007-0.014,0.012-0.02c0.004-0.008,0.009-0.017,0.014-0.024c0.002-0.008,0.006-0.017,0.01-0.023c0.004-0.007,0.009-0.016,0.012-0.023c0.004-0.006,0.006-0.014,0.011-0.021c0.002-0.006,0.007-0.013,0.01-0.021c0.066-0.128,0.097-0.205,0.097-0.205c0.593-1.459,0.052-2.936-0.21-3.225c-0.32-0.353-1.041-0.882-1.041-0.882s-0.288-0.241-0.751-0.144c0.349-0.049,0.791,0.091,0.966,0.558c0.277,0.734,0.376,1.335,0.212,2.33c0,0-0.26,1.387-1.384,2.233c-1.125,0.848-1.923,0.096-2.885,0.13c-0.962,0.032-1.516,0.701-1.809,1.157c-0.293,0.457-1.417,2.2-1.319,5.067c0.097,2.868,0.291,4.301,0.325,5.558c0.033,1.205,0.178,3.976-0.635,5.278c-0.815,1.303-1.628,0.65-2.2,0.309c-0.571-0.341-1.223-0.245-1.744,0.131c-0.521,0.375-0.833,1.124-0.848,3.324c-0.016,2.364,1.532,2.606,1.532,2.606s0.293,0.146,0.945-0.537c0,0,0.651-0.685,1.253-0.603c0.604,0.082,0.995,0.716,1.255,1.808c0.261,1.092,0.796,5.621,0.717,8.668c-0.034,1.271-0.62,1.286-0.36,3.617c0,0,0.409,3.13,1.401,4.089c0.995,0.962,2.378,0.781,2.706,0.75c0.324-0.032,0.7-0.26,0.7-0.26s0.309-0.197,0.537-0.374c0.23-0.182,0.522-0.428,1.011-0.277c0.489,0.146,1.645,0.896,2.557,2.571c0.915,1.678,0.496,3.317-0.26,3.521c-0.668,0.182-0.848,0.229-1.971-0.05c-1.124-0.274-1.451-0.567-1.957-0.766c-0.504-0.196-1.043-0.263-1.547,0.114c-0.505,0.373-1.345,1.057-0.343,3.32c0.961,2.174,1.692,3.797,3.518,5.623c-0.522-0.607-0.956-1.188-1.427-1.871L20.381,74.92L20.381,74.92z"/><linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="237.3721" y1="-388.3604" x2="218.8474" y2="-478.5023" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st39;" d="M22.494,7.387l-0.05,0.025C22.45,7.41,22.469,7.401,22.494,7.387z"/><linearGradient id="SVGID_16_" gradientUnits="userSpaceOnUse" x1="259.9063" y1="-479.3379" x2="259.8987" y2="-479.3752" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st40;" d="M46.028,92.85c0.13,0.014,0.26,0.026,0.391,0.041c-0.114-0.016-0.31-0.039-0.561-0.074C45.916,92.828,45.972,92.838,46.028,92.85L46.028,92.85z"/><path style="&st29;" d="M24.089,5.489c-0.649,0.36-0.7-0.016-1.141,0.017c-0.439,0.033-1.026,0.212-1.596,1.043c-0.571,0.831-0.586,1.89,0.326,1.417c0,0,0.436-0.428,0.815-0.579c0.081-0.043,0.24-0.126,0.406-0.174l0.144-0.117c0,0,0.424-0.491,1.073-0.333c0.648,0.156,1.119-0.129,1.119-0.129c1.01-0.761,1.655-2.184,1.655-2.184l0.987-1.998l-0.826-1.336c0,0-0.698,1.489-1.383,2.53C24.986,4.692,25.033,4.972,24.089,5.489L24.089,5.489z"/><path style="&st29;" d="M19.871,16.292c0,0-0.424,1.89,1.156,1.597c0,0,0.006-0.002,0.022-0.007c-0.062,0.003-0.089-0.006-0.089-0.006c-0.025-0.497,0.149-1.432,0.49-2.261c0.341-0.83,1.075-2.254,1.075-2.254s1.047-1.791,1.467-2.89c0.42-1.102,0.416-1.939,0.416-1.939s-0.8-1.019-0.915-1.176c-0.115-0.157-0.272-0.223-0.272-0.223c-0.054,0.019-0.103,0.036-0.146,0.051c0.115-0.007,0.221,0.021,0.283,0.114c0.213,0.31-0.39,2.036-0.39,2.036s-0.522,1.238-1.548,3.03C20.393,14.157,19.871,16.292,19.871,16.292L19.871,16.292z"/><linearGradient id="SVGID_17_" gradientUnits="userSpaceOnUse" x1="268.9033" y1="-394.6382" x2="249.4966" y2="-489.0725" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st41;" d="M38.185,89.697l0.166,0.02c-0.134-0.119-0.305-0.236-0.497-0.347c0.184,0.113,0.489,0.358,0.312,0.665c-0.245,0.424-0.048,0.457,0.489,0.863c0,0,0.022,0.013,0.061,0.033c-0.156-0.107-0.253-0.234-0.156-0.362c0.125-0.166,0.136-0.334,0.065-0.499L38.185,89.697L38.185,89.697z"/><linearGradient id="SVGID_18_" gradientUnits="userSpaceOnUse" x1="254.4561" y1="-391.5991" x2="235.0337" y2="-486.1104" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st42;" d="M24.437,82.749c-1.245-1.185,1.595-0.118,1.595-0.118s0.619,0.262,0.343-0.385c-0.246-0.57-1.373-1.963-2.543-3.219l0.144,0.156c0,0,2.346,2.721,2.183,2.966c-0.164,0.245-1.108-0.325-1.108-0.325s-1.401-0.539-1.206,0.13c0.143,0.491,1.059,1.271,1.536,1.649C25.109,83.372,24.798,83.09,24.437,82.749z"/><linearGradient id="SVGID_19_" gradientUnits="userSpaceOnUse" x1="262.6514" y1="-392.9692" x2="243.1559" y2="-487.8355" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st43;" d="M26.977,84.73c0.424,0.256,0.903,0.513,1.365,0.676c0,0,0.831,0.293,1.337-0.114c0.503-0.403,0.503-0.601,1.238-0.243c0,0,1.388,0.696,2.382,1.444c0.98,0.735,3.557,2.336,4.396,2.791c-0.764-0.417-3.712-2.365-4.633-2.99c-0.936-0.633-2.574-1.698-3.297-1.476c-0.554,0.172-0.474,0.396-0.804,0.555c-0.331,0.158-0.688,0.055-1.504-0.383C27.291,84.9,27.134,84.818,26.977,84.73L26.977,84.73z"/><linearGradient id="SVGID_20_" gradientUnits="userSpaceOnUse" x1="271.5479" y1="-390.9575" x2="251.1904" y2="-490.0176" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st44;" d="M39.903,91.448c0.37,0.104,0.672,0.06,0.787,0.035c-0.678,0.04-1.35-0.269-1.35-0.269s-0.067-0.021-0.165-0.061C39.413,91.268,39.689,91.385,39.903,91.448z"/><linearGradient id="SVGID_21_" gradientUnits="userSpaceOnUse" x1="274.6582" y1="-395.8442" x2="255.2559" y2="-490.2569" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset="1" stop-color="#E4E5E6"/></linearGradient><path style="&st45;" d="M44.293,92.169c0,0-1.344-0.163-1.939-0.163c0,0-0.037,0.064,0.226,0.158c-0.021-0.021-0.031-0.049,0.189,0c0.304,0.064,2.018,0.225,2.465,0.158c0.448-0.068-0.091-0.278-0.091-0.278s-0.088-0.041-0.267-0.102C44.553,92.201,44.293,92.169,44.293,92.169L44.293,92.169z"/><path style="&st34;" d="M4.662,62.045c0.085,0.143,0.198,0.432,0.462,0.725c0.146,0.16,0.266,0.072,0.162-0.525c-0.253-0.182-0.407-0.318-0.464-0.371c-0.113-0.013-0.263-0.297-0.263-0.297s-0.471-0.835-0.274-0.227c0.398,1.23,1.6,3.821,1.6,3.821l1.396,2.47c-0.999-1.803-2.299-4.633-2.44-5.013C4.691,62.223,4.577,61.904,4.662,62.045L4.662,62.045z"/><path style="&st34;" d="M1.547,32.696l0.032-0.643c0.027-0.122,0.057-0.241,0.087-0.36c0.712-2.789,1.069-3.858,1.425-4.649c0.356-0.792,0.398-0.245,0.398-0.245s0,0.209,0.136,0.234c0.135,0.023,0.324-0.32,0.494-0.826c0.17-0.504,0.604-1.745,0.693-2.212c0.135-0.704-0.051-0.358-0.115-0.354c-0.108,0.005-0.126-0.091-0.113-0.306c0,0,0.382-2.122,3.064-6.563c0.18-0.17,0.321-0.307,0.47-0.449c-0.055-0.052-0.033-0.265,0.001-0.32c0.136-0.214,0.275-0.435,0.422-0.661l-0.09,0.504c0,0-1.85,2.492-3.104,5.694c0,0-0.342,0.835-0.359,1.094c-0.025,0.154-0.104,0.739,0.152,0.582l0.065-0.048c-0.093,0.484-0.295,1.37-0.607,2.325c-0.288,0.878-0.573,1.633-0.841,2.078l-0.002-0.004c-0.08,0.067-0.098-0.016-0.146-0.21c-0.048-0.198-0.113-0.198-0.113-0.198c-0.179,0-0.324,0.202-0.41,0.359c-0.04,0.056-0.089,0.19-0.089,0.19s-0.461,0.934-1.281,4.26c-0.822,3.328-0.836,6.14-0.836,6.14s-0.084,1.309-0.21,1.379c-0.126,0.07-0.097-0.056-0.097-0.056s-0.045-0.052-0.114,0.045c0,0,0.02-0.76,0.044-0.875c0,0,0.041-0.206,0.119-0.206s0.006,0.125,0.048,0.16c0.039,0.032,0.084,0.03,0.075-0.178c-0.005-0.176,0.147-2.816,0.621-5.312L1.547,32.696L1.547,32.696z"/><path style="&st34;" d="M0.392,41.994c0-0.002,0-0.004,0-0.005c0,0,0.018,0.217,0.042,0.356l-0.003,0.01c0.078,0.357,0.187,0.357,0.187,0.357c0.008-0.096,0.087-0.273,0.183-0.458c0.007,0.106,0.007,0.231-0.004,0.375c-0.037,0.537-0.019,2.466,0.209,4.28c0.225,1.815,0.367,3.349,0.394,3.594c0.029,0.245,0.498,3.283,1.025,5.089c0.285,0.967,0.422,1.344,0.483,1.424l0.008,0.049c0,0,0.097,0.184,0.348,0.32c0,0,0.111-0.097,0.112-0.412c0.018,0.031,0.037,0.065,0.057,0.105c-0.083,0.262-0.105,0.426-0.105,0.426l0,0c-0.042-0.043-0.06-0.031-0.046,0.045c0.067,0.357,0.027,0.68-0.169,0.272c-0.198-0.403-0.8-1.832-1.307-4.251c0,0-0.531-2.659-0.795-5.084l0.042-0.105L0.989,48.29c-0.027-0.248-0.048-0.491-0.067-0.729c0,0-0.255-3.657-0.237-4.562c0.019-0.904-0.085-0.02-0.085-0.02s-0.021,0.219-0.028,0.329c-0.008,0.109-0.103,0.352-0.136-0.246C0.459,43.322,0.392,42.261,0.392,41.994L0.392,41.994z"/><path style="&st34;" d="M24.672,1.974l-0.53-0.753l-0.066-0.065c0,0-0.131-0.136-0.896,0.038l-0.11,0.022c0,0,0.38-0.094,0.168,0.191c-0.212,0.285-0.56,0.496-1.172,1.15c-0.612,0.655-0.411,0.803-0.01,0.668c0.401-0.138,1.188-0.499,2.606-1.243L24.672,1.974z"/><path style="&st34;" d="M23.106,1.21c-0.022,0.003-0.036,0.006-0.036,0.006L23.106,1.21z"/><path style="&st34;" d="M23.637,1.811c0.31-0.272,0.429-0.484,0.454-0.641l-0.015-0.014c0,0-0.131-0.136-0.896,0.038l-0.075,0.015c0.09-0.015,0.303-0.032,0.133,0.198c-0.212,0.285-0.56,0.496-1.172,1.151c-0.612,0.656-0.411,0.803-0.01,0.667c0.106-0.038,0.239-0.088,0.4-0.157C22.599,2.755,23.046,2.325,23.637,1.811z"/><path style="&st34;" d="M83.482,4.115l-0.2,0.235c0,0,0.136,0.081,0.208,0.141c0.008,0.005,0.014,0.01,0.021,0.012c-0.043-0.034-0.07-0.056-0.07-0.056c-0.023-0.109,0.004-0.223,0.014-0.297L83.482,4.115c0,0,0.055,0.002,0.143,0.011L83.482,4.115L83.482,4.115z"/><path style="&st6;" d="M62.559,90.319c0,0,1.686-0.187,3.239-0.691c1.558-0.504,1.935-0.981,1.874-1.341c-0.037-0.238-0.396-0.305-0.906-0.238c0.271-0.021,0.514,0.032,0.354,0.332c-0.313,0.582-0.861,0.782-0.861,0.782s-0.267,0.19-0.89,0.371c-0.806,0.245-1.794,0.375-2.335,0.438c-0.691,0.082-0.521-0.033-1.465,0.291c-0.023,0.016-0.047,0.025-0.065,0.043c-0.289,0.237,1.071,0.514,1.071,0.514s1.302,0.361,3.257,0.23l0.067-0.021c0.267-0.078,0.533-0.161,0.8-0.245c-2.021,0.457-3.324,0.149-3.737,0.095c-0.434-0.058-0.777-0.144-0.88-0.359C61.98,90.305,62.559,90.319,62.559,90.319L62.559,90.319z"/><path style="&st34;" d="M63.301,4.417l0.717,0.076c1.429-0.405,2.651-0.776,2.651-0.776s1.265-0.41,1.901-0.636c0.635-0.227,1.09-0.313,1.656-0.41c0.563-0.096,1.309-0.14,1.709-0.131c0.398,0.007,0.528,0.122,0.528,0.122s0.166,0.131,0.245,0.27c0.077,0.138,0.74,1.891,2.975,2.005c2.231,0.112,2.261-1.096,2.063-1.464c-0.226-0.427-0.896-0.863-0.896-0.863s-0.898-0.575-1.09-0.846c-0.192-0.271,0.033-0.358,0.104-0.376c0.066-0.018,2.433-0.497,2.729-0.608l0.021-0.02l-0.563-0.174c0,0-0.119,0.134-0.789,0.312c-0.67,0.179-1.233,0.246-1.742,0.313c-0.504,0.067-0.504,0.239-0.504,0.239l-0.879,1.406c0,0-0.029,0.104,0.043,0.305c0.073,0.202,0.41,0.448,0.41,0.448s0.573,0.424,0.99,0.699c0.418,0.275,0.395,0.373,0.395,0.373c-1.123,0.095-1.418-0.048-1.875-0.276c-0.445-0.223-0.76-0.729-0.922-1.086c-0.162-0.357-0.521-0.663-0.521-0.663c-0.589-0.336-1.696-0.343-2.813-0.15c-1.115,0.194-2.656,0.707-2.923,0.812c-0.271,0.104-1.616,0.551-2.309,0.729c-0.694,0.179-1.224,0.357-1.646,0.47c-0.426,0.11-3.431,1.005-4.557,1.339c-1.124,0.333-1.848,0.461-1.848,0.461c-1.688,0.171-2.193-0.134-2.193-0.134c-0.297-0.125-0.262-0.527-0.262-0.527l0.009-1.147c0,0-0.029-0.433-0.356-0.611c-0.328-0.179-0.779-0.252-1.593-0.29c-0.811-0.038-1.683,0.044-2.093,0.134c-0.408,0.09-1.19,0.313-1.764,0.952c-0.573,0.641-0.481,1.141-0.481,1.141s0.035,0.683,0.088,1.19c0.052,0.504,0.484,0.662,0.484,0.662s-0.744,0.532-3.045,1.206c-2.209,0.648-3.682,0.774-3.682,0.774l0.678,0.254c0,0,5.468-1.015,7.148-2.616c0,0,0.624-0.293,0.02-0.88c-0.606-0.585-0.897-0.761-0.897-0.761s-0.41-0.224,0.019-0.771c0.43-0.547,0.923-0.795,1.352-0.933c0.429-0.138,1.753-0.25,2.925-0.093c0,0,0.491,0.041,0.459,0.408c-0.034,0.366-0.088,0.872-0.077,1.028c0.008,0.158,0.023,0.515,0.398,0.845c0.378,0.332,1.099,0.453,1.099,0.453s1.257,0.228,2.843-0.217c1.584-0.445,3.642-1.14,5.431-1.629L63.301,4.417L63.301,4.417z"/><path style="&st12;" d="M-16.122-14.641"/><path style="&st22;" d="M48.462,6.628c0.31,0.207,0.476,0.221,0.5,0.421c0.055,0.339-0.56,0.64-0.56,0.64l-0.006-0.011c0,0-0.431-0.157-0.484-0.664c-0.052-0.505-0.088-1.19-0.088-1.19s0.001,0.2,0.046,0.26C48.004,6.256,48.087,6.378,48.462,6.628z"/><path style="&st20;" d="M82.447,79.307l0.451,0.17c1.104-0.617,1.496-0.809,1.759-0.963c1.183-0.703,2.592-1.563,2.963-1.855c0,0,0.761-0.518,0.116,0.195s-0.969,1.007-0.969,1.007s-0.625,0.626-0.471,0.782c0,0,0.166,0.246,1.193-0.687c1.023-0.929,2.15-2.258,2.275-2.44c0.127-0.188,0.146-0.293,0.146-0.293s0.107-0.215,0.273-0.393c0.145-0.15,1.377-1.496,1.994-2.121c0,0,0.002,0.001,0.006,0.003c0.273-0.362,0.541-0.729,0.806-1.102c-0.358,0.379-1.724,1.829-2.483,2.684c0,0-0.713,0.763-0.938,1.056s-0.225,0.47-0.225,0.47s-0.117,0.196-0.392,0.519s-1.24,1.186-1.24,1.186s-0.577,0.47-0.754,0.478c-0.179,0.011,0.431-0.538,0.431-0.538s0.588-0.625,0.967-1.123c0.382-0.498,0.137-0.47,0.137-0.47s-0.186-0.049-0.986,0.459c-0.8,0.508-1.367,0.858-1.367,0.858s-1.722,0.986-2.814,1.623c-1.096,0.636-3.6,1.908-5.021,2.492c-1.43,0.588-2.162,0.715-2.035,0.527c0.127-0.186,0.461-0.459,0.461-0.459s0.399-0.4,0.399-0.803c0,0,0.128-0.586-1.604-0.223c-1.729,0.36-3.293,1.213-3.293,1.213s-2.571,1.182-1.965,1.887c0,0,0.117,0.186,0.635,0.352c0.52,0.166-0.92,0.606-0.92,0.606c-1.365,0.448-2.413,0.651-3.74,0.926c-1.963,0.403-3.564,0.761-4.165,0.894c-0.165,0.035-0.253,0.059-0.253,0.059s-1.212,0.292-3.229,1.072c-2.015,0.783-5.972,1.43-5.972,1.43s-2.542,0.293-2.777,0.627c-0.234,0.331,0.177,0.499,0.177,0.499s0.362,0.224,1.671,0.283c0,0,0.451,0,0.471,0.036c0.018,0.039,0.046,0.068-0.235,0.156c-0.286,0.088-0.854,0.314-2.778,0.558c-1.936,0.245-1.896-0.067-1.896-0.067s-0.01-0.076,0.078-0.216c0.087-0.134,0.009-0.369-0.293-0.535c0,0-0.419-0.272-1.829-0.262c-1.408,0.009-4.212,0.017-6.833-0.14c-2.374-0.143-5.59-0.551-6.099-0.664c0,0-0.117-0.029-0.206-0.117c-0.088-0.09-0.646-0.422-1.164-0.733c-0.517-0.313-2.073-0.907-2.073-0.907s-2.011-0.783-1.945-0.521c0.015,0.063,0.13,0.153,0.268,0.246c0.351,0.188,0.704,0.375,1.06,0.56l0.002-0.002c0,0-0.743-0.402-0.538-0.402s0.438,0.109,0.438,0.109s1.213,0.332,1.966,0.686c0.753,0.353,1.407,0.83,1.407,0.83s0.929,0.549,2.319,0.732c1.346,0.182,3.174,0.389,3.777,0.448l0.594-0.272l0.433,0.354c1.106,0.068,2.575,0.146,2.575,0.146s2.976,0.111,4.605-0.019c0.733-0.063,0.507,0.317,0.507,0.317s-0.214,0.354,0.206,0.529c0,0,0.771,0.439,3.343,0.157c2.573-0.286,3.138-0.862,3.138-0.862s0.299-0.275-0.351-0.398c-0.513-0.1-0.513-0.051-1.175-0.117c-0.665-0.067-0.998-0.205-0.557-0.323c0.441-0.114,1.174-0.175,1.174-0.175s2.249-0.313,4.066-0.783c0,0,1.938-0.458,3.861-1.134c0.756-0.265,1.395-0.459,1.887-0.599l0.438-0.644l0.644,0.372c0.065-0.014,0.103-0.021,0.103-0.021s2.306-0.539,3.274-0.703c0.966-0.168,3.154-0.637,4.087-1.086c0.928-0.448,1.396-0.805,1.505-1.075c0.107-0.272-0.393-0.431-0.393-0.431s-0.588-0.138-0.508-0.34c0.075-0.205,0.293-0.382,1.213-0.793c0.918-0.41,2.07-0.859,3.227-1.144c1.154-0.282,0.732,0.194,0.732,0.194s-0.692,0.705-0.783,0.979c-0.086,0.273,0.029,0.285,0.119,0.333c0.088,0.05,0.646,0.028,1.022-0.067c0.383-0.099,3.464-1.271,5.341-2.347c0.049-0.026,0.094-0.054,0.139-0.08L82.447,79.307z"/><linearGradient id="SVGID_22_" gradientUnits="userSpaceOnUse" x1="221.1826" y1="-454.5649" x2="221.373" y2="-454.5649" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#808080"/><stop offset=".0868" stop-color="#7A7A7A"/><stop offset=".36" stop-color="#6B6B6B"/><stop offset=".5192" stop-color="#686868"/><stop offset=".6377" stop-color="#5F5F5F"/><stop offset=".7431" stop-color="#4E4E4E"/><stop offset=".8408" stop-color="#383838"/><stop offset=".9324" stop-color="#1B1B1B"/><stop offset="1" stop-color="#000"/></linearGradient><path style="&st13;" d="M7.432,68.01l0.178,0.131c-0.105-0.099-0.167-0.155-0.167-0.155s-0.008,0.003-0.024,0.003C7.423,67.993,7.429,68.002,7.432,68.01L7.432,68.01z"/><linearGradient id="SVGID_23_" gradientUnits="userSpaceOnUse" x1="221.4043" y1="-449.8027" x2="316.0254" y2="-449.8027" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#808080"/><stop offset=".0868" stop-color="#7A7A7A"/><stop offset=".3817" stop-color="#828282"/><stop offset=".5185" stop-color="#808080"/><stop offset=".5677" stop-color="#797979"/><stop offset=".6027" stop-color="#6E6E6E"/><stop offset=".608" stop-color="#6B6B6B"/><stop offset="1" stop-color="#4E4E4E"/></linearGradient><path style="&st7;" d="M90.412,59.954l-0.371-0.021c-1.807,1.463-2.342,1.938-3.781,2.955c0,0-1.644,1.228-3.44,2.196c-1.804,0.97-3.919,0.853-3.919,0.853s-0.573-0.062-0.295-0.477c0.275-0.415,0.634-1.425,0.771-1.938c0.141-0.516,0.415-1.82-0.633-2.235s-3.018,0.196-3.018,0.196s-4.525,1.205-6.371,3.23c-1.793,1.969-0.286,2.846-0.286,2.846s0.702,0.49,1.386,0.73c0.645,0.229,0.516,0.436,0.354,0.555c0,0-2.021,1.287-4.408,1.974c0,0-3.268,1.001-6.441,1.206c-3.154,0.203-4.495,0.283-4.495,0.283l-0.399,0.379l-0.758-0.252c-1.283,0.154-3.455,0.463-5.596,0.979c-2.622,0.64-5.123,1.147-6.903,2.296c0,0-1.333,0.887-0.566,1.746c0.765,0.862,1.565,1.23,1.565,1.23s0.472,0.207,0.464,0.336c-0.009,0.164-0.015,0.309-0.367,0.512c0,0-1.394,0.814-4.108,0.859c-2.714,0.045-3.911,0.021-4.707-0.695c-0.658-0.591,0.165-1.844,0.165-1.844s0.33-0.612,0-1.453c-0.33-0.84-2.218-0.854-2.218-0.854l-2.615-0.134c-3.095-0.081-7.182-0.427-9.001-0.653c0,0-0.012-0.002-0.033-0.006l-0.006,0.166l-0.721-0.303c-1.139-0.221-3.243-0.668-4.075-1.084c-0.759-0.38-1.167-0.313-1.066-1.102c0.101-0.769-0.753-1.836-0.753-1.836s-1.188-1.287-2.257-2.086c-1.069-0.804-1.523-0.564-1.523-0.564s-0.484,0.258-0.049,1.296c0.436,1.04,0.86,1.403,0.86,1.403s0.208,0.22,0.089,0.279c-0.118,0.06-0.484-0.219-0.789-0.478c-0.253-0.21-1.885-1.742-2.456-2.276l0.105,0.356c0.019,0.028,0.035,0.062,0.052,0.086c0.184,0.291,0.855,1.269,2.155,2.28c1.549,1.213,1.559,0.729,1.559,0.729s0.061-0.399-0.297-0.84c-0.359-0.44-0.934-1.373-0.791-1.715c0.144-0.339,0.309-0.31,0.309-0.31s0.133-0.051,0.596,0.299c0.462,0.351,1.498,1.076,2.011,1.703c0.513,0.623,0.48,1.181,0.48,1.181s-0.102,0.563,0.453,1.17c0.553,0.604,1.733,1.714,5.859,2.351c0.025,0.004,0.034,0.006,0.059,0.01l0.193-0.551l0.573,0.663c3.598,0.521,5.555,0.563,5.555,0.563s4.709,0.162,5.982,0.162c1.272,0,1.035,0.666,1.035,0.666s-0.072,0.359-0.225,0.646c-0.155,0.287-0.524,1.365-0.144,1.939c0,0,0.585,1.427,4.381,1.527c0,0,3.324,0.268,5.643-0.688c2.319-0.954,0.226-2.275,0.226-2.275s-0.794-0.481-1.13-0.739c-0.308-0.234-0.184-0.481-0.121-0.646c0.06-0.162,0.297-0.359,0.563-0.492c0.266-0.134,1.239-0.654,5.365-1.722c4.124-1.069,6.587-1.183,6.587-1.183s0.02-0.002,0.055-0.004l0.338-0.656l0.854,0.556c0.732-0.06,1.681-0.129,2.526-0.171c1.691-0.082,4.341-0.471,5.879-0.807c1.54-0.343,3.869-1.062,5.592-1.951c1.725-0.895,1.809-1.519,1.809-1.519s0.328-0.475-0.392-0.995c-0.719-0.523-1.036-0.382-1.673-1.027c-0.637-0.646,0.557-1.62,0.557-1.62s0.612-0.861,4.021-2.175c3.403-1.313,3.979-0.873,4.153-0.729s0.195,0.615,0.123,0.935c-0.069,0.317-0.494,1.455-0.721,2.053c-0.227,0.594-0.316,1.406,0.605,1.601c0.923,0.194,2.215-0.008,3.428-0.442c2.893-1.033,3.756-2.295,8.534-5.764c0.012-0.008,0.021-0.017,0.03-0.021L90.412,59.954l0.689,0.108c1.978-1.573,3.869-3.571,3.869-3.571s1.258-1.261,1.889-2.356c0.595-1.026,0.027,0.89,0.027,0.89s-0.32,1.516,0.19,2.077c0.405,0.445,1.563-0.795,1.563-0.795s0.688-0.789,0.965-2.061c0.408-1.875,0.185-2.248,0.185-2.248s-0.246-0.389-0.093-0.852c0.154-0.459,1.158-3.047,1.98-4.01l0.502-0.563c0-0.008,0.002-0.02,0.002-0.027l-0.224-0.557l0.304-0.512c0,0-0.279,0.322-1.404,2.177c-1.266,2.087-1.467,3.771-1.467,3.771s-0.119,0.653-0.054,1.034c0.063,0.355,0.188,0.519,0.192,0.622c0.009,0.104-0.073,0.959-0.508,1.773c-0.438,0.814-0.815,1.031-0.815,1.031s-0.756,0.545-0.86,0.157c-0.104-0.39-0.074-0.72-0.035-0.966c0.035-0.248,0.289-1.579,0.252-2.072c-0.035-0.494-0.479-0.098-0.479-0.098s-0.104,0.119-0.298,0.366s-1.288,1.637-1.705,2.125c-0.988,1.157-1.886,1.989-4.292,3.93c-0.007,0.003-0.015,0.011-0.019,0.015L90.412,59.954L90.412,59.954z"/><linearGradient id="SVGID_24_" gradientUnits="userSpaceOnUse" x1="214.5928" y1="-431.356" x2="314.4043" y2="-431.356" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#555555"/><stop offset="1" stop-color="#231F20"/></linearGradient><path style="&st11;" d="M1.193,48.543l0.104,0.975c0.235,0.285,0.577,0.677,1.071,1.187c1.084,1.121,1.427,0.416,1.427,0.416s0.253-0.705-0.054-1.985C3.434,47.85,3.488,47.09,4.066,47.11c0.578,0.019,2.258,0.361,2.782,1.752c0,0,0.217,0.649,0.018,1.479c-0.2,0.834-0.162,1.57-0.018,2.295c0.145,0.725,0.759,1.407,1.464,1.971c0.706,0.562,2.746,1.535,4.734,1.66c1.987,0.127,2.601,0.021,2.601,0.021l0.746-0.767l0.134,0.668c0.812-0.09,2.116-0.229,3.62-0.393c2.528-0.271,4.227-0.544,5.798-0.308c1.573,0.235,2.079,1.462,2.079,1.462s0.108,0.314-0.253,0.544c-0.349,0.224-0.749,0.547-0.948,0.89c-0.199,0.346-0.411,1.068,0.16,2.035c0.572,0.963,2.142,1.592,3.478,1.432c1.335-0.155,3.335-0.67,4.52-0.979c1.287-0.337,2.424-0.971,2.572-1.98c0.147-1.008-1.534-2.295-1.534-2.295s-0.812-0.609-0.91-0.75c-0.1-0.139,0.099-0.197,0.099-0.197s0.949-0.229,1.357-0.414c0.404-0.189,1.522-0.646,3.353-1.219s5.608-1.248,5.608-1.248s2.084-0.332,4.685-0.543l0.622-0.702l0.485,0.625c0.409-0.024,0.825-0.046,1.243-0.063c3.572-0.129,5.344-0.554,7.242-0.979c1.897-0.427,4.568-1.978,4.965-2.276c0.396-0.295,1.229-0.66,1.396-1.957c0.168-1.295-1.364-2.157-1.364-2.157s-1.218-0.644-1.475-0.93c-0.258-0.287-0.02-0.562-0.02-0.562s0.689-1.485,2.896-2.354c2.205-0.872,3.689-1.107,4.618-1.208c0.932-0.099,1.245,0.237,1.374,0.396c0.128,0.157,0.128,0.485,0.021,0.821c-0.102,0.308-0.444,1.038-0.645,1.395c-0.197,0.356-0.523,1.216-0.316,1.622c0.208,0.405,0.843,0.593,1.662,0.445c0.821-0.149,2.988-0.761,4.888-1.553c1.9-0.792,5.073-2.345,5.073-2.345s0.009-0.004,0.022-0.012l0.086-0.729l0.729,0.295c1.02-0.562,2.764-1.58,4.01-2.631c1.871-1.573,3.699-3.225,4.166-3.639c0.465-0.417,0.892-0.752,1.307-0.732c0.414,0.021,0.732,0.317,0.988,1.434c0.258,1.118,0.308,2.038,0.426,2.582c0.117,0.543,0.285,1.175,0.931,1.304c0.646,0.129,1.513-0.434,1.838-0.713c0.33-0.276,0.92-1.176,0.882-2.382c0,0,0.068-1.604-0.761-3.127c0,0-0.351-0.614-0.479-0.782c-0.088-0.118-0.155-0.238-0.01-0.525c0.148-0.286,0.467-0.821,1.062-1.156c0.448-0.256,0.88-0.316,1.128-0.396c0,0,0.275-0.067,0.626-0.261l-0.126-0.412l0.289,0.316c0.404-0.239,0.652,0.045,0.652,0.045l-0.392-0.501l0.119-0.484c0,0-0.304-0.163-0.685-0.088c-0.383,0.078-0.42,0.362-1.014,0.458c-0.593,0.096-1.275,0.306-1.945,1.319c-0.67,1.011,0,2.271,0,2.271s0.359,0.592,0.533,0.896c0.172,0.306,1.066,2.215,0.037,3.608c0,0-0.552,0.643-1.525,0.86c-0.86,0.19-0.642-0.816-0.729-1.355c0,0-0.129-2.281-1.237-3.588c-0.976-1.146-2.746,0.888-3.629,1.566c-0.822,0.629-3.228,3.112-6.684,4.925l-0.51,0.892l-0.324-0.472c-1.658,0.827-5.418,2.656-7.87,3.514c0,0-1.875,0.762-2.64,0.782c0,0-0.17,0.006-0.034-0.179c0.133-0.185,0.276-0.322,0.507-0.737c0.23-0.418,0.646-1.357,0.646-2.327c0-0.969-1.119-1.917-2.68-1.748c-1.561,0.167-3.052,0.6-4.849,1.292c-1.796,0.692-3.343,2.159-3.55,3.375c-0.209,1.216,1.105,1.92,1.105,1.92s1.484,0.751,1.674,1.157c0.188,0.406,0.049,0.783,0.049,0.783s-0.129,0.406-0.783,0.782c-0.649,0.377-2.42,1.287-2.42,1.287s-2.207,1.217-5.562,1.512c0,0-3.058,0.26-4.817,0.348c-0.022,0.002-0.046,0.002-0.069,0.003l-0.541,0.53l-0.587-0.449c-1.64,0.136-3.54,0.359-3.54,0.359s-4.29,0.609-8.219,1.822c-3.336,1.027-3.971,1.594-3.971,1.594s-0.711,0.596-0.118,1.453c0,0,0.341,0.539,1.03,1.08c0.685,0.541,1.237,1.057,1.159,1.317c-0.08,0.265-0.29,0.382-0.29,0.382s-0.961,0.856-4.894,1.518c0,0-2.531,0.488-3.31-0.275c-0.778-0.766-0.435-1.279-0.435-1.279s0.052-0.173,0.62-0.527c0,0,0.951-0.596,0.647-1.727c-0.303-1.135-2.129-2.545-4.101-2.533c0,0-2.303,0.006-8.196,0.762c0,0-0.008,0-0.027,0.005l-0.204,0.501l-0.605-0.393c-0.324,0.039-0.713,0.076-1.114,0.107c-1.012,0.07-2.477-0.057-4.3-0.596c-1.824-0.543-2.963-1.535-3.126-2.133c-0.114-0.412,0.035-0.996,0.035-0.996S7.62,50.2,7.405,49.115c-0.22-1.083-0.582-1.934-1.631-2.567c-1.048-0.632-1.643-0.522-1.643-0.522s-0.939-0.144-0.904,1.446c0.037,1.59,0.235,2.256,0.235,2.256s0.181,0.562-0.108,0.635c-0.288,0.072-0.74-0.361-0.74-0.361s-1.021-0.924-1.619-1.688l0.048,0.066l-0.214,0.525c0,0,0.067,0.115,0.266,0.375L1.193,48.543L1.193,48.543z"/><linearGradient id="SVGID_25_" gradientUnits="userSpaceOnUse" x1="214.8965" y1="-410.8818" x2="306.501" y2="-410.8818" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#A0A0A0"/><stop offset=".0769" stop-color="#656767"/><stop offset="1" stop-color="#717375"/></linearGradient><path style="&st1;" d="M91.075,11.742l0.183,0.846c0,0-0.563,0.313-1.678,0.613c-1.113,0.3-2.188,0.801-2.188,0.801s-0.89,0.289-0.551,1.013c0.338,0.726,0.838,1.076,0.838,1.076s0.711,0.69,0.736,1.213c0.021,0.526-0.199,0.765-0.764,1.076c-0.563,0.313-1.075,0.375-1.075,0.375s-1.338,0.24-2.001-0.387c-0.663-0.626-0.787-1.663-0.787-1.663s-0.05-0.876-1.148-1.251c-1.102-0.375-2.453,0.425-2.453,0.425s-1.063,0.563-2.2,1.3c-1.14,0.738-3.291,1.64-4.642,2.114l-0.152,0.699l-0.758-0.382c-1.422,0.489-3.271,1.109-3.271,1.109S66.652,21.645,65,21.871c-1.648,0.224-2.016-0.014-2.238-0.238c-0.228-0.224,0.039-1.012,0.039-1.012s0.674-1.376,0.348-2.09c-0.324-0.714-2.451-0.9-2.486-0.9c-0.04,0-2.318-0.265-4.451,0.932c-1.895,1.062-2.143,1.642-2.143,1.642s-0.604,0.938,0.113,1.867c0.807,1.051,1.879,1.146,1.879,1.146s1.021,0.079,1.258,0.38c0.24,0.299,0.076,0.626,0.076,0.626s-0.336,0.925-2.228,1.312c0,0-3.181,0.933-9.113,1.776l-0.582,0.579c-3.743,0.47-8.143,1.363-10.555,1.989c-2.412,0.627-2.553,1.317-2.553,1.317c-0.519,0.813,0.141,1.236,0.141,1.236s0.829,0.283,1.017,1.19c0.19,0.91-0.783,1.629-0.783,1.629s-1.159,0.972-2.898,1.269c-1.739,0.297-2.396,0.35-3.429-0.47c-0.91-0.721-0.298-1.863,0.312-2.301c0.612-0.438,0.909-0.91,0.988-1.112c0.079-0.204,0.032-0.377,0.032-0.377l-0.58-0.534c-2.005-1.33-9.883,0.063-9.883,0.063s0,0.002,0,0l-1.341,0.289l-0.673-0.435c0,0-2.291,0.604-4.876,0.589c-2.712-0.014-1.27-2.128-1.27-2.128s0.638-1.118,0.75-1.764c0,0,0.224-1.745-1.42-1.631c-1.645,0.112-1.968,1.546-1.968,1.546s-0.112,0.801-0.089,1.392c0.021,0.594-0.002,1.847-0.742,2.56c-0.737,0.713-1.529,0.495-1.529,0.495s-1.331-0.582-1.595-0.718c-0.274-0.142-0.517-0.151-0.751-0.066c-0.02,0.007-0.039,0.018-0.057,0.029l-0.175,0.75l0.025-0.623c-0.156,0.176-0.271,0.42-0.271,0.42l0.088,0.327l-0.248,0.565c-0.002,0.012-0.005,0.023-0.006,0.035l0.008,0.003c0,0,0.087-0.196,0.222-0.357l0.182-0.369L1.493,32.94c0.055-0.044,0.112-0.07,0.172-0.074c0.281-0.017,0.629,0.158,0.629,0.158s1.135,0.611,1.642,0.716s0.875-0.065,1.205-0.292c0.527-0.365,1.143-1.121,1.4-1.839c0.229-0.646,0.279-2.394,0.279-2.394l0.004,0.014c0,0,0-0.421-0.011-0.518c-0.012-0.098-0.075-0.553,0.204-0.783c0.278-0.234,0.459-0.347,1.144-0.364c0.68-0.017,0.886,0.38,0.886,0.38S9.28,28.269,9.28,28.48c0,0.21-0.068,0.34-0.068,0.34s-0.371,0.626-0.5,0.934c-0.13,0.307-0.636,1.323-0.489,2.177c0.148,0.852,1.479,1.251,1.479,1.251s1.062,0.25,2.575,0.027l3.12-0.503l0.543-0.624l0.218,0.474c0.805-0.147,2.14-0.369,3.583-0.511c2.326-0.228,4.787-0.262,5.821-0.132c0,0,0.484,0.061,0.405,0.234c-0.062,0.136-0.421,0.415-0.421,0.415s-0.135,0.081-0.654,0.667s-0.671,1.155-0.693,1.661c-0.024,0.505,0.516,1.995,2.415,2.394c1.901,0.397,4.077-0.341,4.077-0.341s1.427-0.314,2.786-1.674c1.41-1.411,0.012-3.108,0.012-3.108s-0.22-0.304-0.647-0.442c0,0-0.187-0.05-0.079-0.17c0.108-0.12,0.37-0.647,1.37-0.905c1-0.257,3.977-1.198,11.065-2.135l0.274-0.617l0.874,0.459c2.708-0.373,4.551-0.694,7.827-1.454c0,0,3.04-0.539,3.675-1.651c0.368-0.65,1.032-1.539-0.045-2.434c0,0-0.125-0.161-0.791-0.312c-0.666-0.151-1.179-0.252-1.738-0.653c-0.563-0.403-0.551-0.869-0.551-0.869s-0.047-0.445,0.862-0.958c0,0,0.851-0.623,2.54-1.158c1.691-0.533,3.648-0.296,3.648-0.296s0.82,0.089,0.685,0.643c-0.14,0.555-0.604,1.482-0.622,1.959c-0.021,0.474,0.012,1.027,0.938,1.414c0.931,0.386,2.267,0.266,2.267,0.266s1.386-0.069,3.647-0.801c2.265-0.731,4.594-1.573,4.594-1.573l-0.094-0.483l0.971,0.173c0.591-0.22,1.406-0.539,2.285-0.936c1.801-0.81,2.656-1.488,3.48-1.958c0,0,1.815-1.118,2.887-1.088c0,0,0.25-0.009,0.272,0.32c0.022,0.329,0.104,0.814,0.218,1.096c0.111,0.281,0.734,1.822,2.729,2.048c1.993,0.228,2.846-1.118,2.846-1.118s0.683-1.049-0.493-2.296c0,0-0.961-1.028-0.99-1.107c0,0-0.104-0.155,0.168-0.233c0.269-0.078,3.152-0.884,4.268-1.398c0,0,0.012-0.005,0.036-0.015l-0.271-0.485l0.535,0.365c0.202-0.101,0.449-0.246,0.544-0.395c0.171-0.271-0.054-0.797-0.054-0.797l0.006-0.007c-0.133-0.184-0.266-0.366-0.4-0.546l-0.606-0.256l-0.06,0.033L91.075,11.742"/><path style="&st34;" d="M8.12,16.324l-0.291,0.435c0.134-0.023,0.244-0.056,0.244-0.056s0.404-0.066,1.112,0.12c0.917,0.244,2.067-0.496,2.067-0.496s0.872-0.523,1.274-1.381l0.361-1.005c0,0,0.291-0.972,1.105-1.281c0,0,0.317-0.171,0.831-0.177c0.513-0.005,0.392,0.354,0.392,0.354s-0.056,0.233-0.586,0.912c-0.529,0.677-0.671,1.196-0.671,1.196s-0.318,0.722,0.193,0.957c0,0,0.24,0.141,0.939-0.091c0.7-0.233,3.02-0.843,4.438-1.06l0.993-0.506c-0.313-0.23-0.602-0.444-0.602-0.444c-2.388,0.442-4.168,0.995-4.775,1.226c-0.609,0.23-0.62,0.082-0.62,0.082c-0.211-0.248,0.435-1.022,0.435-1.022s0.655-0.894,0.913-1.715c0.259-0.82-0.892-0.707-0.892-0.707c-0.758,0.121-1.303,0.48-1.93,1.236c-0.486,0.586-0.782,1.389-0.893,1.814c-0.071,0.267-0.193,0.515-0.193,0.515s-0.091,0.165-0.45,0.322c-0.416,0.182-1.228,0.396-1.228,0.396s-0.54,0.045-0.931-0.15c-0.24-0.118-0.901,0.05-0.901,0.05l0.091-0.504l-0.082-0.032l-0.683,0.383c-0.115,0.189-0.228,0.379-0.341,0.569c-0.063,0.146-0.179,0.475,0.044,0.51c0.05,0.008,0.113,0.008,0.164,0.008L8.12,16.324L8.12,16.324z"/><path style="&st34;" d="M13.295,9.19c0,0,0.342-0.271,0.342-0.026c0,0.248-0.333,0.69-0.333,0.69s-0.107,0.134-0.172,0.134C13.068,9.987,13.15,9.516,13.295,9.19L13.295,9.19z"/><path style="&st12;" d="M-16.122-14.641"/><path style="&st34;" d="M10.595,12.501c0,0-0.388,0.46,0,0.52l0.838-0.828c-0.037-0.037-0.054-0.055-0.157-0.112C11.277,12.081,10.752,12.343,10.595,12.501L10.595,12.501z"/><path style="&st28;" d="M77.807,85.745c0,0-1.75,0.806-3.396,1.603c-1.647,0.803-2.25,1.14-2.25,1.14s-0.088,0.049-0.031,0.082c0.056,0.028-0.008,0.063-0.008,0.063c-0.847,0.409-2.703,1.07-2.703,1.07s-0.167,0.057-0.157,0.02c0.006-0.041,0.199-0.105,0.199-0.105s0.381-0.146,0.283-0.217c-0.098-0.072-1.21,0.305-1.21,0.305s-1.949,0.621-2.894,0.887c-0.941,0.269-2.75,0.735-2.75,0.735c-1.201,0.298-3.75,0.798-4.315,0.901c-0.562,0.104-0.417,0.064-0.417,0.064s0.492-0.189-0.411-0.226c-1.146-0.05-2.362,0.112-3.612,0.288c-1.25,0.18-1.178,0.324-1.178,0.324s-0.04,0.154,0.708,0.14c0.752-0.019,0.534,0.046,0.534,0.046c-1.396,0.202-4.2,0.238-4.2,0.238l0.005,0.01c0.456,0.014,0.916,0.018,1.376,0.018c0.608,0,1.218-0.01,1.822-0.031c0.241-0.021,1.483-0.15,1.925-0.244c0.486-0.105-0.093-0.105-0.093-0.105l-0.74-0.023c0,0-0.776-0.026-0.052-0.158c0.729-0.133,1.834-0.192,2.388-0.252c0.83-0.094,0.541,0.105,0.541,0.105l-0.04,0.023c0,0,0.014,0.094,0.528,0.066c0.515-0.024,4.721-0.804,7.069-1.487c2.347-0.688,4.102-1.255,4.102-1.255s0.157-0.055,0.066,0.025c-0.094,0.078-0.463,0.2-0.463,0.2s-0.595,0.3,0.844-0.108c0.066-0.02,0.134-0.039,0.197-0.06c1.234-0.469,2.446-0.983,3.635-1.543c0.029-0.028,0.131-0.146-0.021-0.101c-0.172,0.056,0-0.065,0.187-0.131c0.184-0.066,2.267-1.162,3.363-1.608l0.002,0.003c0.394-0.227,0.781-0.455,1.17-0.691L77.807,85.745L77.807,85.745z"/><linearGradient id="SVGID_26_" gradientUnits="userSpaceOnUse" x1="217.6563" y1="-436.751" x2="217.6563" y2="-436.751" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset=".078" stop-color="#F4F4F4"/><stop offset=".3807" stop-color="#CECECE"/><stop offset=".5396" stop-color="#BFBFBF"/><stop offset=".8357" stop-color="#7C7C7C"/><stop offset=".8996" stop-color="#A8A8A8"/><stop offset=".9093" stop-color="#9A9A9A"/><stop offset=".9327" stop-color="#7D7D7D"/><stop offset=".9558" stop-color="#686868"/><stop offset=".9785" stop-color="#5B5B5B"/><stop offset="1" stop-color="#575757"/></linearGradient><path style="&st46;" d="M3.893,50.249L3.893,50.249L3.893,50.249z"/><linearGradient id="SVGID_27_" gradientUnits="userSpaceOnUse" x1="214.3262" y1="-436.5107" x2="322.8717" y2="-424.4851" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset=".078" stop-color="#F4F4F4"/><stop offset=".3807" stop-color="#CECECE"/><stop offset=".5396" stop-color="#BFBFBF"/><stop offset=".8357" stop-color="#7C7C7C"/><stop offset=".8996" stop-color="#A8A8A8"/><stop offset=".9093" stop-color="#9A9A9A"/><stop offset=".9327" stop-color="#7D7D7D"/><stop offset=".9558" stop-color="#686868"/><stop offset=".9785" stop-color="#5B5B5B"/><stop offset="1" stop-color="#575757"/></linearGradient><path style="&st47;" d="M1.193,48.543l0.107,0.98c0.236,0.285,0.579,0.675,1.067,1.181c1.084,1.121,1.428,0.416,1.428,0.416s0.072-0.201,0.092-0.586c-0.042,0.216-0.209,0.403-0.788-0.056c-0.298-0.237-0.688-0.627-1.076-1.049c-0.326-0.326-0.723-0.742-1.021-1.117l0.048,0.065l-0.213,0.526c0,0,0.069,0.115,0.268,0.376L1.193,48.543L1.193,48.543z"/><linearGradient id="SVGID_28_" gradientUnits="userSpaceOnUse" x1="213.8887" y1="-436.4771" x2="336.8819" y2="-422.851" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#FFF"/><stop offset=".078" stop-color="#F4F4F4"/><stop offset=".3807" stop-color="#CECECE"/><stop offset=".5396" stop-color="#BFBFBF"/><stop offset=".8357" stop-color="#7C7C7C"/><stop offset=".8996" stop-color="#A8A8A8"/><stop offset=".9093" stop-color="#9A9A9A"/><stop offset=".9327" stop-color="#7D7D7D"/><stop offset=".9558" stop-color="#686868"/><stop offset=".9785" stop-color="#5B5B5B"/><stop offset="1" stop-color="#575757"/></linearGradient><path style="&st48;" d="M3.741,49.133c-0.006-0.027-0.013-0.054-0.02-0.078c0.012,0.088,0.028,0.179,0.043,0.272c0,0,0.094,0.394,0.12,0.753C3.87,49.813,3.83,49.498,3.741,49.133z"/><linearGradient id="SVGID_29_" gradientUnits="userSpaceOnUse" x1="411.2539" y1="557.002" x2="507.2363" y2="537.6277" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EDEDEE"/><stop offset=".4176" stop-color="#FFF"/><stop offset=".6264" stop-color="#F8F9F9"/><stop offset="1" stop-color="#BFC0C2"/></linearGradient><path style="&st49;" d="M99.696,28.566l0.29,0.316c0.406-0.238,0.654,0.045,0.654,0.045l-0.386-0.494c-0.383,0.082-1.093,0.256-2.233,0.61c0,0-1.353,0.594-1.59,1.532c-0.016,0.332,0.049,0.641,0.116,0.876c0.753,1.429,0.913,1.666,0.913,1.666c0.499,1.091,0.422,1.993,0.25,2.824c-0.188,0.921-1.188,1.668-1.794,1.842c-0.608,0.171-0.953,0-1.14-0.483c-0.188-0.485-0.157-0.845-0.438-2.34c-0.28-1.499-0.653-2.2-1.216-2.372c-0.563-0.173-1.313,0.468-1.749,0.811c-0.438,0.344-2.417,2.152-2.417,2.152s-2.324,2.091-5.743,4.026c-3.417,1.935-7.69,3.418-7.69,3.418s-2.842,1.092-3.525,0.998c-0.688-0.093-0.516-0.718-0.297-1.076c0.219-0.36,0.516-0.937,0.766-1.545c0.313-0.756,0.201-1.654-0.359-1.967c-0.562-0.311-1.248-0.468-3.523,0.094s-3.197,1.076-3.838,1.451c-0.643,0.376-1.576,1.233-1.842,1.716c-0.266,0.484-0.563,0.983,0.126,1.576c0.688,0.594,0.763,0.485,1.56,1.046c0.797,0.562,0.922,0.64,0.969,1.466c0.045,0.827-0.766,1.341-0.766,1.341s-3.123,2.082-6.602,2.777c-2.34,0.469-6.833,0.639-6.833,0.639s-1.327-0.045-5.384,0.547c-4.056,0.594-6.787,1.514-7.738,1.856c-0.952,0.343-2.34,0.81-3.136,1.17c-0.795,0.358-0.375,0.89-0.203,1.015c0.172,0.123,1.185,1.074,1.498,1.354c0.312,0.282,1.466,1.279,0.108,2.108c-1.356,0.826-3.603,1.264-3.603,1.264s-3.121,0.654-4.119,0.234c-1.001-0.422-1.2-0.778-1.452-1.358c-0.313-0.718-0.016-1.263,0.794-1.78c0.77-0.486,0.469-1.199,0.469-1.199c-0.983-1.9-3.058-2.058-4.774-1.936c-2.72,0.198-5.358,0.471-7.425,0.734c-3.059,0.39-4.541-0.063-5.992-0.516c-1.452-0.453-2.997-1.529-3.154-2.498c-0.027-0.097-0.039-0.199-0.042-0.307c-0.078-0.758,0.074-1.146,0.184-1.784c0.108-0.625-0.043-1.532-0.084-1.758c-0.008-0.026-0.016-0.058-0.023-0.085c-0.507-1.304-1.725-1.903-2.668-2.058c-0.953-0.157-0.983,0.857-0.983,0.857s-0.002,0.012-0.006,0.04c0.078-0.208,0.222-0.315,0.444-0.31c0.577,0.02,2.259,0.361,2.781,1.754c0,0,0.218,0.648,0.019,1.479c-0.199,0.832-0.162,1.571-0.019,2.295c0.145,0.725,0.759,1.408,1.465,1.969c0.704,0.562,2.745,1.535,4.734,1.66c1.814,0.117,2.483,0.037,2.587,0.023l0.759-0.768l0.135,0.666c0.81-0.088,2.115-0.229,3.619-0.394c2.529-0.271,4.227-0.541,5.8-0.306c1.572,0.232,2.078,1.463,2.078,1.463s0.107,0.313-0.253,0.542c-0.349,0.226-0.75,0.548-0.947,0.891c-0.2,0.345-0.411,1.066,0.159,2.033c0.572,0.965,2.142,1.595,3.478,1.435c1.336-0.158,3.336-0.672,4.521-0.98c1.286-0.336,2.424-0.969,2.572-1.979c0.148-1.009-1.534-2.297-1.534-2.297s-0.81-0.611-0.909-0.75c-0.1-0.14,0.099-0.197,0.099-0.197s0.95-0.229,1.356-0.416c0.403-0.19,1.523-0.644,3.353-1.217c1.831-0.572,5.609-1.248,5.609-1.248s2.09-0.332,4.694-0.543l0.612-0.705l0.493,0.627c0.406-0.023,0.819-0.045,1.235-0.061c3.572-0.129,5.343-0.555,7.24-0.979c1.897-0.426,4.569-1.979,4.965-2.276c0.396-0.296,1.229-0.662,1.395-1.958c0.17-1.294-1.363-2.157-1.363-2.157s-1.218-0.643-1.476-0.929c-0.256-0.288-0.019-0.562-0.019-0.562s0.689-1.485,2.896-2.355c2.207-0.872,3.69-1.106,4.619-1.207c0.931-0.099,1.247,0.237,1.375,0.395c0.128,0.158,0.128,0.485,0.021,0.821c-0.101,0.308-0.443,1.039-0.644,1.396c-0.199,0.356-0.522,1.216-0.317,1.622c0.211,0.405,0.842,0.592,1.662,0.444c0.822-0.147,2.987-0.761,4.889-1.553c1.897-0.793,5.074-2.344,5.074-2.344s0.01-0.005,0.021-0.013l0.086-0.729l0.729,0.296c1.021-0.562,2.764-1.582,4.01-2.63c1.871-1.574,3.699-3.225,4.166-3.641c0.465-0.415,0.89-0.751,1.305-0.732c0.416,0.021,0.734,0.318,0.99,1.434c0.258,1.119,0.306,2.038,0.426,2.583c0.117,0.542,0.285,1.176,0.929,1.305c0.644,0.128,1.513-0.436,1.841-0.713c0.326-0.277,0.918-1.176,0.879-2.383c0,0,0.068-1.605-0.762-3.127c0,0-0.348-0.614-0.477-0.782c-0.088-0.119-0.155-0.238-0.008-0.523c0.146-0.288,0.465-0.821,1.059-1.157c0.449-0.256,0.881-0.316,1.128-0.396c0,0,0.28-0.069,0.636-0.266L99.696,28.566L99.696,28.566z"/><path style="&st23;" d="M1.547,32.696l-0.05,0.239c0.053-0.041,0.111-0.068,0.17-0.072c0.281-0.018,0.629,0.158,0.629,0.158s1.135,0.61,1.642,0.716c0.507,0.105,0.875-0.065,1.205-0.292c0.25-0.174,0.521-0.434,0.763-0.737c-0.29,0.29-0.725,0.548-1.365,0.595c0,0-0.571-0.049-1.419-0.587c-0.846-0.537-1.327-0.231-1.729,0.105l0,0l-0.249,0.564c-0.001,0.013-0.003,0.023-0.006,0.036l0.009,0.001c0,0,0.087-0.192,0.217-0.352L1.547,32.696L1.547,32.696z"/><path style="&st4;" d="M6.387,31.961c0.059-0.12,0.112-0.238,0.155-0.354c0.05-0.14,0.09-0.334,0.125-0.55c-0.096,0.44-0.223,0.73-0.223,0.73S6.428,31.853,6.387,31.961L6.387,31.961z"/><path style="&st4;" d="M6.807,28.654c-0.038,0.439-0.038,0.987-0.038,1.493l0,0c0.04-0.509,0.052-0.935,0.052-0.935l0.004,0.014c0,0,0-0.421-0.011-0.518C6.811,28.695,6.809,28.677,6.807,28.654z"/><linearGradient id="SVGID_30_" gradientUnits="userSpaceOnUse" x1="413.5137" y1="516.4121" x2="417.999" y2="516.4121" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#E2E3E4"/><stop offset=".5055" stop-color="#FFF"/></linearGradient><path style="&st50;" d="M8.12,16.324l-0.291,0.435c0.087-0.014,0.089-0.007,0.244-0.056c0,0,0.404-0.066,1.112,0.12c0.917,0.244,2.067-0.496,2.067-0.496s0.272-0.164,0.583-0.458c-0.4,0.24-1.385,0.762-2.132,0.585c-0.961-0.229-0.994-0.017-1.336-0.049c-0.292-0.028-0.292-0.11-0.275-0.314c0.002-0.032,0.023-0.054,0.03-0.092c0.05-0.261,0.339-0.689,0.339-0.689l-0.684,0.383c-0.115,0.189-0.227,0.378-0.34,0.569c-0.063,0.146-0.179,0.475,0.044,0.509c0.055,0.009,0.11,0.011,0.163,0.009L8.12,16.324L8.12,16.324z"/><path style="&st23;" d="M17.019,15.036c-1.027,0.278-1.972,0.734-2.494,0.604c-0.438-0.109-0.084-0.76,0.042-0.965c0.069-0.146,0.167-0.292,0.249-0.406c0.31-0.506,0.833-1.351,0.833-1.351s0,0,0-0.002c0.017-0.032,0.033-0.067,0.049-0.102c0.067-0.18,0.12-0.537-0.472-0.597c-0.799-0.082-1.613,0.619-1.613,0.619s-0.547,0.301-0.838,1.417l0.112-0.313c0,0,0.291-0.973,1.105-1.281c0,0,0.317-0.171,0.831-0.177c0.513-0.005,0.392,0.354,0.392,0.354s-0.056,0.233-0.586,0.912c-0.529,0.677-0.671,1.195-0.671,1.195s-0.319,0.723,0.193,0.957c0,0,0.238,0.141,0.939-0.091c0.7-0.233,3.02-0.843,4.438-1.06l0.993-0.506C19.849,14.299,18.012,14.769,17.019,15.036L17.019,15.036z"/><path style="&st23;" d="M-16.122-14.641"/><path style="&st23;" d="M-16.122-14.641"/><path style="&st59;" d="M90.578,74.217c0.006-0.004,0.009-0.008,0.014-0.013C90.587,74.21,90.582,74.213,90.578,74.217z"/><path style="&st59;" d="M90.821,73.951c0.001-0.002,0.002-0.004,0.003-0.004C90.823,73.947,90.822,73.949,90.821,73.951z"/><path style="&st59;" d="M90.738,74.042c0.003-0.004,0.008-0.009,0.011-0.013C90.746,74.033,90.741,74.038,90.738,74.042z"/><path style="&st8;" d="M87.9,76.68l-0.164,0.174c-0.646,0.716-0.969,1.007-0.969,1.007l-0.242,0.269l0,0c-0.002,0.006-0.006,0.012-0.012,0.014c0.008,0.002,0.018,0.004,0.041,0.004c0,0,0.229-0.002,0.588-0.219c-0.072,0.041-0.139,0.068-0.181,0.07c-0.177,0.012,0.431-0.538,0.431-0.538s0.588-0.626,0.967-1.125c0.382-0.497,0.138-0.468,0.138-0.468s-0.087-0.021-0.397,0.125C88.125,76.018,88.268,76.223,87.9,76.68L87.9,76.68z"/><path style="&st59;" d="M90.657,74.133c0.003-0.006,0.007-0.013,0.013-0.017C90.664,74.121,90.662,74.128,90.657,74.133z"/><path style="&st0;" d="M72.945,81.21c0,0,2.215-0.931,3.402-0.79c0,0,0.611,0.059-0.062,0.711c-0.672,0.652-0.892,1.168,0.396,0.752c0,0,0.094-0.033,0.244-0.086c-0.504,0.143-0.734,0.143-0.658,0.033c0.127-0.188,0.461-0.461,0.461-0.461s0.399-0.4,0.399-0.801c0,0,0.128-0.588-1.604-0.225c-1.01,0.209-1.969,0.59-2.588,0.867C72.941,81.211,72.943,81.211,72.945,81.21L72.945,81.21z"/><path style="&st59;" d="M72.234,81.555l-0.004,0.002C72.232,81.557,72.234,81.555,72.234,81.555z"/><path style="&st59;" d="M88.057,76.014c-0.014,0.008-0.026,0.015-0.043,0.021C88.028,76.027,88.043,76.021,88.057,76.014z"/><path style="&st14;" d="M78.305,81.299c1.448-0.521,3.93-1.854,5.023-2.492C82.232,79.442,79.73,80.717,78.305,81.299z"/><path style="&st59;" d="M87.512,76.325c0.026-0.017,0.055-0.032,0.08-0.049C87.566,76.293,87.538,76.309,87.512,76.325z"/><path style="&st59;" d="M91.618,73.084c0.008-0.011,0.019-0.023,0.026-0.029C91.637,73.061,91.626,73.073,91.618,73.084z"/><path style="&st59;" d="M91.434,73.281c0.01-0.012,0.019-0.02,0.023-0.027C91.451,73.264,91.441,73.27,91.434,73.281z"/><path style="&st59;" d="M91.521,73.188c0.01-0.012,0.02-0.022,0.029-0.032C91.539,73.165,91.53,73.178,91.521,73.188z"/><path style="&st59;" d="M90.9,73.863c0.003-0.006,0.007-0.01,0.012-0.016C90.907,73.854,90.903,73.857,90.9,73.863z"/><path style="&st59;" d="M71.246,82.088c-0.014,0.008-0.023,0.018-0.036,0.022C71.221,82.105,71.232,82.096,71.246,82.088z"/><path style="&st59;" d="M91.346,73.375c0.008-0.008,0.014-0.015,0.021-0.021C91.359,73.36,91.354,73.367,91.346,73.375z"/><path style="&st59;" d="M91.077,73.669c0.006-0.006,0.01-0.011,0.013-0.015C91.087,73.659,91.083,73.663,91.077,73.669z"/><path style="&st59;" d="M91.251,73.479c0.007-0.006,0.015-0.012,0.021-0.021C91.266,73.463,91.255,73.473,91.251,73.479z"/><path style="&st59;" d="M90.987,73.768c0.004-0.006,0.01-0.012,0.016-0.021C90.997,73.756,90.991,73.762,90.987,73.768z"/><path style="&st59;" d="M91.161,73.578c0.006-0.006,0.011-0.014,0.017-0.02C91.172,73.564,91.165,73.572,91.161,73.578z"/><path style="&st59;" d="M71.816,81.764c-0.008,0.006-0.02,0.012-0.026,0.017C71.799,81.774,71.809,81.77,71.816,81.764z"/><path style="&st59;" d="M72.044,81.646c-0.006,0.004-0.012,0.006-0.019,0.009C72.032,81.652,72.038,81.649,72.044,81.646z"/><path style="&st59;" d="M71.305,82.055c-0.011,0.008-0.021,0.014-0.031,0.021C71.283,82.067,71.294,82.063,71.305,82.055z"/><path style="&st59;" d="M71.969,81.684c-0.008,0.004-0.015,0.009-0.021,0.014C71.953,81.692,71.961,81.688,71.969,81.684z"/><path style="&st59;" d="M72.109,81.613c-0.004,0.005-0.01,0.006-0.016,0.01C72.102,81.619,72.105,81.617,72.109,81.613z"/><path style="&st59;" d="M72.008,81.665c-0.007,0.004-0.013,0.007-0.021,0.011C71.994,81.672,72.001,81.669,72.008,81.665z"/><path style="&st59;" d="M72.206,81.566c-0.003,0.002-0.005,0.003-0.007,0.004C72.201,81.569,72.203,81.568,72.206,81.566z"/><path style="&st59;" d="M72.148,81.594c-0.008,0.004-0.016,0.01-0.024,0.015C72.135,81.604,72.141,81.598,72.148,81.594z"/><path style="&st59;" d="M71.928,81.707c-0.01,0.003-0.02,0.01-0.027,0.016C71.908,81.715,71.918,81.711,71.928,81.707z"/><path style="&st59;" d="M72.193,81.575c-0.006,0.001-0.01,0.003-0.014,0.004C72.184,81.578,72.189,81.575,72.193,81.575z"/><path style="&st59;" d="M72.172,81.585c-0.004,0.003-0.008,0.005-0.015,0.007C72.164,81.59,72.168,81.585,72.172,81.585z"/><path style="&st59;" d="M72.079,81.631c-0.008,0.002-0.013,0.004-0.019,0.006C72.066,81.635,72.071,81.633,72.079,81.631z"/><path style="&st59;" d="M71.866,81.739c-0.011,0.002-0.021,0.008-0.027,0.013C71.848,81.747,71.857,81.741,71.866,81.739z"/><path style="&st59;" d="M71.555,81.906c-0.018,0.012-0.033,0.02-0.052,0.029C71.521,81.924,71.539,81.918,71.555,81.906z"/><path style="&st59;" d="M72.219,81.561c0,0.002-0.002,0.002-0.002,0.004C72.217,81.563,72.219,81.563,72.219,81.561z"/><path style="&st59;" d="M71.421,81.986c-0.011,0.006-0.022,0.01-0.03,0.02C71.398,81.996,71.41,81.992,71.421,81.986z"/><path style="&st59;" d="M71.363,82.02c-0.012,0.005-0.021,0.013-0.032,0.021C71.342,82.032,71.354,82.024,71.363,82.02z"/><path style="&st59;" d="M71.482,81.948c-0.014,0.006-0.023,0.015-0.036,0.021C71.458,81.963,71.471,81.956,71.482,81.948z"/><path style="&st59;" d="M71.768,81.79c-0.01,0.004-0.018,0.009-0.024,0.017C71.751,81.799,71.758,81.794,71.768,81.79z"/><path style="&st59;" d="M91.708,72.984c0.013-0.014,0.024-0.028,0.04-0.042C91.734,72.956,91.723,72.971,91.708,72.984z"/><path style="&st59;" d="M71.717,81.818c-0.01,0.004-0.019,0.009-0.027,0.015C71.698,81.827,71.707,81.822,71.717,81.818z"/><path style="&st59;" d="M71.665,81.846c-0.011,0.006-0.021,0.014-0.028,0.018C71.645,81.858,71.654,81.852,71.665,81.846z"/><path style="&st59;" d="M71.609,81.875c-0.01,0.008-0.021,0.014-0.03,0.02C71.589,81.889,71.602,81.881,71.609,81.875z"/><path style="&st59;" d="M92.443,72.197c-0.021,0.021-0.037,0.039-0.055,0.061C92.406,72.238,92.423,72.217,92.443,72.197z"/><path style="&st59;" d="M92.359,72.287c-0.021,0.021-0.041,0.044-0.061,0.066C92.318,72.331,92.339,72.309,92.359,72.287z"/><path style="&st59;" d="M92.501,72.135c-0.011,0.015-0.021,0.023-0.028,0.033C92.48,72.157,92.49,72.148,92.501,72.135z"/><path style="&st59;" d="M91.786,72.899c0.022-0.021,0.042-0.042,0.062-0.063C91.828,72.857,91.807,72.878,91.786,72.899z"/><path style="&st59;" d="M92.273,72.379c-0.014,0.016-0.025,0.029-0.041,0.045C92.245,72.409,92.26,72.395,92.273,72.379z"/><path style="&st59;" d="M92.579,72.053c-0.013,0.012-0.021,0.021-0.03,0.032C92.559,72.074,92.569,72.063,92.579,72.053z"/><path style="&st59;" d="M92.762,71.858c-0.002,0-0.002,0-0.002,0.001C92.76,71.858,92.76,71.858,92.762,71.858z"/><path style="&st59;" d="M92.703,71.919c-0.004,0.005-0.01,0.013-0.014,0.017C92.693,71.928,92.699,71.924,92.703,71.919z"/><path style="&st59;" d="M87.938,76.074c-0.017,0.008-0.027,0.016-0.043,0.023C87.907,76.09,87.922,76.082,87.938,76.074z"/><path style="&st59;" d="M92.648,71.98c-0.012,0.011-0.021,0.021-0.029,0.029C92.629,72,92.637,71.991,92.648,71.98z"/><path style="&st59;" d="M87.666,76.229c-0.018,0.013-0.031,0.021-0.051,0.031C87.633,76.25,87.648,76.241,87.666,76.229z"/><path style="&st59;" d="M48.204,91.026c0,0-0.001,0-0.003,0.002C48.203,91.026,48.203,91.026,48.204,91.026z"/><path style="&st59;" d="M48.073,91.03c-0.007,0-0.013,0-0.021,0C48.06,91.03,48.066,91.03,48.073,91.03z"/><path style="&st59;" d="M48.136,91.028c-0.007,0.002-0.013,0.002-0.02,0.002C48.123,91.03,48.129,91.03,48.136,91.028z"/><path style="&st59;" d="M48.005,91.032c-0.003,0-0.007,0-0.012,0C47.998,91.032,48.002,91.032,48.005,91.032z"/><path style="&st59;" d="M47.94,91.035c-0.004,0-0.009,0-0.015,0C47.93,91.035,47.935,91.035,47.94,91.035z"/><path style="&st59;" d="M87.869,76.111c-0.014,0.006-0.021,0.015-0.039,0.021C87.848,76.126,87.857,76.117,87.869,76.111z"/><path style="&st59;" d="M87.807,76.146c-0.014,0.009-0.025,0.018-0.041,0.021C87.779,76.164,87.793,76.155,87.807,76.146z"/><path style="&st59;" d="M87.738,76.186c-0.016,0.011-0.028,0.018-0.044,0.024C87.71,76.203,87.723,76.196,87.738,76.186z"/><path style="&st59;" d="M87.951,76.067c0.02-0.011,0.035-0.021,0.054-0.027C87.986,76.047,87.971,76.057,87.951,76.067z"/><path style="&st59;" d="M87.719,77.52c0,0-0.082,0.064-0.193,0.147C87.592,77.621,87.664,77.566,87.719,77.52z"/><path style="&st59;" d="M92.205,72.452c-0.021,0.022-0.042,0.046-0.064,0.067C92.163,72.498,92.186,72.475,92.205,72.452z"/><path style="&st59;" d="M28.05,87.006c-0.019-0.007-0.037-0.016-0.056-0.021C28.013,86.991,28.031,86.999,28.05,87.006z"/><path style="&st59;" d="M71.051,82.217c-0.013,0.008-0.021,0.017-0.037,0.021C71.027,82.23,71.038,82.223,71.051,82.217z"/><path style="&st59;" d="M45.854,89.871c-0.024,0-0.049-0.004-0.074-0.004C45.806,89.867,45.831,89.871,45.854,89.871z"/><path style="&st59;" d="M27.678,86.883c0.02,0.004,0.039,0.01,0.058,0.019C27.717,86.893,27.696,86.887,27.678,86.883z"/><path style="&st59;" d="M27.555,86.844c0.038,0.012,0.078,0.022,0.119,0.037C27.633,86.869,27.593,86.854,27.555,86.844z"/><path style="&st59;" d="M27.862,86.941c-0.041-0.014-0.082-0.026-0.123-0.04C27.78,86.913,27.82,86.928,27.862,86.941z"/><path style="&st59;" d="M91.88,72.799c0.015-0.016,0.026-0.027,0.04-0.043C91.907,72.771,91.895,72.784,91.88,72.799z"/><path style="&st59;" d="M28.058,87.006c0.04,0.016,0.079,0.026,0.116,0.041C28.137,87.033,28.098,87.021,28.058,87.006z"/><path style="&st59;" d="M91.977,72.695c0.014-0.016,0.026-0.027,0.041-0.044C92.002,72.668,91.989,72.68,91.977,72.695z"/><path style="&st59;" d="M92.057,72.612c0.021-0.022,0.039-0.041,0.061-0.062C92.096,72.571,92.076,72.59,92.057,72.612z"/><path style="&st59;" d="M27.991,86.985c-0.021-0.009-0.041-0.017-0.062-0.022C27.95,86.969,27.97,86.977,27.991,86.985z"/><path style="&st59;" d="M71.133,82.162c0.021-0.013,0.037-0.021,0.055-0.036C71.17,82.139,71.152,82.149,71.133,82.162z"/><path style="&st59;" d="M46.361,89.926c-0.016-0.002-0.035-0.004-0.053-0.008C46.325,89.922,46.345,89.924,46.361,89.926z"/><path style="&st59;" d="M71.122,82.17c-0.019,0.012-0.034,0.021-0.049,0.032C71.088,82.191,71.105,82.18,71.122,82.17z"/><path style="&st59;" d="M46.439,89.939c-0.017-0.002-0.032-0.006-0.049-0.008C46.407,89.934,46.422,89.938,46.439,89.939z"/><path style="&st59;" d="M46.513,89.953c-0.016-0.005-0.031-0.007-0.047-0.011C46.481,89.946,46.497,89.948,46.513,89.953z"/><path style="&st59;" d="M46.096,89.891c-0.031-0.002-0.065-0.006-0.1-0.01C46.031,89.885,46.065,89.889,46.096,89.891z"/><path style="&st59;" d="M46.278,89.913c-0.02-0.002-0.041-0.004-0.061-0.006C46.237,89.909,46.259,89.911,46.278,89.913z"/><path style="&st59;" d="M46.19,89.904c-0.028-0.005-0.054-0.008-0.084-0.012C46.136,89.896,46.163,89.899,46.19,89.904z"/><path style="&st59;" d="M45.971,89.881c-0.025-0.005-0.051-0.006-0.079-0.009C45.92,89.875,45.945,89.877,45.971,89.881z"/><path style="&st59;" d="M27.926,86.961c-0.02-0.004-0.039-0.011-0.058-0.019C27.888,86.953,27.908,86.957,27.926,86.961z"/><path style="&st59;" d="M47.395,90.975c0.001,0.004,0.003,0.004,0.004,0.004C47.398,90.979,47.396,90.979,47.395,90.975z"/><path style="&st59;" d="M47.375,90.969c0.001,0,0.002,0,0.003,0C47.378,90.969,47.376,90.969,47.375,90.969z"/><path style="&st59;" d="M47.418,90.982L47.418,90.982L47.418,90.982z"/><path style="&st59;" d="M47.465,90.996c0.003,0,0.004,0.001,0.006,0.001C47.47,90.997,47.468,90.996,47.465,90.996z"/><path style="&st59;" d="M47.442,90.988c0.001,0,0.002,0.002,0.002,0.002L47.442,90.988z"/><path style="&st59;" d="M47.342,90.955L47.342,90.955L47.342,90.955z"/><path style="&st59;" d="M46.589,89.967c-0.02-0.002-0.036-0.009-0.054-0.013C46.553,89.959,46.57,89.965,46.589,89.967z"/><path style="&st59;" d="M46.764,90.012c-0.011-0.004-0.021-0.008-0.033-0.012C46.742,90.006,46.753,90.008,46.764,90.012z"/><path style="&st59;" d="M49.049,90.953c-0.01,0.001-0.021,0.002-0.032,0.004C49.028,90.955,49.038,90.954,49.049,90.953z"/><path style="&st59;" d="M46.659,89.984c-0.021-0.006-0.039-0.01-0.061-0.014C46.619,89.975,46.639,89.979,46.659,89.984z"/><path style="&st59;" d="M47.767,91.028c0.003,0,0.003,0,0.006,0C47.773,91.028,47.77,91.028,47.767,91.028z"/><path style="&st59;" d="M47.821,91.03c0.003,0,0.007,0,0.013,0C47.828,91.03,47.824,91.03,47.821,91.03z"/><path style="&st59;" d="M45.214,89.855c0.047,0,0.092,0,0.139,0C45.308,89.855,45.261,89.855,45.214,89.855z"/><path style="&st59;" d="M47.716,91.026c0.005,0,0.009,0,0.013,0.002C47.727,91.026,47.722,91.026,47.716,91.026z"/><path style="&st32;" d="M46.772,90.014c0,0,0.158,0.021,0.059,0.338c-0.1,0.313,0.06,0.451,0.475,0.594l0.023,0.006c0,0,0.001,0,0.002,0c-0.079-0.04-0.074-0.08-0.074-0.08s-0.01-0.078,0.078-0.216c0.087-0.136,0.009-0.369-0.293-0.536C47.044,90.118,46.967,90.07,46.772,90.014L46.772,90.014L46.772,90.014z"/><path style="&st59;" d="M47.869,91.032c0.006,0,0.012,0,0.018,0C47.881,91.032,47.875,91.032,47.869,91.032z"/><path style="&st59;" d="M47.495,91.002c0.001,0,0.004,0,0.004,0C47.497,91.002,47.496,91.002,47.495,91.002z"/><path style="&st59;" d="M47.677,91.024c0.004,0,0.007,0,0.01,0C47.684,91.024,47.681,91.024,47.677,91.024z"/><path style="&st59;" d="M47.529,91.006c0.001,0,0.002,0,0.002,0S47.53,91.006,47.529,91.006z"/><path style="&st59;" d="M47.559,91.01c0.002,0.002,0.005,0.002,0.008,0.002C47.566,91.012,47.561,91.01,47.559,91.01z"/><path style="&st59;" d="M47.594,91.016c0.002,0,0.004,0,0.008,0C47.599,91.016,47.596,91.016,47.594,91.016z"/><path style="&st59;" d="M46.711,89.997c-0.011-0.002-0.026-0.007-0.043-0.011C46.685,89.99,46.701,89.995,46.711,89.997z"/><path style="&st59;" d="M28.748,87.256c-0.008-0.003-0.018-0.007-0.025-0.01C28.731,87.25,28.739,87.254,28.748,87.256z"/><path style="&st59;" d="M28.776,87.27c-0.007-0.002-0.016-0.008-0.024-0.012C28.761,87.262,28.769,87.268,28.776,87.27z"/><path style="&st59;" d="M28.681,87.23c-0.008-0.004-0.021-0.006-0.03-0.01C28.66,87.225,28.672,87.227,28.681,87.23z"/><path style="&st59;" d="M45.66,89.862c0.026,0,0.052,0.005,0.074,0.005C45.711,89.865,45.686,89.865,45.66,89.862z"/><path style="&st59;" d="M28.797,87.275c-0.005-0.002-0.013-0.006-0.021-0.008C28.784,87.271,28.792,87.273,28.797,87.275z"/><path style="&st59;" d="M27.38,86.794c0.038,0.011,0.074,0.022,0.112,0.031C27.453,86.816,27.417,86.803,27.38,86.794z"/><path style="&st59;" d="M27.492,86.825c0.021,0.004,0.039,0.011,0.058,0.019C27.53,86.836,27.512,86.829,27.492,86.825z"/><path style="&st59;" d="M28.814,87.284c-0.003-0.002-0.006-0.005-0.012-0.007C28.808,87.279,28.811,87.282,28.814,87.284z"/><path style="&st59;" d="M28.64,87.219c-0.011-0.006-0.021-0.01-0.03-0.014C28.621,87.21,28.629,87.213,28.64,87.219z"/><path style="&st61;" d="M27.687,87.239c-0.014-0.013-0.023-0.022-0.03-0.032c-0.263-0.197-0.343-0.418-0.343-0.418l0.009-0.011c0.017,0.007,0.034,0.011,0.052,0.014c-0.291-0.075-0.5-0.104-0.479-0.018c0.015,0.061,0.131,0.153,0.269,0.245c0.174,0.094,0.346,0.187,0.522,0.279V87.239L27.687,87.239z"/><path style="&st59;" d="M28.716,87.245c-0.009-0.003-0.018-0.006-0.027-0.01C28.699,87.239,28.708,87.242,28.716,87.245z"/><path style="&st59;" d="M28.602,87.202c-0.013-0.004-0.027-0.01-0.042-0.015C28.574,87.192,28.59,87.198,28.602,87.202z"/><path style="&st59;" d="M28.841,87.293c0,0-0.006-0.004-0.022-0.009C28.835,87.29,28.841,87.293,28.841,87.293z"/><path style="&st59;" d="M28.232,87.068c-0.018-0.006-0.031-0.014-0.047-0.018C28.201,87.055,28.215,87.063,28.232,87.068z"/><path style="&st59;" d="M45.534,89.858c0.028,0,0.054,0.002,0.081,0.002C45.587,89.858,45.562,89.858,45.534,89.858z"/><path style="&st59;" d="M45.397,89.855c0.029,0,0.06,0,0.089,0C45.457,89.855,45.427,89.855,45.397,89.855z"/><path style="&st59;" d="M28.348,87.11c-0.034-0.013-0.07-0.025-0.106-0.039C28.278,87.085,28.314,87.098,28.348,87.11z"/><path style="&st59;" d="M28.506,87.168c-0.013-0.005-0.025-0.01-0.037-0.015C28.481,87.158,28.494,87.162,28.506,87.168z"/><path style="&st59;" d="M28.401,87.129c-0.013-0.006-0.028-0.011-0.043-0.015C28.373,87.118,28.388,87.123,28.401,87.129z"/><path style="&st59;" d="M28.557,87.186c-0.013-0.004-0.025-0.012-0.04-0.017C28.531,87.176,28.544,87.182,28.557,87.186z"/><path style="&st59;" d="M28.458,87.15c-0.016-0.008-0.031-0.014-0.047-0.018C28.427,87.137,28.442,87.143,28.458,87.15z"/><path style="&st59;" d="M70.02,84.389c0.004,0,0.006,0,0.006,0C70.023,84.389,70.023,84.389,70.02,84.389z"/><path style="&st59;" d="M70.789,84.087c-0.001,0.003-0.003,0.005-0.004,0.005C70.786,84.09,70.788,84.088,70.789,84.087z"/><path style="&st59;" d="M70.762,84.102c-0.002,0.002-0.004,0.002-0.006,0.004C70.758,84.104,70.76,84.104,70.762,84.102z"/><path style="&st59;" d="M70.732,84.116c-0.002,0.002-0.004,0.003-0.006,0.004C70.729,84.119,70.73,84.118,70.732,84.116z"/><path style="&st59;" d="M70.697,84.133c-0.001,0-0.002,0-0.002,0.002C70.695,84.133,70.696,84.133,70.697,84.133z"/><path style="&st59;" d="M70.417,84.249c0.006-0.001,0.009-0.002,0.011-0.002C70.426,84.247,70.423,84.248,70.417,84.249z"/><path style="&st59;" d="M70.389,84.262h0.002H70.389z"/><path style="&st59;" d="M70.662,84.146L70.662,84.146L70.662,84.146z"/><path style="&st59;" d="M70.316,84.289c0.002-0.002,0.007-0.003,0.009-0.003C70.321,84.286,70.318,84.287,70.316,84.289z"/><path style="&st59;" d="M70.285,84.299c0.003,0,0.005-0.002,0.009-0.004C70.29,84.297,70.288,84.299,70.285,84.299z"/><path style="&st59;" d="M70.354,84.275c0.002-0.002,0.002-0.002,0.002-0.002S70.354,84.273,70.354,84.275z"/><path style="&st59;" d="M48.946,90.965c-0.011,0-0.022,0.004-0.033,0.004C48.924,90.969,48.935,90.965,48.946,90.965z"/><path style="&st59;" d="M70.256,84.311c0.002,0,0.004,0,0.006-0.002C70.26,84.311,70.258,84.311,70.256,84.311z"/><path style="&st59;" d="M70.78,82.41c0.013-0.009,0.026-0.021,0.042-0.032C70.809,82.389,70.793,82.401,70.78,82.41z"/><path style="&st59;" d="M70.956,82.279c0.013-0.008,0.022-0.016,0.033-0.023C70.98,82.264,70.969,82.271,70.956,82.279z"/><path style="&st59;" d="M70.898,82.321c0.012-0.009,0.022-0.017,0.033-0.022C70.923,82.305,70.91,82.313,70.898,82.321z"/><path style="&st2;" d="M70.903,83.794c0.2,0.064,0.106,0.171-0.087,0.278l0.089-0.033c0,0,0.793-0.436,0.458-0.633c-0.338-0.198-1.129-0.275-0.613-0.969l0.02-0.02c-0.442,0.344-0.756,0.727-0.498,1.021C70.27,83.443,70.387,83.629,70.903,83.794z"/><path style="&st59;" d="M70.566,84.191c-0.002,0-0.006,0.002-0.008,0.003C70.561,84.193,70.564,84.191,70.566,84.191z"/><path style="&st59;" d="M70.631,84.163c-0.002,0.001-0.004,0.002-0.006,0.003C70.627,84.165,70.629,84.164,70.631,84.163z"/><path style="&st59;" d="M70.598,84.176c0,0.002-0.004,0.004-0.006,0.004C70.594,84.18,70.598,84.178,70.598,84.176z"/><path style="&st59;" d="M70.493,84.223c-0.003,0-0.003,0-0.007,0.002C70.49,84.223,70.49,84.223,70.493,84.223z"/><path style="&st59;" d="M70.459,84.233c-0.002,0-0.004,0.002-0.008,0.004C70.455,84.235,70.457,84.233,70.459,84.233z"/><path style="&st59;" d="M70.842,82.363c0.012-0.01,0.024-0.018,0.034-0.025C70.866,82.346,70.854,82.354,70.842,82.363z"/><path style="&st59;" d="M48.293,91.024c-0.007,0-0.016,0-0.023,0C48.277,91.024,48.286,91.024,48.293,91.024z"/><path style="&st59;" d="M48.444,91.014c-0.004,0-0.011,0-0.017,0C48.434,91.014,48.44,91.014,48.444,91.014z"/><path style="&st59;" d="M48.369,91.02c-0.009,0-0.017,0-0.027,0C48.352,91.02,48.359,91.02,48.369,91.02z"/><path style="&st8;" d="M50.023,89.904c0,0,0.362,0.225,1.673,0.285c0,0,0.45,0,0.468,0.035c0.016,0.028,0.036,0.056-0.068,0.102l0,0c0.06-0.021,0.793-0.254,0.476-0.391c-0.04-0.019-0.063-0.024-0.074-0.028c-0.006,0-0.013,0-0.019-0.003l0,0c-0.008-0.002-0.016-0.002-0.021-0.004c-0.007,0-0.009-0.001-0.013-0.001c-0.006-0.003-0.014-0.003-0.021-0.005c-0.004,0-0.009,0-0.015-0.002c-0.005,0-0.011-0.002-0.017-0.002c-0.004,0-0.011-0.002-0.017-0.004c-0.005,0-0.012,0-0.015,0c-0.008-0.002-0.014-0.002-0.018-0.004c-0.004,0-0.012,0-0.016-0.002c-0.005,0-0.012,0-0.018,0c-0.002-0.004-0.008-0.004-0.01-0.004c-0.011-0.002-0.015-0.003-0.021-0.003c-0.004,0-0.006-0.001-0.008-0.001c-0.01-0.001-0.021-0.001-0.028-0.002c0,0-0.002,0-0.004-0.002c-0.007,0-0.015,0-0.021,0c-0.005-0.002-0.007-0.002-0.012-0.002s-0.011,0-0.02,0c-0.004,0-0.006,0-0.008,0c-0.008-0.002-0.013-0.002-0.019-0.002c-0.003,0-0.007,0-0.009,0c-0.008,0-0.014-0.002-0.018-0.002c-0.005,0-0.009-0.003-0.012-0.003c-0.006,0-0.014,0-0.021,0c-0.004,0-0.004,0-0.006,0c-0.039-0.004-0.08-0.004-0.128-0.009c-0.002,0-0.004,0-0.004,0c-0.009,0-0.015-0.002-0.022-0.002c-0.002,0-0.007,0-0.011,0c-0.007,0-0.013,0-0.021,0c-0.004-0.002-0.01-0.002-0.014-0.002c-0.006,0-0.013-0.002-0.02-0.002c-0.005,0-0.011,0-0.016-0.002c-0.005,0-0.011,0-0.019,0c-0.01,0-0.02-0.002-0.028-0.004c-0.006,0-0.012,0-0.019,0c-0.008,0-0.018-0.002-0.028-0.002c-0.005,0-0.011-0.002-0.016-0.002c-0.008,0-0.019,0-0.024-0.001c-0.006-0.001-0.013-0.001-0.021-0.001c-0.007-0.002-0.018-0.002-0.026-0.004c-0.005,0-0.013-0.001-0.02-0.001c-0.008-0.001-0.018-0.003-0.026-0.003c-0.007-0.001-0.016-0.001-0.023-0.003c-0.01,0-0.019-0.002-0.027-0.002c-0.007-0.002-0.014-0.002-0.021-0.002c-0.012,0-0.024-0.003-0.035-0.005c-0.007,0-0.014,0-0.02,0c-0.02-0.004-0.037-0.006-0.057-0.006c-0.142-0.019-0.271-0.033-0.378-0.055l-0.187-0.025c0,0-0.47-0.014-0.653-0.316c-0.118-0.197,0.457-0.318,0.457-0.318s0.956-0.193,1.917-0.321c0,0-2.542,0.294-2.777,0.626C49.613,89.737,50.023,89.904,50.023,89.904L50.023,89.904z"/><path style="&st59;" d="M69.986,84.401L69.986,84.401L69.986,84.401z"/><path style="&st59;" d="M69.989,84.399c0.001,0,0.001,0,0.004,0C69.991,84.399,69.99,84.399,69.989,84.399z"/><path style="&st59;" d="M48.839,90.979c-0.007,0-0.015,0.002-0.021,0.002C48.824,90.98,48.831,90.979,48.839,90.979z"/><path style="&st59;" d="M48.727,90.988c-0.009,0-0.017,0.002-0.026,0.002C48.71,90.99,48.718,90.988,48.727,90.988z"/><path style="&st59;" d="M48.637,90.998c-0.009,0-0.019,0.001-0.029,0.003C48.619,90.999,48.628,90.998,48.637,90.998z"/><path style="&st59;" d="M48.55,91.004c-0.009,0-0.018,0.002-0.025,0.004C48.532,91.006,48.54,91.004,48.55,91.004z"/><path style="&st59;" d="M70.139,84.35c0.004,0,0.006-0.002,0.01-0.004C70.145,84.348,70.143,84.35,70.139,84.35z"/><path style="&st59;" d="M70.116,84.359c0.002-0.002,0.004-0.002,0.007-0.002C70.12,84.357,70.118,84.357,70.116,84.359z"/><path style="&st59;" d="M70.193,84.332c0.002,0,0.002-0.002,0.004-0.002C70.195,84.33,70.195,84.332,70.193,84.332z"/><path style="&st59;" d="M70.068,84.374c0.003,0,0.004,0,0.007-0.002C70.072,84.374,70.07,84.374,70.068,84.374z"/><path style="&st59;" d="M70.163,84.342c0.005,0,0.007-0.002,0.011-0.005C70.17,84.34,70.167,84.342,70.163,84.342z"/><path style="&st59;" d="M69.996,84.395c0.002,0,0.002,0,0.004,0C69.998,84.395,69.998,84.395,69.996,84.395z"/><path style="&st59;" d="M70.004,84.395c0.002,0,0.006-0.002,0.008-0.002C70.006,84.395,70.006,84.395,70.004,84.395z"/><path style="&st59;" d="M72.23,81.559c-0.002,0-0.004,0-0.004,0S72.229,81.559,72.23,81.559z"/><path style="&st59;" d="M70.053,84.379c0.002,0,0.002,0,0.004,0C70.053,84.379,70.053,84.379,70.053,84.379z"/><path style="&st59;" d="M70.036,84.385c0.001,0,0.003,0,0.004-0.002C70.039,84.385,70.037,84.385,70.036,84.385z"/><linearGradient id="SVGID_31_" gradientUnits="userSpaceOnUse" x1="414.2451" y1="568.2656" x2="509.0055" y2="545.7273" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EDEDEE"/><stop offset=".4176" stop-color="#FFF"/><stop offset=".6264" stop-color="#F8F9F9"/><stop offset=".9505" stop-color="#B2B4B6"/></linearGradient><path style="&st51;" d="M7.61,68.141c-0.065-0.062-0.112-0.105-0.139-0.131L7.45,68.021L7.61,68.141L7.61,68.141z"/><linearGradient id="SVGID_32_" gradientUnits="userSpaceOnUse" x1="416.6992" y1="578.5645" x2="511.8228" y2="555.9398" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EDEDEE"/><stop offset=".4176" stop-color="#FFF"/><stop offset=".6264" stop-color="#F8F9F9"/><stop offset=".9505" stop-color="#B2B4B6"/></linearGradient><path style="&st62;" d="M90.412,59.954l0.689,0.108c1.976-1.573,3.869-3.571,3.869-3.571s1.258-1.261,1.889-2.356c0.22-0.381,0.281-0.356,0.271-0.177c0.023-0.09,0.103-0.456-0.038-0.714c-0.094-0.176-0.381,0.288-0.83,0.861c0,0-2.013,2.926-5.798,5.816c-3.786,2.891-4.776,3.771-8.083,5.655c0,0-2.309,1.021-3.914,0.669c-1.246-0.271,0-1.547,0.271-2.699c0.271-1.146,0.063-1.58-0.225-1.807c-0.287-0.225-0.91-0.385-2.142-0.109c0,0-4.709,1.264-6.819,3.307c-1.918,1.854,0.478,2.619,1.021,2.875c0,0,0.78,0.338,0.719,0.672c-0.063,0.336-0.496,0.623-0.733,0.783c-0.239,0.16-3.338,1.977-8.324,2.764c-4.039,0.641-3.26,0.255-7.143,0.654c-3.881,0.399-4.952,0.72-8.068,1.453c-3.116,0.734-4.945,1.537-5.352,2.349c-0.336,0.671,0.479,1.103,0.991,1.407c0.511,0.304,1.423,0.781,1.119,1.293c-0.305,0.512-1.631,1.277-4.874,1.391c-3.243,0.114-4.569-0.336-5.16-1.04c-0.548-0.649-0.08-1.323,0.096-1.946c0,0,0.382-0.814,0.16-1.215c-0.224-0.398-0.737-0.494-1.278-0.559c-0.544-0.064-3.245-0.158-5.337-0.271c-2.372-0.127-5.208-0.211-8.611-0.928c0,0-2.237-0.441-3.69-1.262c-0.096-0.055-0.18-0.107-0.25-0.156c-0.11-0.059-0.194-0.122-0.25-0.209c-0.41-0.432-0.047-0.748-0.186-1.168c-0.121-0.359-0.352-0.878-0.896-1.501c-0.176-0.183-0.428-0.437-0.72-0.713c-0.08-0.069-0.165-0.144-0.254-0.214c-1.276-1.037-1.422-1.149-1.964-1.166c-0.542-0.019-0.235,0.895-0.129,1.246c0.041,0.136,0.139,0.328,0.242,0.508c-0.2-0.364-0.336-0.729-0.257-0.915c0.144-0.337,0.309-0.308,0.309-0.308s0.133-0.053,0.595,0.297c0.463,0.35,1.499,1.078,2.012,1.705c0.512,0.625,0.481,1.18,0.481,1.18s-0.103,0.563,0.451,1.17c0.555,0.604,1.733,1.714,5.859,2.349c0.021,0.005,0.041,0.005,0.06,0.009l0.193-0.549l0.568,0.663c0.006,0,0.01,0.001,0.016,0.002c3.592,0.519,5.544,0.563,5.544,0.563s4.709,0.164,5.982,0.164c1.271,0,1.035,0.664,1.035,0.664s-0.072,0.361-0.225,0.647c-0.153,0.288-0.524,1.365-0.144,1.94c0,0,0.585,1.426,4.382,1.527c0,0,3.324,0.267,5.643-0.688c2.317-0.954,0.224-2.277,0.224-2.277s-0.794-0.483-1.129-0.737c-0.308-0.233-0.184-0.48-0.122-0.646c0.061-0.163,0.297-0.355,0.564-0.492c0.265-0.134,1.241-0.652,5.365-1.722c4.124-1.067,6.587-1.183,6.587-1.183s0.021-0.004,0.062-0.006l0.334-0.656l0.845,0.559c0.732-0.061,1.686-0.129,2.537-0.17c1.691-0.083,4.341-0.475,5.879-0.811c1.539-0.342,3.869-1.059,5.591-1.951c1.724-0.891,1.808-1.519,1.808-1.519s0.328-0.472-0.391-0.995c-0.719-0.521-1.037-0.38-1.672-1.024c-0.638-0.646,0.553-1.619,0.553-1.619s0.615-0.865,4.021-2.177c3.408-1.313,3.98-0.873,4.156-0.728c0.175,0.142,0.195,0.613,0.123,0.933c-0.072,0.316-0.494,1.455-0.721,2.055c-0.227,0.592-0.316,1.402,0.604,1.6c0.924,0.193,2.215-0.009,3.427-0.443c2.893-1.033,3.757-2.295,8.535-5.764c0.011-0.01,0.021-0.016,0.029-0.023L90.412,59.954L90.412,59.954z"/><linearGradient id="SVGID_33_" gradientUnits="userSpaceOnUse" x1="415.4736" y1="573.4199" x2="510.5869" y2="550.7977" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EDEDEE"/><stop offset=".4176" stop-color="#FFF"/><stop offset=".6264" stop-color="#F8F9F9"/><stop offset=".9505" stop-color="#B2B4B6"/></linearGradient><path style="&st52;" d="M100.895,47.596c-0.635,1.186-1.164,2.608-1.443,3.5c-0.045,0.213-0.061,0.33-0.061,0.33s-0.119,0.654-0.054,1.036c0.028,0.161,0.069,0.279,0.106,0.375c0.021,0.052,0.039,0.095,0.055,0.134c0.02,0.045,0.031,0.082,0.033,0.111c0.007,0.082-0.044,0.614-0.27,1.23l0,0c0,0,0,0,0,0.002c-0.063,0.176-0.143,0.359-0.24,0.539c-0.024,0.05-0.053,0.095-0.074,0.139c-0.458,0.814-1.098,1.457-1.604,1.532c-0.324,0.049-0.484-0.117-0.557-0.386c0.014,0.369,0.086,0.738,0.289,0.963c0.406,0.441,1.563-0.795,1.563-0.795s0.688-0.789,0.965-2.062c0.406-1.875,0.187-2.248,0.187-2.248s-0.247-0.389-0.093-0.853c0.152-0.461,1.156-3.047,1.979-4.01l0.502-0.562c0-0.009,0.002-0.02,0.002-0.029l-0.211-0.521c-0.129,0.13-0.259,0.284-0.385,0.454C101.405,46.763,101.178,47.129,100.895,47.596L100.895,47.596z"/><linearGradient id="SVGID_34_" gradientUnits="userSpaceOnUse" x1="414.7754" y1="570.4785" x2="509.8697" y2="547.861" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EDEDEE"/><stop offset=".4176" stop-color="#FFF"/><stop offset=".6264" stop-color="#F8F9F9"/><stop offset=".9505" stop-color="#B2B4B6"/></linearGradient><path style="&st53;" d="M10.564,70.807L10.564,70.807c-0.146-0.092-0.315-0.229-0.469-0.356c-0.133-0.112-0.641-0.585-1.18-1.086c-0.212-0.194-0.411-0.382-0.589-0.55c-0.277-0.262-0.524-0.493-0.688-0.646l0.107,0.358c0.017,0.028,0.034,0.06,0.052,0.089c0.183,0.29,0.854,1.264,2.153,2.277c1.549,1.213,1.559,0.729,1.559,0.729s0.062-0.4-0.296-0.84c-0.063-0.076-0.131-0.167-0.202-0.27v0.002C11.011,70.516,12.023,71.998,10.564,70.807z"/><linearGradient id="SVGID_35_" gradientUnits="userSpaceOnUse" x1="414.915" y1="571.0664" x2="510.04" y2="548.4415" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EDEDEE"/><stop offset=".4176" stop-color="#FFF"/><stop offset=".6264" stop-color="#F8F9F9"/><stop offset=".9505" stop-color="#B2B4B6"/></linearGradient><path style="&st54;" d="M10.678,69.98c0.103,0.186,0.219,0.371,0.333,0.533C11,70.501,10.833,70.253,10.678,69.98z"/><linearGradient id="SVGID_36_" gradientUnits="userSpaceOnUse" x1="416.1035" y1="576.0654" x2="511.2286" y2="553.4405" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#EDEDEE"/><stop offset=".4176" stop-color="#FFF"/><stop offset=".6264" stop-color="#F8F9F9"/><stop offset=".9505" stop-color="#B2B4B6"/></linearGradient><path style="&st55;" d="M96.887,55.023c0,0,0.227-0.76,0.243-1.066c-0.003,0.014-0.005,0.021-0.005,0.021s-0.513,1.443-0.333,2.16C96.771,55.579,96.887,55.023,96.887,55.023z"/><path style="&st34;" d="M63.301,4.417l0.728,0.072c1.426-0.402,2.643-0.772,2.643-0.772s1.265-0.41,1.901-0.637c0.635-0.226,1.09-0.313,1.654-0.409c0.565-0.096,1.311-0.14,1.709-0.131c0.4,0.007,0.531,0.122,0.531,0.122s0.166,0.131,0.244,0.27c0.077,0.138,0.74,1.891,2.973,2.005c2.233,0.112,2.263-1.096,2.065-1.464c-0.226-0.427-0.896-0.863-0.896-0.863s-0.899-0.575-1.092-0.847c-0.191-0.27,0.034-0.357,0.104-0.375c0.065-0.017,2.435-0.497,2.729-0.609l0.021-0.021l-0.562-0.171c0,0-0.119,0.134-0.789,0.313c-0.67,0.179-1.235,0.246-1.742,0.313c-0.506,0.066-0.506,0.239-0.506,0.239l-0.086,0.136c-0.025,0.075-0.067,0.321,0.375,0.642c0.528,0.387,1.172,0.75,1.438,1.04s0.586,0.783,0.012,1.137C76.48,4.576,76.27,4.64,75.977,4.671c0.002,0.008,0,0.012,0,0.012c-0.248,0.021-0.457,0.03-0.638,0.03c-0.049,0.002-0.102,0.006-0.155,0.009l-0.017-0.013c-0.506-0.024-0.746-0.142-1.067-0.302c-0.442-0.223-0.758-0.73-0.92-1.087s-0.521-0.662-0.521-0.662c-0.588-0.336-1.695-0.343-2.813-0.15c-1.115,0.193-2.656,0.707-2.925,0.812c-0.268,0.104-1.616,0.551-2.307,0.73c-0.693,0.178-1.222,0.357-1.646,0.47c-0.427,0.111-3.432,1.005-4.556,1.339c-1.126,0.334-1.849,0.46-1.849,0.46c-1.688,0.172-2.193-0.134-2.193-0.134c-0.296-0.124-0.261-0.526-0.261-0.526l0.009-1.147c0,0-0.027-0.433-0.357-0.611c-0.328-0.179-0.779-0.252-1.593-0.29c-0.811-0.038-1.683,0.044-2.093,0.134c-0.408,0.09-1.189,0.313-1.764,0.952c-0.572,0.641-0.481,1.139-0.481,1.139s0.004,0.079,0.01,0.201c0.154,0.245,0.416,0.524,0.862,0.739c1.015,0.485-1.137,1.342-1.137,1.342l0,0c-0.479,0.208-1.191,0.478-2.208,0.777c-2.21,0.647-3.684,0.774-3.684,0.774l0.679,0.254c0,0,5.468-1.016,7.148-2.616c0,0,0.625-0.293,0.021-0.88c-0.606-0.585-0.898-0.761-0.898-0.761s-0.41-0.223,0.02-0.772c0.428-0.546,0.922-0.794,1.352-0.933c0.428-0.135,1.754-0.249,2.925-0.093c0,0,0.491,0.042,0.457,0.407c-0.032,0.365-0.087,0.873-0.077,1.028c0.01,0.157,0.025,0.515,0.399,0.845c0.379,0.332,1.098,0.453,1.098,0.453s1.257,0.228,2.845-0.218c1.586-0.444,3.65-1.141,5.438-1.629L63.301,4.417L63.301,4.417z"/><linearGradient id="SVGID_37_" gradientUnits="userSpaceOnUse" x1="412.6152" y1="535.3994" x2="501.5865" y2="514.8846" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#FFF"/><stop offset=".6538" stop-color="#FFF"/><stop offset="1" stop-color="#CBCCCE"/></linearGradient><path style="&st56;" d="M91.596,12.992l0.271,0.486c-0.021,0.01-0.034,0.014-0.034,0.014c-1.114,0.515-3.999,1.32-4.271,1.398c-0.271,0.08-0.166,0.234-0.166,0.234c0.029,0.078,0.988,1.106,0.988,1.106c1.178,1.249,0.494,2.296,0.494,2.296s-0.852,1.347-2.844,1.12c-1.993-0.227-2.618-1.767-2.729-2.049c-0.111-0.282-0.197-0.768-0.22-1.095c-0.022-0.33-0.272-0.32-0.272-0.32c-1.069-0.03-2.887,1.089-2.887,1.089c-0.824,0.47-1.682,1.147-3.479,1.958c-0.879,0.396-1.694,0.716-2.287,0.936l-0.967-0.173l0.091,0.482c-0.042,0.013-0.063,0.021-0.063,0.021s-2.268,0.822-4.529,1.553c-2.268,0.732-3.65,0.8-3.65,0.8s-1.336,0.12-2.266-0.266c-0.93-0.386-0.959-0.94-0.939-1.415c0.021-0.476,0.483-1.404,0.623-1.958c0.139-0.555-0.683-0.644-0.683-0.644s-1.958-0.236-3.65,0.296c-1.69,0.535-2.54,1.159-2.54,1.159c-0.91,0.512-0.863,0.957-0.863,0.957s-0.012,0.467,0.551,0.869s1.072,0.505,1.736,0.654c0.668,0.149,0.791,0.311,0.791,0.311c1.08,0.894,0.416,1.785,0.047,2.434c-0.631,1.113-3.674,1.653-3.674,1.653c-3.276,0.758-5.12,1.08-7.827,1.452l-0.876-0.46l-0.276,0.615c-7.089,0.936-10.065,1.877-11.065,2.135c-1,0.257-1.261,0.784-1.369,0.904c-0.108,0.12,0.079,0.171,0.079,0.171c0.427,0.137,0.647,0.442,0.647,0.442s1.399,1.697-0.012,3.108c-1.359,1.36-2.785,1.674-2.785,1.674s-2.177,0.737-4.077,0.341c-1.899-0.399-2.439-1.889-2.416-2.395c0.024-0.505,0.176-1.075,0.694-1.661c0.517-0.585,0.654-0.667,0.654-0.667s0.358-0.279,0.421-0.415c0.079-0.172-0.404-0.233-0.404-0.233c-1.034-0.13-3.496-0.097-5.822,0.131c-1.439,0.14-2.769,0.374-3.578,0.518l-0.223-0.48l-0.543,0.625l-3.12,0.504c-1.514,0.222-2.576-0.028-2.576-0.028s-1.331-0.397-1.479-1.252c-0.147-0.852,0.359-1.87,0.49-2.177c0.13-0.307,0.5-0.934,0.5-0.934s0.068-0.13,0.068-0.34c0-0.211-0.233-0.536-0.233-0.536s-0.205-0.396-0.886-0.38c-0.682,0.018-0.866,0.131-1.144,0.364c-0.044,0.038-0.079,0.081-0.108,0.127c0.021-0.064,0.045-0.117,0.073-0.158c0.21-0.309,0.65-0.668,1.401-0.7c0.748-0.034,1.041,0.228,1.041,0.228c0.719,0.82,0.115,1.845-0.351,2.76c-0.057,0.095-0.155,0.271-0.229,0.483c-0.032,0.076-0.062,0.153-0.087,0.227c-0.358,1.06,0.292,1.565,0.668,1.661c0.376,0.097,1.141,0.57,4.269-0.031c3.13-0.603,3.587-0.731,3.587-0.731s6.145-1.087,8.96-0.425l0.023,0.004c0,0,1.297,0.367,0.331,1.334c-0.966,0.966-1.729,1.617-1.504,2.377c0.223,0.762,1.267,1.903,3.646,1.603c0,0,0.842-0.113,1.105-0.165c1.733-0.336,2.899-1.268,2.899-1.268s0.972-0.721,0.782-1.631c-0.187-0.908-1.017-1.189-1.017-1.189s-0.659-0.424-0.141-1.237c0,0,0.141-0.69,2.553-1.317c2.412-0.626,6.813-1.518,10.555-1.989c3.49-0.408,9.652-1.575,10.89-2.08c1.235-0.508,1.497-1.4,1.521-1.708c0.024-0.31,0.072-0.83-1.14-1.09c-1.213-0.259-1.758-0.655-1.931-0.79c-0.172-0.138-0.545-0.483-0.545-1.275c0-0.791,1.607-1.745,3.392-2.35c1.78-0.606,3.927-0.34,3.927-0.34c1.948,0.167,0.936,1.963,0.936,1.963c-0.074,0.322-0.946,1.785,0.5,2.169c1.541,0.409,4.175-0.347,5.188-0.669c0.829-0.261,3.141-1.074,4.688-1.62c0.352-0.122,0.66-0.231,0.908-0.318c1.656-0.577,3.019-1.219,3.785-1.681c0.771-0.462,2.144-1.297,2.144-1.297s1.351-0.744,1.799-0.808c0.451-0.064,1.619-0.346,1.771,0.771c0.155,1.115,0.631,1.899,1.4,2.271c0.771,0.371,2.064,0.538,3.246-0.231c1.182-0.771,0.359-1.901,0.359-1.901c-0.021-0.028-0.039-0.057-0.062-0.085c-0.151-0.27-0.369-0.518-0.487-0.646c-0.388-0.47-0.736-0.822-0.736-0.822c-0.295-0.436,0.053-0.692,0.425-0.834c0.373-0.141,2.351-0.758,2.351-0.758c1.155-0.383,1.592-0.551,2.053-0.988c0.445-0.419-0.189-1.34-0.239-1.412l0.004-0.002l0.608,0.256c0.136,0.182,0.27,0.362,0.4,0.547l-0.007,0.005c0,0,0.226,0.527,0.054,0.799c-0.095,0.149-0.343,0.293-0.545,0.395L91.596,12.992L91.596,12.992z"/><linearGradient id="SVGID_38_" gradientUnits="userSpaceOnUse" x1="390.042" y1="485.6797" x2="390.042" y2="485.6797" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#FFF"/><stop offset=".6538" stop-color="#FFF"/><stop offset="1" stop-color="#CBCCCE"/></linearGradient><path style="&st57;" d="M-16.122-14.641"/><path style="&st34;" d="M57.455,92.28c-0.034-0.042-0.042-0.034-0.012-0.063c0.021-0.021,0.086-0.082,0.115-0.137c0,0-1.17-0.063-2.141,0.077c-0.962,0.137-1.933,0.335-1.933,0.335l0.301,0.146c0,0,0.127-0.055,1.047-0.183c0.921-0.128,1.267-0.128,1.267-0.128s0.808-0.063,0.969-0.063c0.162,0,0.061,0.104,0.061,0.104s-0.078,0.136,0.366,0.124c0,0,0.663-0.027,1.313-0.188C58.809,92.309,57.678,92.544,57.455,92.28z"/><path style="&st34;" d="M54.469,92.691c0,0,0.146,0.266-2.923,0.394c0,0,1.788,0.052,3.31-0.198C55.963,92.707,54.469,92.691,54.469,92.691L54.469,92.691z"/><path style="&st34;" d="M13.114,9.856c0,0-0.005,0.096,0.019,0.131c0.024,0.034,0.107,0.112,0.107,0.112s0.328-0.5,0.194-0.438c0,0-0.119,0.187-0.164,0.23c0,0-0.029,0.04-0.088,0.077C13.123,10.006,13.117,9.991,13.114,9.856L13.114,9.856z"/><path style="&st34;" d="M10.595,12.501c0,0-0.388,0.46,0,0.52l0.528-0.527c0,0,0.139-0.234,0.139-0.398C11.263,12.095,10.752,12.343,10.595,12.501L10.595,12.501z"/><path style="&st12;" d="M-16.122-14.641"/><path style="&st31;" d="M21.093,23.707c1.227,0.146,1.499-0.132,1.527-0.172c0.294-0.003,1.475-0.034,2.865-0.207c1.685-0.21,3.564-0.891,3.564-0.891s1.554-0.568,2.096-1.18l0.016-0.002c0,0-0.693-0.6-1.057-1.122c0,0-0.286-0.557,0.027-1.035c0.316-0.479,0.836-1.008,2.344-1.643c1.506-0.636,2.356-0.514,2.356-0.514s0.594-0.006,1.007,0.45c0.415,0.458,0.649,1.006,0.649,1.006s0.029,0.38-0.115,0.63c-0.141,0.251-0.155,0.277-0.155,0.277s0.049,0.017,0.378-0.007c0.329-0.021,1.165-0.142,2.67-0.506c1.508-0.363,3.407-0.972,3.407-0.972s4.9-1.578,5.407-1.714c0.507-0.135,1.357-0.436,1.357-0.436l0.027,0.059c0,0,0.405,0.663,0.392,1.269V16.94c0,0-0.021,0.301-0.698,0.818c-0.674,0.517-1.226,0.479-1.678,0.442c-0.452-0.039-0.665-0.071-0.794-0.045l-0.72,0.04c-0.787,0.111-1.224,0.407-1.224,0.407c-1.804,1.065,0.731,9.287,0.731,9.287c-3.742,0.47-8.143,1.363-10.555,1.989c-2.412,0.627-2.553,1.317-2.553,1.317c-0.519,0.813,0.141,1.236,0.141,1.236s0.829,0.283,1.017,1.19c0.19,0.91-0.783,1.629-0.783,1.629s-1.159,0.97-2.898,1.268c-1.738,0.298-2.396,0.35-3.429-0.47c-0.91-0.721-0.297-1.864,0.312-2.301c0.612-0.438,0.909-0.91,0.988-1.113c0.079-0.203,0.032-0.376,0.032-0.376l-0.58-0.534c-2.005-1.33-9.884,0.063-9.884,0.063c-0.213-1.169-0.362-1.171-0.282-3.117c0.051-1.244,0.291-1.752,0.291-1.752l0.058-0.164c0,0,0.448-1.443,1.141-2.44c0,0,0.602-0.172,1.364-0.349C20.616,23.793,21.093,23.707,21.093,23.707L21.093,23.707z"/><linearGradient id="SVGID_39_" gradientUnits="userSpaceOnUse" x1="231.2324" y1="-407.8711" x2="263.6191" y2="-407.8711" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#696969"/><stop offset=".3702" stop-color="#2E2E2E"/><stop offset=".4554" stop-color="#424242"/><stop offset=".6014" stop-color="#303030"/><stop offset=".6947" stop-color="#4A4A4A"/><stop offset="1" stop-color="#666666"/></linearGradient><path style="&st26;" d="M49.855,16.94c0,0-4.085,1.326-3.891,1.254c0,0-0.39,0.075-0.686,0.161c-0.294,0.086-0.539,0.247-0.539,0.247s-3.288,1.222-6.438,1.848c-3.148,0.627-2.977-0.361-2.708-0.83c0.232-0.409,0.829-1.112-0.188-1.254c-1.019-0.14-1.788,0.251-2.21,0.439c-0.422,0.189-3.162,1.362-1.251,2.254c0,0,1.423,0.642-0.377,1.755c0,0-1.816,1.16-5.355,1.77c0,0-0.565,0.063-1.88,0.111c-1.316,0.046-2.558,0.213-4.12,0.658c-1.378,0.391-1.992,0.579-2.744,1.065l0.194-0.501l0.2-0.462c1.069-0.533,3.719-1.288,5.717-1.378c1.997-0.089,2.908-0.16,4.721-0.624c2.134-0.546,2.702-1.019,2.93-1.163c0.194-0.123,0.771-0.479,0.493-0.633c-0.359-0.199-0.895-0.729-0.895-0.729c-0.217-0.256-0.39-0.373-0.158-1.046c0.356-1.029,2.196-1.644,2.196-1.644s1.028-0.534,2.334-0.514c1.305,0.021,1.287,0.752,1.287,0.752s0.062,0.34-0.268,0.827c0,0-0.503,0.579-0.049,0.656c0.454,0.081,1.622,0.179,5.48-1.028c3.859-1.207,8.085-2.611,8.085-2.611S49.855,16.66,49.855,16.94L49.855,16.94z"/><linearGradient id="SVGID_40_" gradientUnits="userSpaceOnUse" x1="231.623" y1="-407.063" x2="263.4941" y2="-407.063" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#525252"/><stop offset=".1856" stop-color="#333333"/><stop offset=".354" stop-color="#AEAEAE"/><stop offset=".4199" stop-color="#ADADAD"/><stop offset=".4276" stop-color="#9D9D9D"/><stop offset=".4433" stop-color="#818181"/><stop offset=".4611" stop-color="#6A6A6A"/><stop offset=".4814" stop-color="#585858"/><stop offset=".506" stop-color="#4C4C4C"/><stop offset=".539" stop-color="#444444"/><stop offset=".6166" stop-color="#424242"/><stop offset=".6684" stop-color="#454545"/><stop offset="1" stop-color="#BDBDBD"/></linearGradient><path style="&st58;" d="M31.145,21.257c-0.541,0.612-2.096,1.18-2.096,1.18s-1.88,0.68-3.564,0.891c-1.608,0.201-2.777,0.209-2.777,0.209l-0.082-0.002c-0.175,0.145-0.483,0.188-0.728,0.21c-0.244,0.023-0.806-0.039-0.806-0.039s-2.156,0.432-2.603,0.616c0,0-0.253,0.392-0.331,0.539c-0.08,0.146-0.299,0.594-0.299,0.594c1.069-0.534,3.718-1.289,5.717-1.379c1.997-0.089,2.908-0.159,4.721-0.624c2.134-0.546,2.702-1.019,2.929-1.163c0.195-0.123,0.771-0.479,0.493-0.633c-0.358-0.199-0.894-0.729-0.894-0.729c-0.217-0.256-0.391-0.373-0.158-1.046c0.356-1.029,2.196-1.644,2.196-1.644s1.028-0.533,2.333-0.514c1.306,0.021,1.287,0.753,1.287,0.753s0.062,0.34-0.269,0.826c0,0-0.503,0.579-0.049,0.657c0.455,0.08,1.622,0.178,5.48-1.028c3.858-1.208,8.085-2.612,8.085-2.612c-0.098-0.29-0.296-0.652-0.296-0.652s-0.85,0.301-1.358,0.436c-0.506,0.136-5.407,1.714-5.407,1.714s-1.9,0.608-3.407,0.972c-1.506,0.364-2.342,0.485-2.671,0.508c-0.329,0.021-0.378,0.006-0.378,0.006s0.013-0.027,0.156-0.279c0.144-0.248,0.115-0.629,0.115-0.629s-0.235-0.548-0.649-1.006c-0.414-0.457-1.007-0.45-1.007-0.45s-0.849-0.121-2.355,0.514c-1.508,0.636-2.029,1.164-2.346,1.643c-0.312,0.478-0.026,1.035-0.026,1.035c0.365,0.521,1.057,1.122,1.057,1.122"/><linearGradient id="SVGID_41_" gradientUnits="userSpaceOnUse" x1="236.917" y1="-417.333" x2="235.8882" y2="-410.5272" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)"><stop offset="0" stop-color="#969696"/><stop offset="1" stop-color="#000"/></linearGradient><path style="&st24;" d="M21.606,31.241c0,0-0.064-0.328,0.172-0.939c0.234-0.611,0.908-0.595,1.362-0.503c0.455,0.095,0.846,0.298,1.472-0.124c0.627-0.423,0.47-1.583,0.046-2.852c-0.423-1.267-0.328-2.128-0.328-2.128l-0.608-0.649l-0.237,0.696c0.047,1.316,0.657,3.226,0.829,3.759c0.173,0.533,0.297,0.8-0.735,0.517c-1.034-0.282-1.519,0.125-1.519,0.125c-1.332,0.862-1.082,2.161-1.082,2.161L21.606,31.241z"/><path style="&st60;" d="M27.498,36.633c-0.264-1.763-0.917-2.749-0.917-2.749c-0.25,0.188-0.513,0.693-0.513,0.693s0.179,0.208,0.471,1.568c0,0,0.141,0.106,0.438,0.279C27.273,36.597,27.498,36.633,27.498,36.633z"/><path style="&st60;" d="M33.152,32.881c0,0-0.78,0.907-0.378,2.336c0,0,0.454-0.379,0.585-0.68c0,0-0.145-0.458,0.138-1.017C33.5,33.52,33.37,33.1,33.152,32.881L33.152,32.881z"/><linearGradient id="SVGID_42_" gradientUnits="userSpaceOnUse" x1="428.7803" y1="532.0527" x2="429.5303" y2="524.4692" gradientTransform="matrix(1 0 0 1 -406.1641 -500.3203)"><stop offset="0" stop-color="#333333"/><stop offset=".431" stop-color="#000"/><stop offset="1" stop-color="#2E2E2E"/></linearGradient><path style="&st3;" d="M21.2,31.253c0.017-1.299,0.471-1.492,0.905-1.818c0.436-0.328,1.326-0.024,1.326-0.024s0.678,0.218,1.046-0.1c0.369-0.319-0.017-1.467-0.217-2.123c-0.202-0.653-0.41-1.599-0.445-2.262c-0.025-0.489-0.091-0.707-0.125-0.789l-0.205,0.604c0.047,1.316,0.657,3.226,0.829,3.759c0.173,0.533,0.297,0.8-0.735,0.517c-1.035-0.282-1.519,0.125-1.519,0.125c-1.332,0.862-1.082,2.162-1.082,2.162l0.259-0.027L21.2,31.253L21.2,31.253z"/><path style="&st21;" d="M26.239,34.29c0.045,0.06,0.421,0.597,0.736,2.113l0.005,0.025c0.294,0.17,0.519,0.205,0.519,0.205c-0.264-1.763-0.917-2.749-0.917-2.749C26.46,33.977,26.336,34.143,26.239,34.29L26.239,34.29z"/><path style="&st21;" d="M33.152,32.881c0,0-0.78,0.907-0.378,2.336c0,0,0.125-0.104,0.262-0.248l0.021-0.051c-0.304-1.033,0.283-1.763,0.283-1.763l0.004-0.003C33.291,33.053,33.225,32.957,33.152,32.881z"/><path style="&st10;" d="M17.159,8.189h0.117c-0.16,0.481-0.789,1.141-1.068,1.583c-0.156,0.248-0.252,0.572-0.474,0.751c0.038,0.043-0.003,0.003,0.04,0.04c0.088,0.052,0.813-0.139,0.95-0.236c0.082,0.015,0.076,0.011,0.12,0.039c0.042,0.07-0.481,0.991-0.595,1.109v0.04c0.196-0.023,0.502-0.056,0.634-0.16c0.383-0.299,0.47-0.937,0.75-1.346c-0.013-0.066-0.026-0.132-0.04-0.196c-0.222-0.04-0.681,0.02-0.87,0.157h-0.039c0.091-0.473,0.868-1.346,1.146-1.741c0.454-0.647,0.881-1.269,1.345-1.9c0.243-0.331,0.585-0.622,0.831-0.949c0.276-0.367,0.569-0.85,0.949-1.107V4.194h-0.158c-0.186,0.135-0.675,0.218-0.908,0.354c0.032,0.135,0.019,0.101,0.118,0.158c-0.139,0.386-0.598,0.673-0.832,0.991c-0.371,0.5-0.784,0.968-1.147,1.464c-0.123,0.164-0.205,0.421-0.356,0.553c-0.237,0.208-0.913,0.185-1.185,0.396h-0.08c0.056-0.332,0.907-1.392,1.147-1.622v-0.04c-0.408,0.057-0.724,0.273-0.989,0.473c0.044,0.091,0.037,0.073,0.12,0.12c-0.145,0.238-0.361,0.415-0.515,0.633c-0.197,0.275-0.305,0.602-0.514,0.871c0.014,0.04,0.028,0.077,0.04,0.118C15.948,8.641,17.001,8.307,17.159,8.189L17.159,8.189z M51.936,13.534c0.199,0.066,0.396,0.131,0.596,0.197c0.159,0.002,0.327-0.002,0.432-0.04c-0.009-0.654-0.364-0.913-0.593-1.345c-0.113-0.22-0.175-0.523-0.355-0.673c0.069-0.242,0.727-0.308,0.988-0.396c0.643-0.211,1.371-0.422,2.02-0.633c0.305-0.099,0.664-0.077,0.91-0.236c0.146,0.015,0.22,0.029,0.277,0.118c0.143,0.212,0.26,1.667,0.156,2.097c-0.398,1.663-0.896,2.963-1.938,3.958v0.039c0.385-0.062,0.568-0.436,0.83-0.632c1.051-0.794,1.762-1.972,2.137-3.444c0.221-0.865-0.14-1.713,0.199-2.452h-0.039c-0.074-0.188-1.082-0.553-1.388-0.555c-0.164,0.177-0.399,0.416-0.634,0.515c-0.357,0.152-0.838,0.109-1.146,0.315c-0.287-0.024-0.506-0.57-0.315-0.791c-0.011-0.09-0.009-0.112-0.04-0.158c-0.239-0.191-0.85-0.171-1.268-0.158c-0.133,0.125-0.252,0.15-0.314,0.358h-0.039c-0.021,0.076,0.02,0.05,0.039,0.078c0.025,0.016,0.163-0.007,0.236,0.04c0.449,0.047,0.438,0.566,0.675,0.831c-0.027,0.069-0.011,0.04-0.042,0.08c-0.155,0.123-1.301,0.453-1.543,0.515c-0.185,0.046-0.414-0.068-0.553-0.081c-0.336-0.028-0.633,0.16-0.831,0.277c0.107,0.157,0.434,0.118,0.554,0.276C51.368,12.193,51.556,12.913,51.936,13.534L51.936,13.534z M59.807,12.977c0.187,0.093,0.187,0.332,0.278,0.514c0.185,0.371,0.437,0.82,0.554,1.228v0.316c0.092,0.252,0.396,0.284,0.596,0.435c0.156-0.021,0.214-0.061,0.314-0.118c-0.066-0.753-0.525-1.378-0.791-1.979c-0.08-0.188-0.207-0.452-0.236-0.633c-0.021-0.109,0.063-0.169,0-0.276c-0.051-0.123-0.072-0.085-0.156-0.159c-0.059-0.04-0.031-0.016,0-0.078c0.068-0.144,0.213-0.287,0.275-0.436c0.133-0.313,0.127-0.576,0.396-0.751c-0.04-0.41-0.639-0.457-1.107-0.435c-0.057,0.042-0.156,0.064-0.24,0.077c0.05,0.103,0.082,0.124,0.199,0.157c0.113,1.161-0.699,2.225-1.229,2.928c-0.208,0.279-0.556,0.456-0.75,0.754h-0.04v0.038C58.395,14.473,59.54,13.383,59.807,12.977L59.807,12.977z M12.407,22.83c-0.081,0.017-0.076,0.009-0.117,0.039c-0.288,0.148-0.773,1.426-1.346,1.069c-0.292,0.002-0.319-0.055-0.476-0.16c0.02-0.376,0.659-1.063,0.913-1.226c0.031-0.604,0.187-1.252,0.118-1.819c-0.041-0.014-0.08-0.028-0.118-0.039c-0.14-0.046-0.25,0.168-0.357,0.276c-0.29,0.291-0.648,0.597-0.871,0.949c-0.337-0.003-1.414-0.013-1.623,0.119H8.411c0.099-0.256,0.86-1.096,0.633-1.464c-0.013-0.041-0.025-0.08-0.04-0.12c-0.722,0.002-1.592,1.287-1.82,1.82c-0.115,0.266-0.115,0.573-0.276,0.791v0.04c0.54-0.066,1.082-0.133,1.622-0.199c0.205-0.044,0.487,0.052,0.633-0.039h0.554c0.092-0.118,0.184-0.238,0.277-0.356c0.33-0.349,0.768-0.702,1.028-1.106h0.119v0.551c-0.303,0.273-0.773,0.695-0.91,1.108v0.316c-0.203,0.88,0.223,1.329,0.99,1.267c0.5-0.466,1.324-0.848,1.226-1.779C12.405,22.833,12.444,22.873,12.407,22.83L12.407,22.83z M7.819,22.118H7.58c0.109-0.436,0.537-0.935,1.069-0.95v0.197c-0.185,0.239-0.369,0.475-0.554,0.713C7.982,22.076,7.88,22.076,7.819,22.118z M93.044,22.315c-0.164-0.405-0.294-0.722-0.475-1.068c-0.3-0.574-0.613-1.414-1.464-1.425c-0.211,0.179-0.435,0.322-0.555,0.593c-0.777,1.762,0.819,3.747,1.543,4.71c0.256,0.339,0.557,0.712,0.948,0.908c-0.091,1.376-1.269,1.813-2.53,1.267c-0.899-0.386-1.617-1.237-2.179-1.979c-0.188-0.249-0.481-0.457-0.672-0.713c-0.177-0.239-0.304-0.507-0.515-0.713v-0.039h-0.078c0.107,0.426,0.354,0.815,0.514,1.188c0.669,1.538,1.52,2.614,2.811,3.521c0.608,0.428,1.621,1.104,2.494,0.475C94.412,27.942,93.669,23.851,93.044,22.315L93.044,22.315z M92.928,24.216c-0.104,0.1-0.539-0.419-0.635-0.515c-0.441-0.443-1.329-1.221-0.83-1.979h0.197c0.388,0.403,0.746,0.788,0.99,1.344c0.129,0.299,0.152,0.805,0.313,1.069C92.941,24.205,92.958,24.175,92.928,24.216L92.928,24.216z M66.693,32.128v-0.395c0.179-0.801,0.137-1.765,0.314-2.572c0.241-1.088-0.101-2.148,0.99-2.414c0.021-0.106,0.057-0.148,0-0.238c-0.025-0.067-0.009-0.039-0.04-0.079c-0.043-0.031-0.038-0.024-0.116-0.039c-0.305,0.222-1.131,0.373-1.543,0.474c-0.313,0.076-0.639,0.01-0.871,0.158c-0.039,0.013-0.078,0.027-0.119,0.04c0.014,0.079,0.025,0.159,0.041,0.237c0.451,0.147,0.867-0.031,1.067,0.356c0.13,0.252,0.112,1.157,0.039,1.504c-0.251,1.163-0.146,2.491-0.396,3.64c-0.086,0.397,0.022,1.171-0.157,1.463v0.08c-0.241-0.115-0.397-0.426-0.554-0.633c-0.354-0.467-0.875-0.84-1.229-1.305c-0.213-0.281-0.437-0.617-0.712-0.833c0.037-0.761,0.259-1.56,0.438-2.254c0.131-0.522,0.135-1.005,0.395-1.386c0.148-0.217,0.505-0.355,0.751-0.475c-0.002-0.1-0.004-0.146-0.04-0.198c-0.014-0.04-0.023-0.079-0.037-0.119c-0.543,0.081-1.003,0.341-1.505,0.475c-0.454,0.123-0.911,0.092-1.269,0.276c0.012,0.091,0.01,0.112,0.041,0.158c0.014,0.039,0.024,0.08,0.039,0.118c1.391-0.078,1.18,0.678,0.912,1.742c-0.084,0.326-0.029,0.775-0.199,1.028v0.079h-0.039c-0.285-0.433-0.713-0.852-1.067-1.227c-0.146-0.132-0.291-0.264-0.435-0.395c-0.104-0.137-0.16-0.312-0.278-0.436c0.024-0.437,0.38-0.549,0.713-0.672c-0.015-0.183-0.052-0.206-0.118-0.317c-1.031,0.151-1.927,0.73-3.086,0.791v0.041h-0.04c0.004,0.1,0.004,0.146,0.04,0.197v0.079c0.227,0.039,0.564-0.054,0.831,0.04c0.427,0.15,0.81,0.648,1.067,0.99c0.388,0.513,0.996,0.949,1.384,1.463c0.204,0.274,0.434,0.634,0.713,0.832c-0.038,0.696-0.229,1.428-0.396,2.058c-0.086,0.323-0.035,0.735-0.197,0.988c-0.025,0.069-0.01,0.039-0.041,0.08c-0.377-0.718-1.104-1.265-1.582-1.9c-0.918-1.22-1.938-2.319-2.889-3.521c0-0.167,0.01-0.268,0.08-0.356c0.073-0.229,0.359-0.443,0.633-0.476c0.015-0.12,0.033-0.135-0.039-0.238c-0.016-0.038-0.026-0.077-0.041-0.118c-0.803,0.123-1.521,0.497-2.293,0.714c-0.401,0.112-0.928,0.057-1.229,0.276c-0.04,0.013-0.08,0.026-0.117,0.04c0.021,0.152,0.061,0.176,0.117,0.277c0.314-0.005,0.646-0.092,0.949,0c0.793,0.241,1.361,1.137,1.818,1.742c0.201,0.266,0.513,0.483,0.713,0.751c0.849,1.129,1.808,2.146,2.65,3.285c0.328,0.442,0.771,0.825,1.066,1.304c0.179-0.004,0.216-0.025,0.316-0.079c0.213-0.929,0.332-1.866,0.596-2.81c0.119-0.432,0.269-0.942,0.314-1.424c0.327,0.117,0.592,0.607,0.793,0.871c0.618,0.821,1.491,1.502,2.057,2.373c0.164-0.007,0.182-0.026,0.277-0.078C66.352,34.819,66.521,33.473,66.693,32.128L66.693,32.128z M4.297,38.894c-0.013,2.467-0.142,6.269,1.781,6.806c0.7,0.193,1.087-0.271,1.306-0.595c0.786-1.17,0.565-3.446-0.199-4.43c-0.339,0.034-0.825,0.84-0.988,1.106c-0.082-0.016-0.075-0.011-0.119-0.04c-0.091-0.041-0.085-0.066-0.159-0.118c-0.06-0.933,0.127-1.802,0.159-2.691c1.044,0.102,1.941,0.696,3.007,0.751c-0.001-0.185,0-0.434,0.077-0.552c-0.009-0.092-0.007-0.112-0.04-0.16c-0.145-0.115-0.949-0.306-1.186-0.315v-0.04h-0.04c0.146-1.174-0.186-2.082-0.99-2.414c-0.449-0.08-0.897-0.16-1.346-0.239c-0.229-0.083-0.341-0.266-0.514-0.395c-0.058-0.38-0.133-0.806,0.159-1.029c-0.021-0.142-0.032-0.168-0.119-0.238v-0.039h-0.04c-0.133,0.228-0.245,0.493-0.315,0.792c-0.234,0.983,0.309,1.818,0.909,2.018c0.397,0.065,0.792,0.132,1.188,0.197c0.314,0.122,0.453,0.379,0.671,0.595c-0.009,0.512-0.5,0.568-0.91,0.435c-0.64-0.208-1.321-0.353-1.977-0.592c-0.172-0.064-0.333-0.17-0.555-0.199c-0.027,0.25-0.054,0.501-0.08,0.751c0.554,0.171,1.109,0.343,1.662,0.515c-0.023,1.398-0.574,3.074,0.119,4.153c0.084,0.021,0.143,0.037,0.198,0.08c0.78-0.054,0.943-0.68,1.345-1.108c0.342,0.82,0.086,2.253-0.671,2.453c-0.326,0.224-0.803-0.066-0.989-0.237c-0.648-0.599-0.785-1.511-1.027-2.532c-0.083-0.344,0.033-1.042-0.118-1.307c0.006-0.404,0.092-1.134-0.12-1.344v-0.039L4.297,38.894L4.297,38.894z M99.336,45.543c-0.143-0.666,0.055-1.478-0.08-2.097v-0.633c-0.097-0.453-0.059-1.056-0.156-1.502c-0.189-0.882-0.022-1.926-0.355-2.652c-0.197-0.047-0.393-0.084-0.671-0.08c-0.103,0.104-0.179,0.158-0.159,0.278c0.083,0.359,0.547,0.432,0.673,0.792c0.015,0.172,0.026,0.343,0.04,0.514c0.133,0.561,0.111,1.286,0.236,1.86v0.475c0.063,0.289,0.16,1.036,0.078,1.267c-0.139,0.41-0.584,0.78-0.868,1.068c-0.754,0.755-1.64,1.715-2.97,1.859c-0.025,0.068-0.01,0.039-0.041,0.08c0.022,0.494,0.476,0.396,0.793,0.594c0.08-0.014,0.158-0.028,0.236-0.042c0.122-0.074,0.191-0.242,0.276-0.356c0.2-0.261,0.563-0.399,0.751-0.671h0.04c0.002,1.205,0.028,2.561,0.04,3.718h0.117c0.272-1.172,0.252-2.61,0.238-4.039c0.521-0.486,0.853-1.19,1.385-1.66v-0.078h0.041c0.007,1.251,0.037,2.529,0.037,3.797c0,0.407-0.102,1.378,0,1.544v0.237h0.08c0.106-0.425,0.133-1.023,0.236-1.501v-0.674C99.451,47.107,99.45,46.078,99.336,45.543L99.336,45.543z M28.313,48.073c-0.347-0.144-0.776-0.461-0.989-0.751c-0.637-0.875-1.337-2.948-0.87-4.51c0.379-1.266,1.202-2.127,2.532-2.454c0.673-0.163,1.397,0.062,1.821,0.278c1.208,0.622,1.725,1.506,2.096,2.967c0.48,1.887-0.132,3.619-1.385,4.194c0.078,0.764,0.158,1.529,0.237,2.295c0.444-0.013,0.852-0.105,1.227-0.199c0.629-0.155,1.271-0.176,1.86-0.315c0.431-0.104,1.052-0.015,1.384-0.237c0.079-0.17-0.247-1.35-0.315-1.623c-0.057-0.229-0.009-0.461-0.119-0.633v-0.079c-0.091,0.012-0.185,0.025-0.277,0.039c0.018,1.195-0.834,1.032-1.781,1.267c-0.473,0.119-1.049,0.27-1.581,0.276c0-0.17,0-0.343-0.001-0.514c0.045-0.083,0.739-0.386,0.868-0.476c0.461-0.318,0.931-0.826,1.229-1.304c0.202-0.327,0.366-0.764,0.473-1.149c0.138-0.489,0.154-1.17,0.041-1.662c-0.079-0.338-0.048-0.603-0.158-0.91c-0.427-1.187-1.322-2.054-2.453-2.532c-0.513-0.216-1.093-0.224-1.7-0.356c-0.539-0.116-1.509,0.124-1.901,0.238c-1.905,0.562-3.198,1.48-3.799,3.323c-0.236,0.728-0.163,1.736,0.04,2.414c0.467,1.561,1.773,3.02,3.72,3.047v0.039c0.062,0.088,0.06,0.264,0.118,0.355c-0.024,0.067-0.009,0.039-0.04,0.08c-0.164,0.111-0.404,0.061-0.633,0.117c-0.47,0.118-1.986,0.486-2.334,0.158c-0.222-0.072-0.37-0.363-0.396-0.632c-0.099,0.004-0.146,0.004-0.197,0.039h-0.082c0.146,0.767,0.291,1.53,0.435,2.296h0.041v0.04c1.385-0.239,2.77-0.478,4.154-0.713c-0.198-0.728-0.395-1.451-0.593-2.179C28.873,48.139,28.517,48.159,28.313,48.073L28.313,48.073z M96.014,43.682c0.086,0.218,0.254,0.58,0.435,0.712c0.086,0.063,0.132,0.04,0.198,0.119c1.31,0.113,1.842-2.143,1.308-3.442c-0.095-0.225-0.517-0.885-0.911-0.633h-0.08c0.026-0.069,0.01-0.038,0.04-0.08c-0.001-0.188-0.021-0.25-0.077-0.356c-0.08-0.013-0.156-0.026-0.238-0.038c-0.039,0.031-0.01,0.014-0.078,0.038c0.027,0.24,0.111,0.247,0.119,0.514C96.09,41.099,95.545,42.497,96.014,43.682z M96.446,41.585c0.088-0.213,0.265-0.35,0.396-0.515c0.082-0.015,0.075-0.01,0.117-0.04c0.301-0.001,0.385,0.057,0.555,0.159c0.301,0.711,0.346,1.954-0.156,2.494c-0.077,0.085-0.229,0.116-0.315,0.197C96.214,43.817,96.146,42.305,96.446,41.585L96.446,41.585z M78.092,57.168c-0.445-0.273-0.507-1.675-0.673-2.294c-0.327-1.215-0.483-2.489-0.831-3.72c-0.223-0.788-0.523-1.605-0.435-2.572c0.139-0.138,0.231-0.32,0.396-0.436c0.223-0.154,0.58-0.229,0.752-0.436c0.027-0.051-0.019-0.128-0.041-0.238c-0.459,0.074-0.879,0.35-1.267,0.515c-0.792,0.337-1.567,0.536-2.373,0.87c-0.252,0.104-0.515,0.282-0.833,0.315v0.238c0.027,0.014,0.055,0.025,0.08,0.04c0.042,0.045,1.033-0.392,1.346-0.118c0.356,0.125,0.311,0.59,0.514,0.872c-0.061,0.614-0.672,1.558-0.912,2.097c-0.58,1.326-1.17,2.592-1.816,3.836c-0.248,0.477-0.543,1.334-0.871,1.701v0.039c-0.216-0.296-0.199-1.051-0.314-1.462c-0.353-1.235-0.578-2.591-0.951-3.798c-0.068-0.23-0.305-1.279-0.156-1.503c0.051-0.546,0.822-0.785,1.266-0.95c-0.012-0.092-0.024-0.186-0.039-0.277c-0.701,0.105-1.429,0.479-2.058,0.713c-0.595,0.223-1.14,0.313-1.741,0.516c-0.298,0.102-0.636,0.275-0.986,0.314v0.041h-0.041c0.015,0.112,0.025,0.172,0.078,0.237c0.162,0.107,1.03-0.352,1.386-0.077c0.557,0.19,0.573,1.075,0.752,1.66c0.481,1.579,0.728,3.327,1.187,4.947c0.115,0.404,0.391,1.686,0.119,2.018c-0.148,0.439-0.885,0.615-1.306,0.791c0.014,0.08,0.024,0.159,0.036,0.237c0.609-0.09,1.162-0.373,1.707-0.56c1.063-0.354,2.066-0.65,3.089-1.029c-0.017-0.092-0.027-0.186-0.041-0.275c-0.437,0.116-0.773,0.248-1.386,0.236c-0.08-0.068-0.157-0.133-0.235-0.199c-0.067-0.21-0.134-0.422-0.199-0.632c0.043-0.499,0.683-1.421,0.91-1.86c0.673-1.293,1.262-2.6,1.856-3.955c0.229-0.519,0.754-1.275,0.832-1.857c0.184,0.111,0.133,0.438,0.197,0.672c0.135,0.475,0.211,0.98,0.355,1.503c0.281,1,0.391,2.075,0.673,3.126c0.104,0.387,0.261,1.048,0.08,1.464c-0.179,0.404-0.841,0.673-1.267,0.83c0.017,0.084,0.037,0.183,0.08,0.238c0.004,0.007,0.906-0.288,1.064-0.354c1.104-0.471,2.236-0.959,3.361-1.386c-0.015-0.093-0.024-0.187-0.039-0.274C79.117,57.043,78.477,57.407,78.092,57.168L78.092,57.168z M96.803,60.498c-0.143,0.13-0.354,0.163-0.514,0.277c-0.501,0.359-1.025,0.962-1.385,1.463c-0.288,0.402-0.534,0.843-0.791,1.268c-0.112,0.188-0.137,0.402-0.277,0.553v0.08c0.346-0.059,0.549-0.283,0.792-0.436c0.659-0.408,1.249-0.781,1.858-1.225c0.295-0.217,0.515-0.551,0.83-0.754c0.029-0.473,0.125-0.844-0.077-1.188C97.115,60.512,96.975,60.496,96.803,60.498z M96.329,61.921c-0.239,0.177-0.47,0.423-0.712,0.595c-0.208,0.146-0.458,0.224-0.633,0.396h-0.04c0.13-0.408,0.817-1.107,1.146-1.344c0.17-0.124,0.383-0.157,0.557-0.279h0.156c0.036,0.046,0.034,0.044,0.08,0.08C96.846,61.667,96.523,61.774,96.329,61.921L96.329,61.921z M10.825,63.465c-0.166-0.502-0.278-0.99-0.435-1.465c-0.079-0.246-0.062-0.525-0.199-0.713v-0.118c0.269,0.097,0.679,0.087,0.911,0.238h0.201c-0.045-0.206-0.086-0.552-0.201-0.713c-0.12-0.195-0.886-0.197-1.106-0.354c-0.312-0.244-0.607-0.947-0.832-1.307c-0.56-0.887-1.302-1.832-2.137-2.453c-0.443-0.329-0.751-0.671-1.544-0.673c-0.092,0.065-0.185,0.132-0.276,0.198c-0.178,0.789,0.139,2.248,0.592,2.611v0.078c-0.189-0.051-0.393-0.152-0.514-0.275h-0.04c0.007,0.227,0.051,0.522,0.158,0.672c0.046,0.195,0.362,0.354,0.554,0.396c0.248,1.037,0.592,2.101,0.95,3.05c0.289,0.758,0.436,1.48,0.75,2.213c0.155,0.356,0.522,0.617,0.634,0.99h0.117c-0.089-0.334-0.271-0.646-0.394-0.949c-0.364-0.875-0.653-1.804-0.952-2.688C6.868,61.62,6.734,61.057,6.548,60.5c-0.069-0.21-0.049-0.427-0.158-0.595v-0.039c0.269,0.049,0.43,0.188,0.634,0.276c0.461,0.201,0.903,0.277,1.385,0.476c0.353,0.146,0.796,0.347,1.228,0.396c0.048,0.359,0.253,1.301,0.435,1.545v0.117c-0.602-0.412-0.589-1-1.663-0.91c-0.054,0.063-0.128,0.117-0.197,0.158c-0.098,0.244-0.104,0.646,0,0.909c0.257,0.646,1.072,1.991,1.741,2.179c0.257,0.184,0.634-0.043,0.75-0.24c0.242,0.127,0.293,0.682,0.395,0.951c0.212,0.558,0.522,1.289,1.031,1.543v0.041h0.083c-0.066-0.447-0.318-0.851-0.475-1.229C11.387,65.223,11.113,64.324,10.825,63.465L10.825,63.465z M9.678,60.26C9.26,60.23,8.905,60.067,8.57,59.945c-0.894-0.332-1.703-0.615-2.492-0.991c-0.095-0.358-0.76-1.644-0.396-2.095c0.026-0.04,0.053-0.081,0.079-0.12c0.081-0.019,0.077-0.011,0.119-0.039c1.219,0.146,2.442,1.629,3.046,2.452c0.236,0.32,0.43,0.799,0.752,1.029V60.26L9.678,60.26z M10.311,63.701c-0.12,0.146-0.237,0.291-0.356,0.436c-0.105,0.078-0.223,0.109-0.316,0.198c-0.68-0.021-0.704-0.686-0.989-1.108c0.005-0.389,0.152-0.39,0.315-0.594c0.092-0.007,0.112-0.007,0.158-0.037c0.614,0.004,0.753,0.278,1.109,0.515C10.29,63.344,10.327,63.445,10.311,63.701L10.311,63.701z M33.578,69.794c-0.165-0.271-0.49-0.342-0.713-0.554c-0.069-0.023-0.04-0.007-0.079-0.039c0.51-0.264,1.053-0.555,1.583-0.79c0.142,0.158,0.801,0.792,1.029,0.671c0.04-0.012,0.079-0.023,0.118-0.038c-0.013-0.224-0.025-0.448-0.04-0.673c-0.499-0.498-1.234-0.91-2.059-1.066v0.039h-0.039c0.093,0.273,0.398,0.534,0.636,0.672v0.119c-0.469,0.068-0.885,0.295-1.307,0.437c-0.289,0.093-0.638,0.08-0.873,0.235h-0.117c0.171-0.479,0.737-0.871,1.028-1.267c0.576-0.776,1.033-1.728,1.94-2.176c-0.024-0.365-1.076-1.12-1.464-0.871c-0.097,0.051-0.029-0.021-0.079,0.078c-0.059,0.144,0.137,0.321,0.079,0.554c-0.076,0.305-0.831,1.74-1.029,1.9v0.041c-0.408-0.139-0.718-0.523-1.107-0.713c0.069-0.364,0.375-0.644,0.554-0.91c0.453-0.684,0.816-1.335,1.503-1.782c-0.006-0.526-0.855-1.075-1.425-1.065c0.002,0.242,0.125,0.379,0.08,0.592c-0.14,0.646-0.435,1.297-0.672,1.861c-0.156,0.364-0.226,0.799-0.476,1.065c-0.054,0.03-0.492-0.006-0.594-0.077c-0.149-0.002-0.298,0.005-0.394,0.038v0.079c0.666,0.645,1.387,0.865,2.295,1.268c-0.126,0.655-0.786,1.092-1.108,1.584c-0.166,0-0.3-0.011-0.395-0.08c-0.091,0.017-0.098,0.021-0.158,0.041c0.016,0.582,0.5,1.077,0.987,1.188c0.327-0.366,0.737-0.543,1.228-0.751c0.449,0.468,0.578,1.137,0.751,1.897c0.075,0.332-0.047,0.697,0.04,0.988c0.152,0.514,0.426,0.667,0.672,1.027h0.277c0.174-0.93-0.253-1.832-0.475-2.571C33.71,70.43,33.644,70.111,33.578,69.794L33.578,69.794z M96.09,63.108c-0.238,0.202-0.57,0.296-0.83,0.475c-0.4,0.282-0.758,0.659-1.146,0.95c-0.177,0.134-0.435,0.253-0.556,0.436c-0.199,0.299-0.16,0.806-0.396,1.067v0.157c0.314-0.114,0.464-0.483,0.713-0.672c0.307-0.23,0.563-0.536,0.87-0.754c0.192-0.133,0.411-0.207,0.594-0.355c0.125,0.023,0.115,0.037,0.199,0.081c-0.021,1.005-0.549,1.714-0.871,2.454c-0.093,0.215-0.121,0.551-0.276,0.71c-0.074,0.076-0.229,0.094-0.314,0.157c-0.264,0.291-0.528,0.58-0.794,0.873c-0.25,0.344-0.365,0.803-0.632,1.146c-0.002,0.114-0.002,0.216,0.037,0.276c0.041,0.031,0.11,0.059,0.16,0.08c0.51-0.483,1.004-0.887,1.424-1.465c0.658-0.904,0.986-2.047,1.465-3.125c0.3-0.683,0.734-1.354,0.711-2.334c-0.047-0.045-0.084-0.102-0.117-0.158L96.09,63.108L96.09,63.108z M93.32,69.361V69.4h-0.04c0.069-0.475,0.43-0.606,0.596-0.952h0.079C93.904,68.842,93.605,69.194,93.32,69.361L93.32,69.361z M34.171,69.993c-0.08,0.342,0.76,1.106,1.027,1.308c0.133,0.1,0.312,0.328,0.515,0.235c0.104-0.008,0.136-0.019,0.199-0.04c0.046-0.105,0.115-0.24,0.039-0.354C35.93,70.645,34.64,70.088,34.171,69.993z M37.97,73.037c0.067,0.034,0.122,0.021,0.198-0.039c0.139-0.113,0.063-0.313,0.159-0.475c0.222-0.159,0.615-0.118,0.911-0.199c0.809-0.213,1.753-0.198,2.65-0.396c0.425-0.093,1.128,0.16,1.464-0.037c0.04-0.016,0.081-0.026,0.118-0.043c-0.019-0.517-1.009-0.737-1.545-0.588c-0.237,0.066-0.513,0.213-0.751,0.275c-0.185,0.014-0.37,0.027-0.555,0.038c-0.062-0.644-0.38-1.144-0.395-1.817c0.595-0.013,1.341-0.091,1.739-0.316c-0.008-0.2-0.045-0.2-0.118-0.314c-0.453-0.107-1.23-0.126-1.583,0.116c-0.1-0.004-0.147-0.004-0.197-0.039c-0.221-0.28-0.116-0.851-0.316-1.146v-0.158c0.426-0.092,1.122-0.168,1.345-0.475c0.031-0.041,0.014-0.011,0.039-0.078c-0.036-0.035-0.051-0.068-0.079-0.119c-0.619-0.156-0.887-0.049-1.423,0.158c-0.167-0.535,0.034-0.959-0.514-1.108c0.117-0.203,0.506-0.194,0.751-0.276c0.382-0.126,0.817-0.296,1.148-0.474c0.026-0.068,0.007-0.04,0.04-0.08c-0.022-0.2-0.078-0.193-0.159-0.316c-0.571-0.044-1.027,0.011-1.346,0.316h-0.076c0.047-0.295,0.231-0.718,0.394-0.949c0.112-0.162,0.318-0.14,0.396-0.356h0.04V64.1c-0.081-0.104-0.159-0.211-0.238-0.314c-0.186-0.13-0.454-0.143-0.632-0.279c-0.263-0.004-0.515-0.003-0.672,0.079c0.021,0.152,0.089,0.248,0.119,0.356c0.109,0.408-0.284,1.669-0.436,1.859c-0.123,0.154-1.551,0.672-1.939,0.555c-0.092-0.029-0.36-0.164-0.435-0.239c-0.032-0.039-0.015-0.008-0.04-0.077c0.561-0.527,0.965-1.702,1.741-1.939c0.014-0.064,0.027-0.131,0.041-0.196c-0.194-0.2-1.135-1.188-1.622-0.871c-0.04,0.014-0.079,0.022-0.117,0.038c0,0.338,0.168,0.593,0.078,0.949c-0.182,0.711-0.587,1.556-0.95,2.139c-0.218,0.35-0.693,0.729-0.712,1.229c0.646-0.064,0.802-0.731,1.304-0.912c0.146,0.135,0.29,0.267,0.436,0.396c0.207,0.311,0.168,0.778,0.276,1.186c0.185,0.856,0.371,1.715,0.554,2.571c0.025,0.425,0.052,0.845,0.08,1.269C37.246,72.28,37.561,72.945,37.97,73.037L37.97,73.037z M39.233,70.032c0.031,0.368,0.258,1.407,0.436,1.662c0.001,0.024,0.001,0.054,0.001,0.08c-0.477,0.102-0.973,0.239-1.504,0.237c-0.082-0.564-0.352-1.061-0.355-1.662C38.418,70.338,38.731,70.094,39.233,70.032z M36.939,66.75c0.063-0.107,1.113-0.273,1.228-0.199c0.42,0.195,0.27,0.813,0.514,1.188c-0.083,0.194-1.047,0.487-1.345,0.514C37.283,67.834,37.213,66.977,36.939,66.75L36.939,66.75z M38.76,68.253h0.04c0.076,0.36,0.119,0.978,0.317,1.267c-0.142,0.348-1.016,0.317-1.346,0.516c-0.138-0.083-0.32-1.076-0.316-1.346C37.757,68.662,38.541,68.402,38.76,68.253L38.76,68.253z M31.914,70.506c-0.06,0.135-0.053,0.354-0.117,0.514c-0.342,0.84-0.454,1.015,0.079,1.82c0.237,0,0.269-0.037,0.396-0.119C32.429,72.064,32.454,70.814,31.914,70.506L31.914,70.506z M77.023,70.744c-1.154-0.285-2.125,0.285-3.325,0.199c-0.114-0.121-0.2-0.19-0.275-0.356c-0.835,0.024-1.757,1.886-0.909,2.453c0.453,0.308,1.744,0.129,2.295,0c0.306-0.071,0.783-0.139,1.027,0.038c0.332,0.247,0.273,1.182,0.157,1.703c-0.132,0.975-0.265,1.951-0.396,2.929c-0.117,0.593-0.236,1.185-0.356,1.779c0.606-0.003,1.178-0.623,1.349-1.069c0.1-0.258,0.047-0.502,0.119-0.791c0.209-0.83,0.237-1.82,0.436-2.689c0.127-0.563,0.041-1.1,0.156-1.621c0.086-0.393,0.143-1.696,0.041-2.059C77.281,71.059,77.126,70.901,77.023,70.744z M22.857,82.695c-0.135-0.102-0.229-0.283-0.356-0.395c-0.473-0.42-1.029-0.826-1.543-1.188c-0.426-0.298-1.008-0.476-1.387-0.829c-0.01-0.086,0.123-0.296,0.041-0.516c-0.335-0.896-1.589-1.933-2.374-2.412c-0.363-0.225-0.972-0.328-1.305-0.555c-0.246-0.017-0.374-0.025-0.435,0.155c-0.097,0.218,0.209,0.521,0.315,0.675c0.271,0.381,0.581,0.826,0.95,1.104c0.276,0.209,0.591,0.392,0.83,0.635h0.119c-0.154-0.426-0.609-0.657-0.949-0.909c-0.311-0.229-0.449-0.632-0.712-0.909c0.021-0.125,0.035-0.115,0.08-0.199c1.093,0.009,1.802,1.012,2.294,1.662c0.22,0.291,0.571,0.461,0.594,0.951c-0.116,0-0.216,0-0.276-0.041h-0.119c0.188,0.522,0.824,0.479,1.267,0.754c0.888,0.549,1.603,1.409,2.373,2.094c0.262,0.234,0.719,0.466,0.791,0.873c-0.537-0.028-0.917-0.327-1.261-0.555c-0.614-0.4-1.597-1.1-2.019-1.662c-0.08-0.104-0.106-0.263-0.199-0.355c-0.109-0.111-0.261-0.145-0.355-0.275h-0.158c-0.039,0.41,0.407,0.705,0.671,0.948c0.819,0.75,1.696,1.442,2.73,1.979c0.373,0.191,1.053,0.521,1.465,0.275C23.874,83.434,23.227,82.975,22.857,82.695L22.857,82.695z M47.226,85.307c-2.014-1.379-4.985-2.775-8.427-2.689c-0.167,0.104-0.503,0.021-0.711,0.078c-0.288,0.076-0.464,0.223-0.672,0.355c-0.008,0.971,1.446,1.496,2.255,1.698c0.483,0.123,0.909-0.104,1.188-0.198c0.215-0.82-0.776-0.94-1.227-1.347h-0.081v-0.038c3.036-0.119,5.308,0.729,7.043,2.02c0.433,0.322,0.93,0.783,1.148,1.306c0.081,0.194,0.116,0.515,0,0.674c-0.159,0.44-0.685,0.401-1.188,0.515c-1.162,0.267-2.755-0.391-3.285-0.91c-0.108,0.189,0.049,0.48-0.118,0.674c-0.176,0.478-0.788,0.354-1.346,0.474c-0.917,0.199-2.353-0.271-2.888-0.632c-0.149-0.104-0.257-0.286-0.396-0.396c-0.007-0.103-0.018-0.136-0.041-0.199c0.081-0.073,0.177-0.187,0.237-0.275c1.139-0.085,1.718-0.027,2.376,0.596c-0.017,0.078-0.01,0.073-0.041,0.114c-0.074,0.152-0.245,0.17-0.474,0.161v0.074c0.417,0.004,0.593-0.059,0.83-0.197c0.013-0.079,0.027-0.159,0.04-0.236c-0.136-0.141-0.231-0.328-0.396-0.438c-0.65-0.426-1.991-0.641-2.729-0.156c-0.116,0.561,0.232,0.864,0.554,1.105c0.646,0.488,1.191,0.771,2.098,1.029c0.291,0.082,0.55,0.008,0.871,0.076c0.28,0.064,0.765,0.079,1.068,0c0.504-0.128,1.205-0.658,0.632-1.268v-0.037c0.299,0.109,0.544,0.402,0.831,0.556c0.761,0.397,2.021,0.726,3.167,0.476c0.562-0.125,1.143-0.125,1.303-0.635c0.179-0.277-0.068-0.668-0.156-0.826C48.322,86.151,47.836,85.721,47.226,85.307L47.226,85.307z M39.906,83.485c0.14,0.094,0.22,0.291,0.356,0.396c-0.003,0.1-0.004,0.148-0.04,0.199c-0.257,0.697-1.706,0.182-2.058-0.081c-0.11-0.08-0.153-0.248-0.236-0.354c0.015-0.082,0.01-0.076,0.041-0.116c0.108-0.306,0.417-0.203,0.671-0.354C39.142,83.174,39.596,83.274,39.906,83.485z M76.625,83.881h-0.396c-0.262,0.209-0.692,0.236-0.991,0.396c-0.263,0.141-0.581,0.332-0.829,0.515c-0.207,0.148-0.326,0.418-0.516,0.592c0.004,0.197,0.008,0.229,0.16,0.277c0.039,0.029,0.01,0.018,0.075,0.04c0.042-0.047,0.08-0.063,0.12-0.12c0.033-0.023-0.027-0.104-0.04-0.232c0.384-0.386,0.667-0.598,1.228-0.832c0.144-0.059,0.447-0.233,0.634-0.119h0.079c-0.026,0.391-0.916,1.591-1.188,1.781v0.115c0.729-0.188,1.215-1.643,1.702-2.174c-0.013-0.09-0.01-0.111-0.04-0.157L76.625,83.881L76.625,83.881z M73.459,86.809c-0.234,0.209-0.807,0.229-1.066,0.435h-0.041c0.104-0.149,0.291-0.213,0.396-0.354c0.076-0.104,0.107-0.226,0.197-0.315c-0.018-0.081-0.01-0.075-0.039-0.117v-0.08c-1.155-0.212-3.084,0.784-3.68,1.308c-0.155,0.135-0.248,0.336-0.396,0.477c0.003,0.111,0.016,0.168,0.039,0.236c0.701,0.047,2.016-0.383,2.174-0.949c0.031-0.025,0.012-0.002,0-0.04v-0.079c-0.479-0.027-1.124,0.075-1.422,0.355h-0.039c0.26-0.396,1.223-0.746,1.739-0.91c0.172-0.053,0.55-0.149,0.714-0.039c0.037,0.015,0.077,0.025,0.117,0.039c-0.094,0.396-0.657,0.838-1.029,0.949v0.08c0.607-0.141,1.163-0.416,1.7-0.634c0.368-0.149,0.786-0.188,1.108-0.396c0.229-0.149,1.008-1.207,1.068-1.504C74.086,85.409,74.012,86.313,73.459,86.809L73.459,86.809z M70.333,87.6v0.119c-0.075,0.049-0.129,0.156-0.198,0.196c-0.205,0.12-0.479,0.106-0.674,0.238c-0.09-0.011-0.109-0.009-0.156-0.041h-0.039C69.373,87.775,70.025,87.621,70.333,87.6L70.333,87.6z M53.835,91.317c0.015-0.037,0.025-0.078,0.039-0.117c-0.976-0.04-1.953-0.079-2.927-0.119c-0.123,0.082-0.312,0.035-0.475,0.079c-0.202,0.059-0.426,0.15-0.593,0.239c0.026,0.067,0.008,0.038,0.04,0.077c0.238,0.188,1.624,0.199,1.9,0h0.078v-0.077c-0.419-0.134-1.183,0.2-1.503,0h-0.041v-0.041c1.052-0.073,2.23-0.044,3.325-0.04c-0.105,0.072-0.328,0.051-0.436,0.119c-0.039,0.014-0.078,0.027-0.117,0.039v0.08c0.238,0.037,0.475,0.078,0.711,0.117c0.037,0.041-0.004,0.004,0.039,0.037c-0.35,0.233-1.254,0.139-1.581-0.037v-0.08c-0.178-0.082-0.991,0.084-1.148,0.117c-0.133,0.03-0.27-0.014-0.357,0.039c-0.165,0.01-0.181,0.029-0.276,0.079c0.022,0.128,0.035,0.115,0.08,0.198c0.255,0.06,0.696,0.064,0.987,0.156v-0.039h0.04v-0.039c-0.148-0.057-0.559-0.025-0.713-0.115h-0.079c0.132-0.104,1.425-0.278,1.663-0.119c0.067,0.023,0.039,0.007,0.079,0.039c-0.211,0.038-0.424,0.08-0.634,0.117c0.025,0.066,0.009,0.039,0.04,0.078c0.065,0.045,0.193,0.045,0.316,0.039c-0.04,0.074-0.054,0.109-0.119,0.158c0.013,0.023,0.027,0.051,0.04,0.078c0.561,0,1.031-0.057,1.502-0.156c0.28-0.062,0.624,0.052,0.831-0.08h0.317v-0.078c-0.539-0.002-1.885-0.055-2.215,0.158h-0.117c0.033-0.043-0.004-0.004,0.038-0.041c0.155-0.18,0.471-0.09,0.75-0.156c0.44-0.104,1.168-0.284,1.544,0c0.105,0.064,0.04-0.008,0.039,0.117c0.107-0.002,0.181-0.002,0.236-0.036h0.277v-0.081c-0.359-0.088-0.889-0.251-1.188-0.434C54.057,91.488,54.135,91.344,53.835,91.317L53.835,91.317z M13.635,18.359c-0.088,0.32-0.274,0.593-0.395,0.87c-0.268,0.613-0.507,1.225-0.751,1.822c-0.207,0.496-0.335,1.295-0.633,1.699v0.079c0.416-0.074,0.698-0.493,0.949-0.751c0.617-0.634,1.92-2.22,1.9-3.402c-0.062-0.061-0.119-0.162-0.159-0.237C14.3,18.38,13.982,18.353,13.635,18.359z M13.794,20.022c-0.181,0.298-0.281,0.592-0.476,0.871c-0.178,0.255-0.46,0.452-0.633,0.713h-0.041c0.051-0.302,0.214-0.546,0.319-0.792c0.235-0.561,0.396-1.118,0.671-1.621c0.152,0.003,0.268,0.015,0.356,0.078c0.095,0.052,0.028-0.018,0.079,0.08C14.15,19.548,13.89,19.862,13.794,20.022L13.794,20.022z M84.023,7.875c-0.414-0.416-0.729-0.938-1.147-1.346V6.49c-0.205,0.073-0.899,0.688-1.028,0.871c-0.25-0.095-0.391-0.365-0.594-0.514c-0.676-0.508-1.313-1.167-2.49-1.147c-0.148,0.115-0.367,0.118-0.556,0.197c-0.53,0.23-1.083,0.688-1.305,1.227c-0.249,0.602,0.004,1.491,0.196,1.939c0.392,0.904,1.03,1.667,1.582,2.414c0.457,0.615,0.973,1.252,1.819,1.464c0.956,0.238,1.422-0.884,1.781-1.308c0.37-0.435,1.182-0.539,1.464-1.107c0.104-0.207,0.034-0.615-0.039-0.791c-0.18-0.426-1.066-1.622-1.425-1.859c0.024-0.239,0.135-0.247,0.235-0.396c0.248,0.121,0.338,0.471,0.516,0.673c0.227,0.258,0.546,0.396,0.791,0.632c0.378,0.003,0.604-0.094,0.79-0.277h0.041C84.561,8.243,84.212,8.06,84.023,7.875L84.023,7.875z M81.77,12.148c-0.699,0.165-1.047-0.293-1.424-0.673c-0.938-0.935-1.57-2.093-2.298-3.244c-0.247-0.396-0.885-1.134-0.554-1.702h0.156c0.199,0.299,0.539,0.507,0.754,0.792c0.591,0.784,1.313,1.469,1.898,2.255c0.359,0.485,0.758,0.94,1.106,1.424c0.178,0.249,0.315,0.565,0.556,0.751C81.924,11.931,81.848,12.015,81.77,12.148L81.77,12.148z M82.361,9.339c0.32,0.439,0.755,0.688,0.751,1.463c-0.122,0.116-0.157,0.224-0.356,0.276c-0.039,0.032-0.011,0.015-0.078,0.041c-0.56-0.932-1.367-1.711-2.017-2.573c-0.212-0.282-0.541-0.511-0.752-0.791c-0.362-0.48-0.793-0.864-1.188-1.305c-0.113-0.131-0.168-0.257-0.313-0.357c0.033-0.086,0.031-0.057,0.076-0.118c0.672,0.006,0.994,0.458,1.386,0.753C80.837,7.453,81.648,8.354,82.361,9.339L82.361,9.339z"/><radialGradient id="SVGID_43_" cx="251.8086" cy="-408.3613" r="72.7509" gradientTransform="matrix(1 0 0 -1 -213.7637 -386.502)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#000" stop-opacity="0"/><stop offset=".8022" stop-color="#000" stop-opacity=".08"/><stop offset="1" stop-color="#000" stop-opacity=".3882"/></radialGradient><path style="&st15;" d="M49.885,17.037c0.014-0.606-0.392-1.27-0.392-1.27l-0.025-0.058c0,0-0.487-0.949-1.302-1.228c-0.815-0.278-1.478,0.342-1.478,0.342s-0.114,0.131-0.429,0.494c-0.313,0.364-0.507,0.666-1.198,0.938c-0.692,0.271-1.379,0.204-1.743,0.033c-0.364-0.172-0.457-0.537-0.457-0.537s-0.229-0.722-0.313-1.049c-0.086-0.331-0.309-1.694-0.309-1.694s-0.491-2.747-0.534-3.304c0,0,1.475-0.126,3.687-0.775c2.299-0.673,3.043-1.206,3.043-1.206s-0.432-0.156-0.484-0.662c-0.051-0.507-0.089-1.19-0.089-1.19s-0.089-0.5,0.483-1.139c0.571-0.64,1.354-0.863,1.762-0.953c0.41-0.089,1.281-0.17,2.093-0.134c0.812,0.038,1.267,0.112,1.593,0.291c0.328,0.178,0.357,0.61,0.357,0.61l-0.008,1.146c0,0-0.037,0.402,0.261,0.529c0,0,0.505,0.305,2.196,0.133c0,0,0.72-0.126,1.846-0.46c1.125-0.335,4.129-1.229,4.554-1.341c0.425-0.111,0.953-0.291,1.646-0.469c0.691-0.179,2.039-0.626,2.308-0.73c0.271-0.104,1.812-0.618,2.927-0.81c1.115-0.195,2.227-0.186,2.813,0.149c0,0,0.357,0.304,0.521,0.662c0.163,0.358,0.478,0.863,0.923,1.088c0.454,0.227,0.752,0.371,1.875,0.273c0,0,0.022-0.096-0.395-0.37c-0.417-0.277-0.991-0.701-0.991-0.701S74.29,3.4,74.215,3.198c-0.072-0.202-0.043-0.306-0.043-0.306l0.877-1.406c0,0,0-0.172,0.508-0.238c0.506-0.067,1.071-0.134,1.74-0.313c0.67-0.178,0.788-0.312,0.788-0.312l0.58,0.178c0,0,3.546,2.853,4.655,3.583l0.199-0.239c0,0,0.436,0.018,0.826,0.172c0.394,0.154,0.979,0.562,0.979,0.562s1.612,1.31,2.071,2.2l0.223,0.679l-0.102,0.161c0,0,0.918,1.307,2.096,2.602c0,0,1.227,1.664,1.689,2.09c0,0-0.108-0.399-0.201-0.849l0.336-0.226l0.203-0.144l0.617,0.259c3.573,4.811,6.432,10.424,8.141,16.328l-0.12,0.484l0.395,0.501c1.128,4.212,1.728,8.643,1.728,13.211c0,1.122-0.036,2.236-0.107,3.339l-0.304,0.511l0.225,0.555c-2.231,26.1-24.124,46.584-50.801,46.584c-18.502,0-34.702-9.854-43.637-24.6L7.674,68.2l-0.205-0.153c-3.387-5.742-5.682-12.205-6.595-19.103l0.212-0.525L0.75,47.936c-0.213-1.892-0.322-3.812-0.322-5.756c0-2.985,0.255-5.909,0.748-8.755l0.25-0.562l-0.087-0.328c1.157-6.048,3.383-11.716,6.474-16.799l0.684-0.384l0.081,0.032c0,0,0.233-0.169,0.354-0.217l0.076-0.023c0,0,1.179-1.971,1.625-2.601c0,0,0.542-0.348,0.745-0.407c0,0,0.124-0.016,0.189,0.076c0,0,0.496-0.432,1.699-2.054c0.004-0.005,0.007-0.011,0.012-0.017c0,0-0.114-0.076-0.131-0.174c-0.018-0.097,0.108-0.591,0.173-0.717c0.065-0.126,0.108-0.156,0.108-0.156s1.722-2.032,3.151-3.238c0,0,0.26-0.202,0.678-0.25c0,0,1.472-0.613,3.264-2.184c0,0,0.051-0.289,0.478-0.858c0.428-0.57,1.456-1.163,2.222-1.337c0.764-0.174,0.896-0.038,0.896-0.038l0.064,0.065l0.515,0.766c0,0,0.565-0.316,1.413-0.604c0.847-0.289,0.979-0.262,0.979-0.262l0.825,1.336l-0.987,2c0,0-0.644,1.421-1.655,2.185c0,0-0.472,0.284-1.12,0.127c-0.648-0.157-1.072,0.333-1.072,0.333l-0.17,0.14c0,0,0.14-0.024,0.346-0.103c0,0,0.158,0.065,0.274,0.223c0.114,0.158,0.913,1.175,0.913,1.175s0.005,0.837-0.415,1.938c-0.419,1.1-1.467,2.891-1.467,2.891s-0.733,1.424-1.075,2.253c-0.342,0.829-0.515,1.765-0.488,2.262c0,0,0.187,0.062,0.707-0.202c0.655-0.332,1.083,0.027,1.083,0.027s0.719,0.53,1.041,0.881c0.262,0.289,0.802,1.765,0.209,3.224c0,0-0.402,1.008-1.377,1.724c0,0-0.216,0.332-1.529,0.174c-0.368-0.043-0.585-0.276-1.372-0.2c-0.785,0.077-1.231,0.815-1.231,0.815l0.013-0.024c-0.692,0.999-1.154,2.458-1.154,2.458l-0.057,0.165c0,0-0.241,0.509-0.292,1.752c-0.053,1.284,0.284,3.109,0.284,3.109s7.876-1.387,9.88-0.055l0.58,0.532c0,0,0.046,0.174-0.031,0.376c-0.08,0.204-0.375,0.673-0.987,1.113c-0.611,0.438-1.222,1.583-0.313,2.304c1.034,0.818,1.691,0.766,3.43,0.468c1.74-0.297,2.898-1.269,2.898-1.269s0.972-0.72,0.783-1.628c-0.188-0.908-1.017-1.189-1.017-1.189s-0.658-0.423-0.141-1.238c0,0,0.141-0.689,2.553-1.316c2.414-0.626,6.812-1.52,10.556-1.989c0,0-2.539-8.223-0.737-9.289c0,0,0.438-0.296,1.224-0.408l0.721-0.037c0.131-0.027,0.344,0.005,0.796,0.045c0.452,0.038,1.001,0.076,1.678-0.441c0.676-0.519,0.697-0.819,0.697-0.819"/></svg>
\ No newline at end of file
diff --git a/modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg.license b/modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/fi/firefox/search_engines/logos/wikipedia.svg.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/fi/firefox/update_extensions.sh b/modules/by-name/fi/firefox/update_extensions.sh
deleted file mode 100755
index 588a7530..00000000
--- a/modules/by-name/fi/firefox/update_extensions.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env sh
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# The `generate_extensions` binary is provided in the devshell.
-
-generate_extensions \
-    darkreader:navbar \
-    keepassxc-browser:navbar \
-    vhack-libredirect:navbar \
-    torproject-snowflake:navbar \
-    tridactyl-vim:menupanel \
-    ublock-origin:menupanel \
-    >"$(dirname "$0")"/extensions.json
diff --git a/modules/by-name/fi/firefox/userChrome.css b/modules/by-name/fi/firefox/userChrome.css
deleted file mode 100644
index 6e0d705d..00000000
--- a/modules/by-name/fi/firefox/userChrome.css
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * nixos-config - My current NixOS configuration
- *
- * Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
- * SPDX-License-Identifier: GPL-3.0-or-later
- *
- * This file is part of my nixos-config.
- *
- * You should have received a copy of the License along with this program.
- * If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
- */
-
-/* thickness of tab when you have too many open tabs */
-.tabbrowser-tab:not([pinned="true"]) {
-  min-width: 10px !important;
-  min-height: 10px !important;
-}
-
-/* tab height
-#TabsToolbar .tabbrowser-tabs {
-min-height: 10px !important;
-}
-*/
-
-/*
-.tabbrowser-tab {min-width: 016px !important;}
-.tabbrowser-tab {clip-width: 016px !important;}
-*/
-
-/* the + button that opens new tabs */
-#TabsToolbar .tabs-newtab-button {
-  margin-left: 10px !important;
-  height: Auto !important;
-}
-
-#main-window[privatebrowsingmode="temporary"] #navigator-toolbox {
-  background-color: #c40944 !important;
-}
-
-/* close button inside a tab */
-.tab-close-button * {
-  width: 10px !important;
-  height: 10px !important;
-}
-
-/* bookmark toolbar */
-#personal-bookmarks .bookmark-item > .toolbarbutton-text {
-  font-size: 10pt !important;
-}
-#personal-bookmarks .bookmark-item > .toolbarbutton-icon {
-  height: 12px !important;
-  width: 12px !important;
-}
diff --git a/modules/by-name/fo/fonts/module.nix b/modules/by-name/fo/fonts/module.nix
index f8752ae6..4bf9a612 100644
--- a/modules/by-name/fo/fonts/module.nix
+++ b/modules/by-name/fo/fonts/module.nix
@@ -20,10 +20,14 @@ in {
 
     fonts = lib.mkOption {
       type = lib.types.listOf lib.types.package;
-      example = lib.literalExpression ''with pkgs.nerdfonts; [SourceCodePro Overpass FiraCode]'';
-      default = with pkgs.nerd-fonts; [
-        sauce-code-pro
-        overpass
+      example = lib.literalExpression ''        [
+                pkgs.nerd-fonts.source-code-pro
+                pkgs.nerd-fonts.overpass
+                pkgs.nerd-fonts.fira-code
+            ]'';
+      default = [
+        pkgs.nerd-fonts.sauce-code-pro
+        pkgs.nerd-fonts.overpass
       ];
       description = "The nerd-fonts to install";
     };
@@ -35,8 +39,8 @@ in {
     fonts = {
       packages =
         cfg.fonts
-        ++ (with pkgs; [liberation_ttf])
-        ++ lib.optional cfg.enableEmoji pkgs.noto-fonts-emoji;
+        ++ [pkgs.liberation_ttf]
+        ++ lib.optional cfg.enableEmoji pkgs.noto-fonts-color-emoji;
 
       fontconfig = {
         # NOTE: This is responsible for color emoji support <2023-08-28>
diff --git a/modules/by-name/fw/fwupd/module.nix b/modules/by-name/fw/fwupd/module.nix
index 0c4a7bf3..7252c170 100644
--- a/modules/by-name/fw/fwupd/module.nix
+++ b/modules/by-name/fw/fwupd/module.nix
@@ -17,7 +17,13 @@ in {
   options.soispha.services.fwupd = {
     enable = lib.mkEnableOption "fwupd";
   };
+
   config = lib.mkIf cfg.enable {
     services.fwupd.enable = true;
+
+    users = {
+      users.fwupd-refresh.uid = config.soispha.constants.ids.uids.fwupd-refresh;
+      groups.fwupd-refresh.gid = config.soispha.constants.ids.gids.fwupd-refresh;
+    };
   };
 }
diff --git a/modules/by-name/gi/git/module.nix b/modules/by-name/gi/git/module.nix
index a70c38d7..77cfce54 100644
--- a/modules/by-name/gi/git/module.nix
+++ b/modules/by-name/gi/git/module.nix
@@ -21,21 +21,37 @@ in {
     enable = lib.mkEnableOption "an opinionated git config";
     defaultBranchName = lib.mkOption {
       type = lib.types.str;
-      description = "The Name of the default branch.";
+      description = "The name of the default branch.";
       default = "prime";
     };
   };
 
   config = lib.mkIf cfg.enable {
     home-manager.users.soispha = {
+      programs.delta = {
+        enable = true;
+        enableGitIntegration = true;
+        options = {
+          decorations = {
+            commit-decoration-style = "bold yellow box ul";
+            file-decoration-style = "none";
+            file-style = "bold yellow ul";
+          };
+          keep-plus-minus-markers = true;
+          features = "decorations";
+          whitespace-error-style = "22 reverse";
+        };
+      };
+
       programs.git = {
         enable = true;
         #package = pkgs.gitAndTools.gitFull; # TODO: for git send-email support
-        aliases = import ./aliases.nix {
-          inherit lib;
-          inherit (cfg) defaultBranchName;
-        };
-        extraConfig = {
+        settings = {
+          alias = import ./aliases.nix {
+            inherit lib;
+            inherit (cfg) defaultBranchName;
+          };
+
           core = {
             excludesFile = "${gitIgnoreFile}";
           };
@@ -100,19 +116,7 @@ in {
             };
           };
         };
-        delta = {
-          enable = true;
-          options = {
-            decorations = {
-              commit-decoration-style = "bold yellow box ul";
-              file-decoration-style = "none";
-              file-style = "bold yellow ul";
-            };
-            keep-plus-minus-markers = true;
-            features = "decorations";
-            whitespace-error-style = "22 reverse";
-          };
-        };
+
         signing = {
           key = "8321ED3A8DB999A51F3BF80FF2682914EA42DE26";
           signByDefault = true;
diff --git a/modules/by-name/gp/gpg/module.nix b/modules/by-name/gp/gpg/module.nix
index cd913daf..d5136e92 100644
--- a/modules/by-name/gp/gpg/module.nix
+++ b/modules/by-name/gp/gpg/module.nix
@@ -22,6 +22,8 @@ in {
   };
 
   config = lib.mkIf cfg.enable {
+    soispha.programs.qutebrowser.key = "8321 ED3A 8DB9 99A5 1F3B  F80F F268 2914 EA42 DE26";
+
     home-manager.users.soispha = {
       programs.gpg = {
         enable = true;
@@ -45,6 +47,7 @@ in {
           }
         ];
       };
+
       services = {
         gpg-agent = {
           enable = true;
@@ -57,8 +60,10 @@ in {
           maxCacheTtl = 60 * 50;
           maxCacheTtlSsh = 60 * 50;
 
-          pinentryPackage = pkgs.pinentry-curses;
-          # pinentryPackage = pkgs.pinentry-tty;
+          pinentry = {
+            package = pkgs.pinentry-curses;
+            # package = pkgs.pinentry-tty;
+          };
 
           enableSshSupport = true;
           sshKeys = let
diff --git a/modules/by-name/ha/hardware/module.nix b/modules/by-name/ha/hardware/module.nix
index 599f5d23..69ef819f 100644
--- a/modules/by-name/ha/hardware/module.nix
+++ b/modules/by-name/ha/hardware/module.nix
@@ -48,7 +48,7 @@ in {
         extraPackages = builtins.attrValues {
           inherit
             (pkgs)
-            vaapiVdpau
+            libva-vdpau-driver
             libvdpau-va-gl
             ;
         };
diff --git a/modules/by-name/hl/lhedger/module.nix b/modules/by-name/hl/lhedger/module.nix
new file mode 100644
index 00000000..68de85d0
--- /dev/null
+++ b/modules/by-name/hl/lhedger/module.nix
@@ -0,0 +1,57 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  config,
+  lib,
+  pkgs,
+  libraries,
+  ...
+}: let
+  cfg = config.soispha.hledger;
+  ledgerFile = "${config.home-manager.users.soispha.xdg.dataHome}/hledger/2025.journal";
+in {
+  options.soispha.hledger = {
+    enable = libraries.base.options.mkEnable "hledger";
+  };
+
+  config = lib.mkIf cfg.enable {
+    environment.variables = {
+      LEDGER_FILE = ledgerFile;
+    };
+
+    home-manager.users.soispha = {
+      home.packages = [
+        pkgs.hledger
+
+        (pkgs.writeShellApplication {
+          name = "hledger-edit";
+
+          text = ''
+            "$EDITOR" ${lib.strings.escapeShellArg ledgerFile}
+          '';
+
+          inheritPath = true; # needs access to nvim
+        })
+      ];
+
+      xdg.configFile = {
+        "hledger/hledger.conf".text =
+          # ledger
+          ''
+            # Actually enforce more checks.
+            --strict
+
+            # Use boxdrawing characters when possible.
+            --pretty
+          '';
+      };
+    };
+  };
+}
diff --git a/modules/by-name/ho/home-manager/module.nix b/modules/by-name/ho/home-manager/module.nix
index 076d466e..d7eccbd6 100644
--- a/modules/by-name/ho/home-manager/module.nix
+++ b/modules/by-name/ho/home-manager/module.nix
@@ -10,22 +10,8 @@
 {
   config,
   lib,
-  pkgsStable,
-  nixpkgs_open_prs,
-  sysLib,
-  # extra information
   system,
-  # bins
-  # TODO: Integrate these <2024-05-22>
-  shell_library,
-  qmk_firmware,
-  # external deps
-  user_js,
-  # modules
-  impermanence,
-  nix-index-database,
-  nixVim,
-  arkenfox-nixos,
+  modules,
   ...
 }: let
   cfg = config.soispha.home-manager;
@@ -34,6 +20,10 @@ in {
     enable = lib.mkEnableOption "home-manager with custom config.";
   };
 
+  imports = [
+    modules.home-manager.nixosModules.home-manager
+  ];
+
   # TODO: Find a way to throw this error below, when a user `enable`s a home-manager
   # module, but not this module. Without having to plaster all the `home-manager` modules
   # with `assert`s. <2024-10-18>
@@ -42,24 +32,12 @@ in {
     home-manager = {
       useGlobalPkgs = true;
       useUserPackages = true;
+
+      # TODO(@bpeetz): Remove this once the legacy -> by-name migration is done. <2025-05-16>
       users.soispha = import ../../../home.legacy;
       extraSpecialArgs = {
         inherit
-          nixpkgs_open_prs
-          pkgsStable
-          sysLib
-          # extra information
           system
-          # bins
-          shell_library
-          qmk_firmware
-          # external deps
-          user_js
-          # modules
-          impermanence
-          nixVim
-          nix-index-database
-          arkenfox-nixos
           ;
       };
     };
diff --git a/modules/by-name/i3/i3bar-river/module.nix b/modules/by-name/i3/i3bar-river/module.nix
new file mode 100644
index 00000000..8a2203aa
--- /dev/null
+++ b/modules/by-name/i3/i3bar-river/module.nix
@@ -0,0 +1,197 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  cfg = config.soispha.programs.i3bar-river;
+
+  toColor = color:
+    if builtins.isString color
+    then lib.trivial.fromHexString color
+    else color;
+
+  substractColor = color_a: color_b: let
+    saturatingSub = a: b:
+      if a < b
+      then 0
+      else a - b;
+  in {
+    red = saturatingSub color_a.red color_b.red;
+    green = saturatingSub color_a.green color_b.green;
+    blue = saturatingSub color_a.blue color_b.blue;
+    alpha = saturatingSub color_a.alpha color_b.alpha;
+    inherit (color_a) __toString;
+  };
+
+  colorOption = red: green: blue: alpha:
+    lib.mkOption {
+      type = lib.types.submodule {
+        options = {
+          red = lib.mkOption {
+            type = lib.types.ints.between 0 255;
+            description = "The amount of red in this color";
+            default = toColor red;
+          };
+          green = lib.mkOption {
+            type = lib.types.ints.between 0 255;
+            description = "The amount of green in this color";
+            default = toColor green;
+          };
+          blue = lib.mkOption {
+            type = lib.types.ints.between 0 255;
+            description = "The amount of blue in this color";
+            default = toColor blue;
+          };
+          alpha = lib.mkOption {
+            type = lib.types.ints.between 0 255;
+            description = "The amount of alpha in this color";
+            default = toColor alpha;
+          };
+
+          __toString = lib.mkOption {
+            internal = true;
+
+            default = self: let
+              tH = num: let
+                converted = lib.trivial.toHexString num;
+              in
+                if builtins.stringLength converted == 1
+                then "0${converted}"
+                else assert (builtins.stringLength converted) == 2; converted;
+
+              output = "#${tH self.red}${tH self.green}${tH self.blue}${tH self.alpha}";
+            in
+              output;
+
+            description = "Convert this type to a string before use";
+          };
+        };
+      };
+
+      default = {
+        red = toColor red;
+        green = toColor green;
+        blue = toColor blue;
+        alpha = toColor alpha;
+      };
+
+      description = "The specific color to use for this name.";
+    };
+in {
+  options.soispha.programs.i3bar-river = {
+    enable = lib.mkEnableOption "i3bar-river";
+
+    package = lib.mkPackageOption pkgs "i3bar-river-patched" {};
+
+    colors = {
+      none = colorOption 00 00 00 00;
+
+      white = colorOption "ff" "ff" "ff" "ff";
+
+      blue = colorOption "99" "d1" "db" "ff";
+      green = colorOption "a6" "e3" "a1" "dd";
+      lavendar = colorOption "b4" "be" "fe" "dd";
+      mauve = colorOption "cb" "a6" "f7" "dd";
+      normal = colorOption "c6" "ce" "ef" "ff";
+      peach = colorOption "fa" "b3" "87" "dd";
+      sapphire = colorOption "74" "c7" "ec" "dd";
+      teal = colorOption "94" "e2" "d5" "dd";
+
+      light_gray = colorOption "58" "5b" "70" "ff";
+      gray = colorOption "45" "47" "5a" "ff";
+      dark_gray = colorOption "30" "34" "46" "ff";
+      bright_red = colorOption "e7" "82" "84" "ff";
+
+      vivid_burgundy = colorOption "9f" "1d" "35" "ff";
+
+      unfocused_offset = colorOption "33" "33" "33" "00";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    soispha.programs.river.init.backgroundStart = [cfg.package];
+
+    home-manager.users.soispha = {
+      programs.i3bar-river = {
+        enable = true;
+        inherit (cfg) package;
+
+        settings = {
+          theme = {
+            focused = {
+              # Colors
+              background = toString cfg.colors.none;
+              color = toString cfg.colors.white; # Only used, if blocks do not specify one
+              separator = toString cfg.colors.vivid_burgundy;
+
+              # Tag is set (but not focused or urgent)
+              tag_fg = toString cfg.colors.white;
+              tag_bg = toString cfg.colors.light_gray;
+
+              tag_urgent_fg = toString cfg.colors.white;
+              tag_urgent_bg = toString cfg.colors.bright_red;
+
+              tag_focused_fg = toString cfg.colors.white;
+              tag_focused_bg = toString cfg.colors.teal;
+
+              tag_inactive_fg = toString cfg.colors.white;
+              tag_inactive_bg = toString cfg.colors.none;
+
+              # Shop options
+              blend = true; # whether tags/blocks colors should blend with bar's background
+              hide_inactive_tags = false;
+              show_layout_name = false;
+              show_mode = true;
+              show_tags = true;
+            };
+
+            unfocused = {
+              hide_inactive_tags = true;
+
+              color = toString (substractColor cfg.colors.white cfg.colors.unfocused_offset);
+              separator = toString (substractColor cfg.colors.vivid_burgundy cfg.colors.unfocused_offset);
+
+              tag_fg = toString (substractColor cfg.colors.white cfg.colors.unfocused_offset);
+              tag_bg = toString (substractColor cfg.colors.light_gray cfg.colors.unfocused_offset);
+
+              tag_urgent_fg = toString (substractColor cfg.colors.white cfg.colors.unfocused_offset);
+              tag_urgent_bg = toString (substractColor cfg.colors.bright_red cfg.colors.unfocused_offset);
+
+              tag_focused_fg = toString (substractColor cfg.colors.white cfg.colors.unfocused_offset);
+              tag_focused_bg = toString cfg.colors.vivid_burgundy;
+
+              tag_inactive_fg = toString (substractColor cfg.colors.white cfg.colors.unfocused_offset);
+              tag_inactive_bg = toString (substractColor cfg.colors.none cfg.colors.unfocused_offset);
+            };
+          };
+
+          # The font and various sizes
+          font = "SauceCodePro Nerd Font Mono:pixelsize=26";
+          height = 24;
+          margin_top = 10;
+          margin_bottom = 0;
+          margin_left = 0;
+          margin_right = 0;
+          separator_width = 0;
+          tags_r = 10.0;
+          tags_padding = 10.0;
+          tags_margin = 5.0;
+          blocks_r = 6.0;
+          blocks_overlap = 0.0;
+
+          # Misc
+          position = "top"; # either "top" or "bottom"
+          layer = "overlay"; # one of "top", "overlay", "bottom" or "background"
+          invert_touchpad_scrolling = true;
+          start_hidden = false; # whether the bar is initially in the 'hidden' state
+
+          # WM-specific options
+          wm.river = {
+            max_tag = 9; # Show only the first nine tags
+          };
+        };
+      };
+    };
+  };
+}
diff --git a/modules/by-name/i3/i3status-rust/module.nix b/modules/by-name/i3/i3status-rust/module.nix
new file mode 100644
index 00000000..10cb4475
--- /dev/null
+++ b/modules/by-name/i3/i3status-rust/module.nix
@@ -0,0 +1,154 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  cfg = config.soispha.programs.i3status-rust;
+
+  mkScript = name: deps:
+    lib.getExe (pkgs.writeShellApplication {
+      inherit name;
+      text = builtins.readFile ./scripts/${name};
+
+      inheritPath = false;
+      runtimeInputs = deps;
+    });
+in {
+  options.soispha.programs.i3status-rust = {
+    enable = lib.mkEnableOption "i3status-rust";
+
+    package = lib.mkPackageOption pkgs "i3status-rust-patched" {};
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      programs.i3status-rust = {
+        enable = true;
+        inherit (cfg) package;
+
+        bars.default = {
+          settings = {
+            icons = {
+              icons = "material-nf";
+
+              overrides = {
+                cpu = [
+                  "󰍛" # nf-md-memory
+                ];
+                memory_mem = ""; # nf-fa-bars
+              };
+            };
+
+            theme = {
+              theme = "slick";
+
+              overrides = {
+                separator = "native";
+                alternating_tint_bg = "none";
+                alternating_tint_fg = "none";
+              };
+            };
+          };
+
+          blocks = [
+            {
+              block = "time";
+              format = " $timestamp.datetime(format:'%d/%m/%y (%a) %H:%M %:z') ";
+              interval = 60;
+            }
+
+            {
+              # TODO(@bpeetz): Switch to “music” when mpd gets mpris support  <2025-05-20>
+              block = "custom";
+              interval = "once";
+              persistent = true;
+              command = mkScript "mpd_song_name.sh" [pkgs.mpc pkgs.mpdpopm pkgs.coreutils];
+              hide_when_empty = true;
+              shell = "${lib.getExe pkgs.dash}";
+              format = " $text.str(max_width:60,rot_interval:0.5) ";
+            }
+
+            {
+              block = "sound";
+              driver = "pulseaudio";
+              headphones_indicator = true;
+            }
+
+            # System info
+            {
+              block = "cpu";
+            }
+            {
+              block = "memory";
+              format = " $icon $mem_used_percents{ ($swap_used_percents.eng(range:1..))|} ";
+            }
+            {
+              block = "amd_gpu";
+              format = " $icon $utilization (^icon_memory_mem $vram_used_percents) ";
+              error_format = "";
+            }
+
+            {
+              block = "net";
+              format = " ^icon_net_down $speed_down.eng(prefix:Ki) ^icon_net_up $speed_up.eng(prefix:Ki) ";
+            }
+            {
+              block = "privacy";
+              driver = [
+                {name = "v4l";}
+                {name = "pipewire";}
+              ];
+            }
+
+            {
+              block = "disk_space";
+              path = "/srv";
+              info_type = "used";
+              format = " $icon $used.eng(prefix:Gi) ($percentage) ";
+              backend = "btrfs";
+
+              # warn if 80 % is used, alert after 90 % used.
+              warning = 80;
+              alert = 90;
+            }
+            {
+              block = "backlight";
+              missing_format = "";
+            }
+            {
+              block = "battery";
+              format = " $icon $percentage{ $time_remaining.dur(hms:true, min_unit:m)|}{ $power|} ";
+              missing_format = "";
+            }
+
+            # {
+            #   block = "calendar";
+            #
+            #   source = {
+            #     calendars = ["user/calendar"];
+            #     auth = {
+            #       type = "unauthenticated";
+            #     };
+            #   };
+            # }
+            # {
+            #   block = "focused_window";
+            #   driver = "wlr_toplevel_management";
+            # }
+            # {
+            #   block = "maildir";
+            #   display_type = "new";
+            #   inboxes = ["~/.local/share/maildir/soispha/*"];
+            #   interval = 60;
+            #   threshold_critical = 10;
+            #   threshold_warning = 1;
+            # }
+          ];
+        };
+      };
+
+      programs.i3bar-river.settings.command = "${lib.getExe cfg.package} config-default.toml";
+    };
+  };
+}
diff --git a/modules/by-name/ya/yambar/scripts/mpd_song_name.sh b/modules/by-name/i3/i3status-rust/scripts/mpd_song_name.sh
index 5c288d1a..edd5da2c 100755
--- a/modules/by-name/ya/yambar/scripts/mpd_song_name.sh
+++ b/modules/by-name/i3/i3status-rust/scripts/mpd_song_name.sh
@@ -10,22 +10,29 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
 while true; do
     state="$(mpc status '%state%')"
 
     if [ "$state" = "playing" ]; then
         song="$(mpc --format '[[%artist% - ]%title%]|[%file%]' current)"
-        echo "playing|bool|true"
-        echo "song|string|$song :: $(mpc status "%currenttime%/%totaltime%")"
+        progress="$(mpc status "%currenttime%/%totaltime%")"
+        base_rating="$(mpdpopm rating get)"
+
+        rating=""
+        if [ "$base_rating" != 0 ]; then
+            rating=" ($base_rating)"
+        fi
+
+        echo "$song :: ${progress}${rating}"
     else
-        echo "playing|bool|false"
+        # The song has stopped, we are done displaying it.
+        echo ""
+
+        # Wait for a new song. (Or in this case for a new event.)
+        mpc idle
     fi
-    echo "" # commit
 
-    sleep 2
+    sleep 1
 done
 
 # vim: ft=sh
diff --git a/modules/by-name/ia/iamb/module.nix b/modules/by-name/ia/iamb/module.nix
new file mode 100644
index 00000000..ef46f5e0
--- /dev/null
+++ b/modules/by-name/ia/iamb/module.nix
@@ -0,0 +1,59 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  config,
+  lib,
+  libraries,
+  ...
+}: let
+  cfg = config.soispha.programs.iamb;
+in {
+  options.soispha.programs.iamb = {
+    enable = libraries.base.options.mkEnable "iamb";
+  };
+
+  config = lib.mkIf cfg.enable {
+    soispha.impermanence.userDirectories = [
+      ".config/iamb/profiles"
+    ];
+
+    home-manager.users.soispha = {
+      programs.iamb = {
+        enable = true;
+
+        settings = {
+          default_profile = "soispha";
+
+          profiles = {
+            soispha = {
+              user_id = "@soispha:vhack.eu";
+              url = "https://matrix.vhack.eu";
+            };
+          };
+
+          settings = {
+            username_display = "displayname";
+
+            notifications = {
+              enabled = true;
+            };
+
+            image_preview = {
+              size = {
+                height = 10;
+                width = 66;
+              };
+            };
+          };
+        };
+      };
+    };
+  };
+}
diff --git a/modules/by-name/im/impermanence/module.nix b/modules/by-name/im/impermanence/module.nix
index b7bbbe3d..78ad570f 100644
--- a/modules/by-name/im/impermanence/module.nix
+++ b/modules/by-name/im/impermanence/module.nix
@@ -10,6 +10,7 @@
 {
   config,
   lib,
+  modules,
   ...
 }: let
   cfg = config.soispha.impermanence;
@@ -30,8 +31,27 @@ in {
       }));
       description = "The directories to persist";
     };
+
+    userDirectories = lib.mkOption {
+      type = lib.types.listOf (lib.types.either lib.types.str (lib.types.submodule {
+        options = {
+          directory = lib.mkOption {
+            type = lib.types.str;
+          };
+          mode = lib.mkOption {
+            type = lib.types.str;
+          };
+        };
+      }));
+      default = [];
+      description = "The directories to persist";
+    };
   };
 
+  imports = [
+    modules.impermanence.nixosModules.impermanence
+  ];
+
   config = lib.mkIf cfg.enable {
     environment.persistence = {
       "/srv" = {
@@ -48,16 +68,13 @@ in {
             ".local/state/wireplumber"
 
             ".config/Signal"
-            ".config/Element"
-            ".config/iamb/profiles"
 
             ".cache"
-            ".mozilla/firefox"
 
             "media"
             "repos"
-            "school"
-          ];
+            "documents"
+          ] ++ cfg.userDirectories;
         };
 
         files = [
diff --git a/modules/by-name/le/less/module.nix b/modules/by-name/le/less/module.nix
index 0dd45a90..e3b47f13 100644
--- a/modules/by-name/le/less/module.nix
+++ b/modules/by-name/le/less/module.nix
@@ -31,7 +31,7 @@ in {
 
       programs.less = {
         enable = true;
-        keys =
+        config =
           builtins.readFile ./command.less
           + builtins.readFile ./line-edit.less
           + builtins.readFile ./env.less;
diff --git a/modules/by-name/lf/lf/commands/base.sh b/modules/by-name/lf/lf/commands/base.sh
index 99852c3e..7003d76c 100755
--- a/modules/by-name/lf/lf/commands/base.sh
+++ b/modules/by-name/lf/lf/commands/base.sh
@@ -41,11 +41,11 @@ prompt() {
 #   set -- "$@" "$file"
 # done < "$(echo "$fx" | tmp)"
 tmp() {
-    __base_tmp_temporary_file="$(mktemp --tmpdir="$__base_tmp_temporary_directory")"
+    __base_tmp_temporary_file="$(mktemp -t --tmpdir="$__base_tmp_temporary_directory" lf_commands_tmp_fun_XXXXXXXX )"
     cat >"$__base_tmp_temporary_file"
     echo "$__base_tmp_temporary_file"
 }
-__base_tmp_temporary_directory="$(mktemp --directory)"
+__base_tmp_temporary_directory="$(mktemp -t --directory lf_commands_tmp_fun_XXXXXXXXXXXX)"
 trap 'rm --recursive "$__base_tmp_temporary_directory"' EXIT
 
 # Run a lf command on the current lf client
diff --git a/modules/by-name/lf/lf/commands/default.nix b/modules/by-name/lf/lf/commands/default.nix
index f212a703..055bfa2c 100644
--- a/modules/by-name/lf/lf/commands/default.nix
+++ b/modules/by-name/lf/lf/commands/default.nix
@@ -48,20 +48,20 @@
 in {
   archive_compress = shell {
     name = "archive_compress";
-    dependencies = with pkgs; [
-      fzf
-      gnutar
-      xz
-      p7zip
-      zip
+    dependencies = [
+      pkgs.fzf
+      pkgs.gnutar
+      pkgs.xz
+      pkgs.p7zip
+      pkgs.zip
     ];
   };
   archive_decompress = pipe {
     name = "archive_decompress";
-    dependencies = with pkgs; [
-      gnutar
-      unzip
-      p7zip
+    dependencies = [
+      pkgs.gnutar
+      pkgs.unzip
+      pkgs.p7zip
     ];
   };
 
@@ -122,9 +122,10 @@ in {
   };
   set_wallpaper = pipe {
     name = "set_wallpaper";
-    dependencies = with pkgs; [
-      river # for `riverctl`
-      swaybg
+    dependencies = [
+      pkgs.river-classic # for `riverctl`
+      pkgs.swaybg
+      pkgs.procps
     ];
   };
 
@@ -139,16 +140,28 @@ in {
   };
   trash_clear = shell {
     name = "trash_clear";
-    dependencies = with pkgs; [conceal fzf gawk trashy gnused];
+    dependencies = [
+      pkgs.conceal
+      pkgs.fzf
+      pkgs.gawk
+      pkgs.trashy
+      pkgs.gnused
+    ];
   };
   trash_restore = shell {
     name = "trash_restore";
-    dependencies = with pkgs; [conceal fzf gawk trashy gnused];
+    dependencies = [
+      pkgs.conceal
+      pkgs.fzf
+      pkgs.gawk
+      pkgs.trashy
+      pkgs.gnused
+    ];
   };
 
   view_file = async {
     name = "view_file";
-    dependencies = with pkgs; [file];
+    dependencies = [pkgs.file];
     keepPath = true;
   };
 }
diff --git a/modules/by-name/lf/lf/commands/scripts/set_wallpaper.sh b/modules/by-name/lf/lf/commands/scripts/set_wallpaper.sh
index ba887032..6311031e 100755
--- a/modules/by-name/lf/lf/commands/scripts/set_wallpaper.sh
+++ b/modules/by-name/lf/lf/commands/scripts/set_wallpaper.sh
@@ -19,8 +19,8 @@ fs="$fs"
 # shellcheck disable=SC2269
 id="$id"
 
-pid="$(pgrep swaybg)"
-[ -n "$pid" ] && kill "$pid"
+# Kill all previous instances
+pkill swaybg
 
 # We cannot control the available commands for river.
 # Thus we ensure that it can correctly start `swaybg`
diff --git a/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix b/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix
index e30aab3e..bc8abf8f 100644
--- a/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix
+++ b/modules/by-name/lf/lf/ctpv/prev/application/pdf/default.nix
@@ -14,7 +14,7 @@
       matches.mime = ["application/pdf"];
       priority = 1;
       dependencies = [
-        pkgs.poppler_utils # for `pdftoppm`
+        pkgs.poppler-utils # for `pdftoppm`
         pkgs.chafa
         pkgs.gnused
         pkgs.coreutils
diff --git a/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh b/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh
index 324a2170..22894ca2 100644
--- a/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh
+++ b/modules/by-name/lf/lf/ctpv/prev/audio/audio.sh
@@ -19,7 +19,7 @@ audio() {
     ffmpegthumbnailer -i "$f" -s 0 -q 5 -t 10 -o "$cache_f" 2>/dev/null
 }
 
-x="$(ffmpeg -hide_banner -i "$f" 2>&1)"
+x="$(ffprobe -hide_banner "$f" 2>&1)"
 printf '%s\n' "$x"
 y=$((y + $(printf '%s\n' "$x" | wc -l)))
 
diff --git a/modules/by-name/lf/lf/ctpv/prev/text/default.nix b/modules/by-name/lf/lf/ctpv/prev/text/default.nix
index edb6e09d..ca042646 100644
--- a/modules/by-name/lf/lf/ctpv/prev/text/default.nix
+++ b/modules/by-name/lf/lf/ctpv/prev/text/default.nix
@@ -21,7 +21,10 @@
     bat = {
       priority = 0;
       previewer = ./bat.sh;
-      matches.mime = ["text/*"];
+      matches.mime = [
+        "text/*"
+        "application/postscript"
+      ];
       dependencies = [
         pkgs.bat
       ];
diff --git a/modules/by-name/lf/lf/keybindings/default.nix b/modules/by-name/lf/lf/keybindings/default.nix
index d4c2a6a3..fbc33f6f 100644
--- a/modules/by-name/lf/lf/keybindings/default.nix
+++ b/modules/by-name/lf/lf/keybindings/default.nix
@@ -94,7 +94,7 @@
   gc = "cd ~/.config";
   gl = "cd ~/.local";
   gE = "cd /etc";
-  gd = "cd ${downloadDir}";
+  gD = "cd ${downloadDir}";
 
   "gU." = "cd /usr";
   gUs = " cd /usr/share";
diff --git a/modules/by-name/lf/lf/module.nix b/modules/by-name/lf/lf/module.nix
index 2e6669e8..8dfd0c52 100644
--- a/modules/by-name/lf/lf/module.nix
+++ b/modules/by-name/lf/lf/module.nix
@@ -19,6 +19,8 @@
   commands = import ./commands {inherit pkgs sysLib shell_library system;};
   keybindings = import ./keybindings {inherit (cfg.keymaps) uid downloadDir;};
 
+  packages = import ./wrappers {inherit pkgs;};
+
   cfg = config.soispha.programs.lf;
 in {
   imports = [
@@ -58,6 +60,11 @@ in {
         "lf/colors".source = ./colors;
       };
 
+      programs.zsh.shellAliases = {
+        ll = ". ${lib.getExe packages.ll}";
+        lm = ". ${lib.getExe packages.lm}";
+      };
+
       programs.lf = {
         enable = true;
 
@@ -93,8 +100,8 @@ in {
           # and keep running through `autoquit = false`.
           # (Otherwise, the remote command is silently dropped: https://github.com/gokcehan/lf/issues/495)
           &{{
-            tmp="$(mktemp)"
-            ${lib.getExe pkgs.lf-make-map} --depth 4 generate ~/media ~/repos ~/school >"$tmp"
+            tmp="$(mktemp -t lf_make_map_dynamic_mapping_source_XXXXX)"
+            ${lib.getExe pkgs.lf-make-map} --depth 4 generate ~/media ~/repos ~/documents >"$tmp"
 
             lf -remote "send $id source $tmp"
             sleep 1
diff --git a/modules/by-name/lf/lf/wrappers/default.nix b/modules/by-name/lf/lf/wrappers/default.nix
new file mode 100644
index 00000000..7257a66e
--- /dev/null
+++ b/modules/by-name/lf/lf/wrappers/default.nix
@@ -0,0 +1,4 @@
+{pkgs}: {
+  ll = pkgs.callPackage ./ll {};
+  lm = pkgs.callPackage ./lm {};
+}
diff --git a/pkgs/by-name/ll/ll/package.nix b/modules/by-name/lf/lf/wrappers/ll/default.nix
index 6e4ee336..6e4ee336 100644
--- a/pkgs/by-name/ll/ll/package.nix
+++ b/modules/by-name/lf/lf/wrappers/ll/default.nix
diff --git a/pkgs/by-name/ll/ll/ll.sh b/modules/by-name/lf/lf/wrappers/ll/ll.sh
index e012cffa..ce29fd97 100755
--- a/pkgs/by-name/ll/ll/ll.sh
+++ b/modules/by-name/lf/lf/wrappers/ll/ll.sh
@@ -10,7 +10,7 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-last_directory="$(mktemp)"
+last_directory="$(mktemp -t ll_last_directory_XXXXXXX)"
 cleanup() {
     rm "$last_directory"
 }
diff --git a/pkgs/by-name/lm/lm/package.nix b/modules/by-name/lf/lf/wrappers/lm/default.nix
index 42bdc687..42bdc687 100644
--- a/pkgs/by-name/lm/lm/package.nix
+++ b/modules/by-name/lf/lf/wrappers/lm/default.nix
diff --git a/pkgs/by-name/lm/lm/lm.sh b/modules/by-name/lf/lf/wrappers/lm/lm.sh
index 71213721..71213721 100755
--- a/pkgs/by-name/lm/lm/lm.sh
+++ b/modules/by-name/lf/lf/wrappers/lm/lm.sh
diff --git a/modules/by-name/lo/locale/keymaps/dvorak_modified.xkb b/modules/by-name/lo/locale/keymaps/dvorak_modified.xkb
index 63f5d4fb..3893e605 100644
--- a/modules/by-name/lo/locale/keymaps/dvorak_modified.xkb
+++ b/modules/by-name/lo/locale/keymaps/dvorak_modified.xkb
@@ -2,10 +2,18 @@ partial alphanumeric_keys
 xkb_symbols "dvorak-modified" {
     name[Group1]= "Dvorak English with additional keys";
 
+    // German
+    key <AC01>  {[  a,  A,  adiaeresis,  Adiaeresis]};
     key <AC02>  {[  o,  O,  odiaeresis,  Odiaeresis]};
     key <AC04>  {[  u,  U,  udiaeresis,  Udiaeresis]};
-    key <AC01>  {type[Group1]="EIGHT_LEVEL",
-                 [  a,  A,  adiaeresis,  Adiaeresis,  aring,  Aring]};
+
+    // Missing Swedish letter (the rest is in the German ones)
+    key <AC07>  {[  h,  H,  aring,  Aring]};
+
+    // Slovenian
+    key <AC10> {[  s,  S,  scaron,  Scaron]};
+    key <AD08> {[  c,  C,  ccaron,  Ccaron]};
+    key <AB10> {[  z,  Z,  zcaron,  Zcaron]};
 
 
     include "us(dvorak)"
diff --git a/modules/by-name/lo/locale/module.nix b/modules/by-name/lo/locale/module.nix
index 17096731..3c9c646c 100644
--- a/modules/by-name/lo/locale/module.nix
+++ b/modules/by-name/lo/locale/module.nix
@@ -37,10 +37,10 @@ in {
     };
 
     i18n = {
-      defaultLocale = "en_CA.UTF-8";
+      defaultLocale = "sv_SE.UTF-8";
       extraLocaleSettings = {
-        LANGUAGE = "en_CA:en_US:en";
-        LC_TIME = "en_DK.UTF-8";
+        LANGUAGE = "sv_SE:en_CA:en_US:en";
+        LC_TIME = "sv_SE.UTF-8";
         LC_COLLATE = "C.UTF-8";
       };
     };
diff --git a/modules/by-name/ma/mako/module.nix b/modules/by-name/ma/mako/module.nix
new file mode 100644
index 00000000..1630d2d0
--- /dev/null
+++ b/modules/by-name/ma/mako/module.nix
@@ -0,0 +1,81 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  cfg = config.soispha.services.mako;
+
+  iconPath = "${pkgs.gruvbox-dark-icons-gtk.overrideAttrs (prev: final: {
+    # Remove unused dependencies
+    propagatedBuildInputs = [];
+  })}/share/icons/oomox-gruvbox-dark";
+in {
+  options.soispha.services.mako = {
+    enable = lib.mkEnableOption "mako";
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      services.mako = {
+        enable = true;
+
+        # See mako(5)
+        settings = {
+          max-history = 5;
+          sort = "-time";
+
+          background-color = "#2e3440";
+          border-color = "#88c0d0";
+          border-radius = 25;
+          border-size = 2;
+          default-timeout = 5000;
+          font = "Source Code Pro 10";
+          group-by = "body";
+          height = 500;
+          icon-path = iconPath;
+          icons = true;
+          ignore-timeout = false;
+          layer = "overlay";
+          markup = true;
+          max-icon-size = 64;
+          width = 500;
+
+          "urgency=low" = {
+            border-color = "#cccccc";
+          };
+
+          "urgency=normal" = {
+            border-color = "#d08770";
+          };
+
+          "urgency=high" = {
+            border-size = 3;
+            border-color = "#bf616a";
+            default-timeout = 0;
+          };
+
+          "urgency=critical" = {
+            border-size = 4;
+            border-color = "#bf616a";
+            default-timeout = 0;
+          };
+
+          "category=mpd" = {
+            default-timeout = 2000;
+            group-by = "category";
+          };
+        };
+      };
+    };
+  };
+}
diff --git a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/pylyzer.nix b/modules/by-name/me/mergiraf/module.nix
index 47e8de7a..474a0ae3 100644
--- a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/pylyzer.nix
+++ b/modules/by-name/me/mergiraf/module.nix
@@ -10,19 +10,20 @@
 {
   config,
   lib,
-  pkgs,
+  libraries,
   ...
 }: let
-  cfg = config.soispha.programs.nvim;
+  cfg = config.soispha.programs.mergiraf;
 in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    extraConfigLuaPost =
-      /*
-      lua
-      */
-      ''
-        require('lspconfig').pylyzer.setup{}
-      '';
-    extraPackages = with pkgs; [pylyzer];
+  options.soispha.programs.mergiraf = {
+    enable = libraries.base.options.mkEnable "mergiraf";
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      programs.mergiraf = {
+        enable = true;
+      };
+    };
   };
 }
diff --git a/modules/by-name/mp/mpd/module.nix b/modules/by-name/mp/mpd/module.nix
index b7c7ab5a..37c648c6 100644
--- a/modules/by-name/mp/mpd/module.nix
+++ b/modules/by-name/mp/mpd/module.nix
@@ -71,6 +71,7 @@ in {
 
         extraConfig = ''
           metadata_to_use "artist,album,title,track,name,genre,date,composer,performer,disc,comment"
+
           # Updated by the beets `mpdupdate` plugin
           auto_update "no"
 
@@ -82,6 +83,8 @@ in {
           replaygain "track"
           replaygain_limit "yes"
 
+          sticker_file "${cfg.directories.data}/sticker.sql"
+
           #database {
           #       plugin "simple"
           #       path "~/.local/share/mpd/db
diff --git a/modules/by-name/mp/mpdpopm/module.nix b/modules/by-name/mp/mpdpopm/module.nix
new file mode 100644
index 00000000..3524554c
--- /dev/null
+++ b/modules/by-name/mp/mpdpopm/module.nix
@@ -0,0 +1,65 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  config,
+  pkgs,
+  libraries,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.services.mpdpopm;
+
+  settingsFormat = pkgs.formats.json {};
+in {
+  options.soispha.services.mpdpopm = {
+    enable = libraries.base.options.mkEnable "mpdpopm";
+
+    settings = lib.mkOption {
+      # Setting this type allows for correct merging behavior
+      inherit (settingsFormat) type;
+      default = {};
+      description = ''
+        Configuration for foo, see
+        <link xlink:href="https://example.com/docs/foo"/>
+        for supported settings.
+      '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    soispha.services.mpdpopm.settings = {
+      version = "1";
+      log = "${config.home-manager.users.soispha.xdg.dataHome}/mpdpopm/log";
+
+      conn.Local = {
+        path = config.home-manager.users.soispha.home.sessionVariables.MPD_HOST;
+      };
+
+      local_music_dir = config.soispha.services.mpd.directories.music;
+    };
+
+    home-manager.users.soispha = {
+      systemd.user.services.mpdpopm = {
+        Unit = {
+          Description = "mpdpopm ratings and playcounts for MPD";
+          Requires = ["mpd.service"];
+          After = ["mpd.service"];
+        };
+
+        Service = {
+          Restart = "on-failure";
+          ExecStart = "${lib.getExe' pkgs.mpdpopm "mpdpopmd"} --config ${settingsFormat.generate "config.json" cfg.settings}";
+        };
+
+        Install = {WantedBy = ["default.target"];};
+      };
+    };
+  };
+}
diff --git a/modules/by-name/mp/mpv/module.nix b/modules/by-name/mp/mpv/module.nix
index 4250edb7..4416b295 100644
--- a/modules/by-name/mp/mpv/module.nix
+++ b/modules/by-name/mp/mpv/module.nix
@@ -29,11 +29,8 @@ in {
         "Shift+q" = "quit-watch-later 1";
       };
       config = {
-        # uosc provides seeking & volume indicators (via flash-timeline and flash-volume commands)
-        # if you decide to use them, you don't need osd-bar
-        osd-bar = false;
+        osd-bar = true;
 
-        # uosc will draw its own window controls and border if you disable window border
         border = false;
       };
       scriptOpts = {
@@ -41,272 +38,6 @@ in {
           scalewindowed = 0.8;
           hidetimeout = 300;
         };
-        uosc = {
-          # Display style of current position. available: line, bar
-          timeline_style = "line";
-
-          # Line display style config
-          timeline_line_width = 2;
-
-          # Timeline size when fully expanded, in pixels, 0 to disable
-          timeline_size = 40;
-
-          # Comma separated states when element should always be fully visible.
-          # Available: paused, audio, image, video, idle, windowed, fullscreen
-          timeline_persistency = "";
-
-          # Top border of background color to help visually separate timeline from video
-          timeline_border = 1;
-
-          # When scrolling above timeline, wheel will seek by this amount of seconds.
-          # Default uses fast seeking. Add `!` suffix to enable exact seeks. Example: `5!`
-          timeline_step = 5;
-
-          # Render cache indicators for streaming content
-          timeline_cache = true;
-
-          # When to display an always visible progress bar (minimized timeline). Can be: windowed, fullscreen, always, never
-          # Can also be toggled on demand with `toggle-progress` command.
-          progress = "windowed";
-          progress_size = 2;
-          progress_line_width = 20;
-
-          # A comma delimited list of controls above the timeline. Set to `never` to disable.
-          # Parameter spec: enclosed in `{}` means value, enclosed in `[]` means optional
-          # Full item syntax: `[<[!]{disposition1}[,[!]{dispositionN}]>]{element}[:{paramN}][#{badge}[>{limit}]][?{tooltip}]`
-          # Common properties:
-          #   `{icon}` - parameter used to specify an icon name (example: `face`)
-          #            - pick here: https://fonts.google.com/icons?icon.platform=web&icon.set=Material+Icons&icon.style=Rounded
-          # `{element}`s and their parameters:
-          #   `{shorthand}` - preconfigured shorthands:
-          #        `play-pause`, `menu`, `subtitles`, `audio`, `video`, `playlist`,
-          #        `chapters`, `editions`, `stream-quality`, `open-file`, `items`,
-          #        `next`, `prev`, `first`, `last`, `audio-device`, `fullscreen`,
-          #        `loop-playlist`, `loop-file`, `shuffle`, `autoload`
-          #   `speed[:{scale}]` - display speed slider, [{scale}] - factor of controls_size, default: 1.3
-          #   `command:{icon}:{command}` - button that executes a {command} when pressed
-          #   `toggle:{icon}:{prop}[@{owner}]` - button that toggles mpv property. shorthand for yes/no cycle below
-          #   `cycle:{default_icon}:{prop}[@{owner}]:{value1}[={icon1}][!]/{valueN}[={iconN}][!]`
-          #       - button that cycles mpv property between values, each optionally having different icon and active flag
-          #       - presence of `!` at the end will style the button as active
-          #       - `{owner}` is the name of a script that manages this property if any. Set to `uosc` to tap into uosc options.
-          #   `gap[:{scale}]` - display an empty gap
-          #       {scale} - factor of controls_size, default: 0.3
-          #   `space` - fills all available space between previous and next item, useful to align items to the right
-          #           - multiple spaces divide the available space among themselves, which can be used for centering
-          #   `button:{name}` - button whose state, look, and click action are managed by external script
-          # Item visibility control:
-          #   `<[!]{disposition1}[,[!]{dispositionN}]>` - optional prefix to control element's visibility
-          #   - `{disposition}` can be one of:
-          #     - `idle` - true if mpv is in idle mode (no file loaded)
-          #     - `image` - true if current file is a single image
-          #     - `audio` - true for audio only files
-          #     - `video` - true for files with a video track
-          #     - `has_many_video` - true for files with more than one video track
-          #     - `has_image` - true for files with a cover or other image track
-          #     - `has_audio` - true for files with an audio track
-          #     - `has_many_audio` - true for files with more than one audio track
-          #     - `has_sub` - true for files with an subtitle track
-          #     - `has_many_sub` - true for files with more than one subtitle track
-          #     - `has_many_edition` - true for files with more than one edition
-          #     - `has_chapter` - true for files with chapter list
-          #     - `stream` - true if current file is read from a stream
-          #     - `has_playlist` - true if current playlist has 2 or more items in it
-          #   - prefix with `!` to negate the required disposition
-          #   Examples:
-          #     - `<stream>stream-quality` - show stream quality button only for streams
-          #     - `<has_audio,!audio>audio` - show audio tracks button for all files that have
-          #                                   an audio track, but are not exclusively audio only files
-          # Place `#{badge}[>{limit}]` after the element params to give it a badge. Available badges:
-          #   `sub`, `audio`, `video` - track type counters
-          #   `{mpv_prop}` - any mpv prop that makes sense to you: https://mpv.io/manual/master/#property-list
-          #                - if prop value is an array it'll display its size
-          #   `>{limit}` will display the badge only if it's numerical value is above this threshold.
-          #   Example: `#audio>1`
-          # Place `?{tooltip}` after the element config to give it a tooltip.
-          # Example implementations:
-          #   menu = command:menu:script-binding uosc/menu-blurred?Menu
-          #   subtitles = command:subtitles:script-binding uosc/subtitles#sub?Subtitles
-          #   fullscreen = cycle:crop_free:fullscreen:no/yes=fullscreen_exit!?Fullscreen
-          #   loop-playlist = cycle:repeat:loop-playlist:no/inf!?Loop playlist
-          #   toggle:{icon}:{prop} = cycle:{icon}:{prop}:no/yes!
-          controls = "menu,gap,subtitles,<has_many_audio>audio,<has_many_video>video,<has_many_edition>editions,<stream>stream-quality,gap,space,speed,space,shuffle,loop-playlist,loop-file,gap,prev,items,next,gap,fullscreen";
-          controls_size = 32;
-          controls_margin = 8;
-          controls_spacing = 2;
-          controls_persistency = "";
-
-          # Where to display volume controls: none, left, right
-          volume = "right";
-          volume_size = 40;
-          volume_border = 1;
-          volume_step = 1;
-          volume_persistency = "";
-
-          # Playback speed widget: mouse drag or wheel to change, click to reset
-          speed_step = 0.1;
-          speed_step_is_factor = false;
-          speed_persistency = "";
-
-          # Controls all menus, such as context menu, subtitle loader/selector, etc
-          menu_item_height = 36;
-          menu_min_width = 260;
-          menu_padding = 4;
-
-          # Determines if `/` or `ctrl+f` is required to activate the search, or if typing
-          # any text is sufficient.
-          # When enabled, you can no longer toggle a menu off with the same key that opened it, if the key is a unicode character.
-          menu_type_to_search = true;
-
-          # Top bar with window controls and media title
-          # Can be: never, no-border, always
-          top_bar = "never";
-          top_bar_size = 40;
-          # Can be: `no` (hide), left or right
-          top_bar_controls = false;
-          # Can be: `no` (hide), `yes` (inherit title from mpv.conf), or a custom template string
-          top_bar_title = false;
-          # Template string to enable alternative top bar title. If alt title matches main title,
-          # it'll be hidden. Tip: use `${media-title}` for main, and `${filename}` for alt title.
-          top_bar_alt_title = "";
-          # Can be:
-          #   `below`  => display alt title below the main one
-          #   `toggle` => toggle the top bar title text between main and alt by clicking
-          #               the top bar, or calling `toggle-title` binding
-          top_bar_alt_title_place = "below";
-          # Flash top bar when any of these file types is loaded. Available: audio,video,image,chapter
-          top_bar_flash_on = "video,audio";
-          top_bar_persistency = "";
-
-          # Window border drawn in no-border mode
-          window_border_size = 1;
-
-          # If there's no playlist and file ends, load next file in directory
-          # Uses `load_types` config below to determine what type of file to load next.
-          # When enabled, usoc will set mpv config `keep-open` to `yes`, and `keep-open-pause` to `no`.
-          autoload = false;
-          # Enable uosc's playlist/directory shuffle mode
-          # This simply makes the next selected playlist or directory item be random, just
-          # like any other player in the world. It also has an easily togglable control button.
-          shuffle = false;
-
-          # Scale the interface by this factor
-          scale = 1;
-          # Scale in fullscreen
-          scale_fullscreen = 1.3;
-          # Adjust the text scaling to fit your font
-          font_scale = 1;
-          # Border of text and icons when drawn directly on top of video
-          text_border = 1.2;
-          # Border radius of buttons, menus, and all other rectangles
-          border_radius = 4;
-          # A comma delimited list of color overrides in RGB HEX format. Defaults:
-          # foreground=ffffff,foreground_text=000000,background=000000,background_text=ffffff,curtain=111111,success=a5e075,error=ff616e
-          color = "";
-          # A comma delimited list of opacity overrides for various UI element backgrounds and shapes.
-          # This does not affect any text, which is always rendered fully opaque. Defaults:
-          # timeline=0.9,position=1,chapters=0.8,slider=0.9,slider_gauge=1,controls=0,speed=0.6,menu=1,submenu=0.4,border=1,title=1,tooltip=1,thumbnail=1,curtain=0.8,idle_indicator=0.8,audio_indicator=0.5,buffering_indicator=0.3,playlist_position=0.8
-          opacity = "";
-
-          # A comma delimited list of features to refine at a cost of some performance impact.
-          # text_width - Use a more accurate text width measurement that measures each text string individually
-          #              instead of just measuring the width of known letters once and adding them up.
-          # sorting    - Use filename sorting that handles non-english languages better, especially asian ones.
-          #              At the moment, this is only available on windows, and has no effect on other platforms.
-          refine = "";
-
-          # Duration of animations in milliseconds
-          animation_duration = 100;
-
-          # Execute command for background clicks shorter than this number of milliseconds, 0 to disable
-          # Execution always waits for `input-doubleclick-time` to filter out double-clicks
-          click_threshold = 0;
-          click_command = "cycle pause; script-binding uosc/flash-pause-indicator";
-
-          # Flash duration in milliseconds used by `flash-{element}` commands
-          flash_duration = 1000;
-
-          # Distances in pixels below which elements are fully faded in/out
-          proximity_in = 40;
-          proximity_out = 120;
-
-          # Use only bold font weight throughout the whole UI
-          font_bold = false;
-
-          # One of `total`, `playtime-remaining` (scaled by the current speed), `time-remaining` (remaining length of file)
-          destination_time = "playtime-remaining";
-
-          # Display sub second fraction in timestamps up to this precision
-          time_precision = 0;
-
-          # Display stream's buffered time in timeline if it's lower than this amount of seconds, 0 to disable
-          buffered_time_threshold = 60;
-
-          # Hide UI when mpv autohides the cursor. Timing is controlled by `cursor-autohide` in `mpv.conf` (in milliseconds).
-          autohide = true;
-
-          # Can be: flash, static, manual (controlled by flash-pause-indicator and decide-pause-indicator commands)
-          pause_indicator = "static";
-
-          # Sizes to list in stream quality menu
-          stream_quality_options = "4320,2160,1440,1080,720,480,360,240,144";
-
-          # Types to identify media files
-          video_types = "3g2,3gp,asf,avi,f4v,flv,h264,h265,m2ts,m4v,mkv,mov,mp4,mp4v,mpeg,mpg,ogm,ogv,rm,rmvb,ts,vob,webm,wmv,y4m";
-          audio_types = "aac,ac3,aiff,ape,au,cue,dsf,dts,flac,m4a,mid,midi,mka,mp3,mp4a,oga,ogg,opus,spx,tak,tta,wav,weba,wma,wv";
-          image_types = "apng,avif,bmp,gif,j2k,jp2,jfif,jpeg,jpg,jxl,mj2,png,svg,tga,tif,tiff,webp";
-          subtitle_types = "aqt,ass,gsub,idx,jss,lrc,mks,pgs,pjs,psb,rt,sbv,slt,smi,sub,sup,srt,ssa,ssf,ttxt,txt,usf,vt,vtt";
-          playlist_types = "m3u,m3u8,pls,url,cue";
-
-          # Type pools used by file navigation and `autoload` to determine what type of file to load next
-          # Available: video,audio,image,playlist,same. `same` means the same type pool (not just extension) as currently open file.
-          load_types = "video,audio,image";
-
-          # Default open-file menu directory. Use `{drives}` to open drives menu on windows (defaults to `/` on unix).
-          default_directory = "~/";
-
-          # List hidden files when reading directories. Due to environment limitations, this currently only hides
-          # files starting with a dot. Doesn't hide hidden files on windows (we have no way to tell they're hidden).
-          show_hidden_files = false;
-
-          # Move files to trash (recycle bin) when deleting files. Dependencies:
-          # - Linux: `sudo apt install trash-cli`
-          # - MacOS: `brew install trash`
-          use_trash = false;
-
-          # Adjusted osd margins based on the visibility of UI elements
-          adjust_osd_margins = true;
-
-          # Adds chapter range indicators to some common chapter types.
-          # Additionally to displaying the start of the chapter as a diamond icon on top of the timeline,
-          # the portion of the timeline of that chapter range is also colored based on the config below.
-          #
-          # The syntax is a comma-delimited list of `{type}:{color}` pairs, where:
-          # `{type}` => range type. Currently supported ones are:
-          #   - `openings`, `endings` => anime openings/endings
-          #   - `intros`, `outros` => video intros/outros
-          #   - `ads` => segments created by sponsor-block software like https://github.com/po5/mpv_sponsorblock
-          # `{color}` => an RGB(A) HEX color code (`rrggbb`, or `rrggbbaa`)
-          #
-          # To exclude marking any of the range types, simply remove them from the list.
-          chapter_ranges = "openings:30abf964,endings:30abf964,ads:c54e4e80";
-
-          # Add alternative lua patterns to identify beginnings of simple chapter ranges (except for `ads`)
-          # Syntax: `{type}:{pattern}[,{patternN}][;{type}:{pattern}[,{patternN}]]`
-          chapter_range_patterns = "openings:オープニング;endings:エンディング";
-
-          # Localization language priority from highest to lowest.
-          # Also controls what languages are fetched by `download-subtitles` menu.
-          # Built in languages can be found in `uosc/intl`.
-          # `slang` is a keyword to inherit values from `--slang` mpv config.
-          # Supports paths to custom json files: `languages=~~/custom.json,slang,en`
-          languages = "slang,en";
-
-          # A comma separated list of element IDs to disable. Available IDs:
-          #   window_border, top_bar, timeline, controls, volume,
-          #   idle_indicator, audio_indicator, buffering_indicator, pause_indicator
-          disable_elements = "";
-        };
         thumbfast = {
           hwdec = true;
           network = false;
@@ -315,9 +46,8 @@ in {
           max_width = 250;
         };
       };
-      scripts = with pkgs.mpvScripts; [
-        uosc
-        thumbfast
+      scripts = [
+        pkgs.mpvScripts.thumbfast
       ];
     };
   };
diff --git a/modules/by-name/ms/msr/module.nix b/modules/by-name/ms/msr/module.nix
new file mode 100644
index 00000000..521b3a40
--- /dev/null
+++ b/modules/by-name/ms/msr/module.nix
@@ -0,0 +1,17 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.msr;
+in {
+  options.soispha.msr = {
+    enable = (lib.mkEnableOption "msr") // {default = config.hardware.cpu.x86.msr.enable;};
+  };
+
+  config = lib.mkIf cfg.enable {
+    users = {
+      groups.msr.gid = config.soispha.constants.ids.gids.msr;
+    };
+  };
+}
diff --git a/modules/by-name/ne/networking/module.nix b/modules/by-name/ne/networking/module.nix
index 6f8633e8..075a1a5a 100644
--- a/modules/by-name/ne/networking/module.nix
+++ b/modules/by-name/ne/networking/module.nix
@@ -99,10 +99,18 @@ in {
         soispha.impermanence.directories = [
           "/etc/NetworkManager"
         ];
-
-        users.users."${cfg.userName}".extraGroups = [
-          "networkmanager" # allows to configure NetworkManager as this user
-        ];
+        users = {
+          users = {
+            "${cfg.userName}".extraGroups = [
+              "networkmanager" # allows to configure NetworkManager as this user
+            ];
+            nm-iodine.uid = config.soispha.constants.ids.uids.nm-iodine;
+            wpa_supplicant.uid = config.soispha.constants.ids.uids.wpa_supplicant;
+          };
+          groups = {
+            wpa_supplicant.gid = config.soispha.constants.ids.gids.wpa_supplicant;
+          };
+        };
       })
     ]);
 }
diff --git a/modules/by-name/zs/zsh/config/command_not_found/command_not_found.sh b/modules/by-name/ni/nix-index/command_not_found.sh
index 5f7461e6..579f9db4 100644
--- a/modules/by-name/zs/zsh/config/command_not_found/command_not_found.sh
+++ b/modules/by-name/ni/nix-index/command_not_found.sh
@@ -26,12 +26,12 @@ command_not_found_handle() {
 
     toplevel=nixpkgs # nixpkgs should always be available even in NixOS
     cmd="$1"
-    attrs=$(nix-locate --minimal --no-group --type x --type s --top-level --whole-name --at-root "/bin/$cmd")
+    attrs=$(nix-locate --minimal --no-group --type x --type s --whole-name --at-root "/bin/$cmd")
     len=$(if [ -n "$attrs" ]; then echo "$attrs" | wc -l; else echo 0; fi)
 
     case "$len" in
     0)
-        eprintln "$cmd: command not found"
+        printf "%s: command not found\n" "$cmd" >&2
         ;;
     1)
         # If only one package provides this, then we can invoke it
@@ -58,7 +58,7 @@ EOF
 The program '$cmd' is currently not installed. It is provided by
 several packages. You can run it once with:
 EOF
-        awk --assign=toplevel="$toplevel" 'BEGIN{counter=0} {printf("%3s)", counter); printf("  nix shell %s#%s\n", toplevel, $1); counter+=1}' "$(ptmp "$attrs")"
+        echo "$attrs" | awk --assign=toplevel="$toplevel" 'BEGIN{counter=0} {printf("%3s)", counter); printf("  nix shell %s#%s\n", toplevel, $1); counter+=1}'
         ;;
     esac
 
diff --git a/modules/by-name/ni/nix-index/module.nix b/modules/by-name/ni/nix-index/module.nix
new file mode 100644
index 00000000..5ddaece3
--- /dev/null
+++ b/modules/by-name/ni/nix-index/module.nix
@@ -0,0 +1,44 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  config,
+  lib,
+  modules,
+  ...
+}: let
+  cfg = config.soispha.programs.nix-index;
+in {
+  options.soispha.programs.nix-index = {
+    enable = lib.mkEnableOption "nix-index";
+  };
+
+  config = lib.mkIf cfg.enable {
+    soispha.programs.zsh.integrations.nix-index = ./command_not_found.sh;
+    home-manager.users.soispha = {
+      imports = [
+        modules.nix-index-database.homeModules.nix-index
+      ];
+
+      programs.nix-index = {
+        enable = true;
+        symlinkToCacheHome = true;
+
+        # Handled by myself (and the script is overridden)
+        enableBashIntegration = false;
+        enableZshIntegration = false;
+        enableFishIntegration = false;
+      };
+
+      programs.nix-index-database = {
+        comma.enable = false;
+      };
+    };
+  };
+}
diff --git a/modules/by-name/ni/nix/module.nix b/modules/by-name/ni/nix/module.nix
index 29ba4080..2b91f59b 100644
--- a/modules/by-name/ni/nix/module.nix
+++ b/modules/by-name/ni/nix/module.nix
@@ -10,24 +10,23 @@
 {
   pkgs,
   # flakes
-  nixpkgs_as_input,
-  templates,
   self,
   system,
+  externalDependencies,
   ...
 }: {
   # TODO(@bpeetz): Modularize <2025-02-08>
 
   nix = {
-    package = pkgs.lix;
+    package = pkgs.lixPackageSets.latest.lix;
 
     # Disable nix channels  (this is a remnant of old days)
     channel.enable = false;
 
     registry = {
-      nixpkgs.flake = nixpkgs_as_input;
+      nixpkgs.flake = self.inputs.nixpkgs;
       n.flake =
-        nixpkgs_as_input
+        self.inputs.nixpkgs
         // {
           # Otherwise nixpkgs's config and overlays are not available:
 
@@ -36,7 +35,7 @@
           legacyPackages."${system}" = pkgs;
         };
 
-      t.flake = templates;
+      t.flake = externalDependencies.templates;
 
       my_flake.flake = self;
       m.flake = self;
diff --git a/modules/by-name/ni/nixos-option/module.nix b/modules/by-name/ni/nixos-option/module.nix
new file mode 100644
index 00000000..0053d357
--- /dev/null
+++ b/modules/by-name/ni/nixos-option/module.nix
@@ -0,0 +1,18 @@
+{
+  config,
+  lib,
+  libraries,
+  ...
+}: let
+  cfg = config.soispha.programs.nixos-option;
+in {
+  options.soispha.programs.nixos-option = {
+    enable = libraries.base.options.mkEnable "nixos-option";
+  };
+
+  config = lib.mkIf cfg.enable {
+    # NOTE: We disable nixos-option here explicitly, because I never used it, and it
+    # depends on cppnix. <2025-12-11>
+    system.tools.nixos-option.enable = false;
+  };
+}
diff --git a/modules/by-name/ni/nixos-shell/module.nix b/modules/by-name/ni/nixos-shell/module.nix
new file mode 100644
index 00000000..8dda2890
--- /dev/null
+++ b/modules/by-name/ni/nixos-shell/module.nix
@@ -0,0 +1,128 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Jörg Thalheim and contributors
+# SPDX-License-Identifier: MIT
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  lib,
+  config,
+  pkgs,
+  self,
+  ...
+}: let
+  cfg = config.soispha.nixos-shell;
+in {
+  options.soispha.nixos-shell = {
+    enable = lib.mkEnableOption "nixos-shell";
+
+    user_name = lib.mkOption {
+      type = lib.types.str;
+      default = "soispha";
+      description = "The user to auto-login into the vm.";
+    };
+
+    configuration = {
+      specialArgs = lib.mkOption {
+        type = lib.types.attrsOf lib.types.anything;
+        default = {};
+        description = ''
+          The arguments to pass to the `specialArgs` attribute set.
+        '';
+      };
+      value = lib.mkOption {
+        type = lib.types.deferredModule;
+        default = {};
+        description = ''
+          Additional NixOS configuration to load into the VM's config.
+        '';
+      };
+    };
+
+    mounts = lib.mkOption {
+      type = lib.types.attrsOf (lib.types.submodule ({config, ...}: {
+        options = {
+          target = lib.mkOption {
+            type = lib.types.path;
+            description = "Target on the guest.";
+          };
+
+          cache_mode = lib.mkOption {
+            type = lib.types.enum ["none" "loose" "fscache" "mmap"];
+            default = "loose"; # bad idea? Well, at least it is fast!1!!
+            description = "9p caching policy";
+          };
+
+          readOnly =
+            (lib.mkEnableOption "mount this disk in read-only mode")
+            // {
+              default = true;
+            };
+
+          tag = lib.mkOption {
+            type = lib.types.str;
+            internal = true;
+          };
+        };
+
+        config.tag = lib.mkDefault (
+          builtins.substring 0 31 ( # tags must be shorter than 32 bytes
+            "a"
+            + # tags must not begin with a digit
+            builtins.hashString "md5" config._module.args.name
+          )
+        );
+      }));
+      default = {};
+      description = ''
+        Extra paths to make available in the vm.
+        These will be mounted ro to their `target.`
+      '';
+    };
+  };
+
+  config = let
+    vmSystem = self.inputs.nixpkgs.lib.nixosSystem {
+      inherit (cfg.configuration) specialArgs;
+
+      modules = [
+        {
+          # TODO(@bpeetz): This should be bumped each release. <2025-05-17>
+          system.stateVersion = "25.11";
+        }
+
+        cfg.configuration.value
+
+        (import ./shell_setup.nix {inherit cfg;})
+      ];
+    };
+
+    nixos-shell = pkgs.writeShellApplication {
+      name = "nixos-shell";
+      text = builtins.readFile ./nixos-shell.sh;
+
+      # We need to keep the PATH, as we otherwise can't pass it along.
+      inheritPath = true;
+
+      runtimeInputs = [
+        vmSystem.config.system.build.vm
+        pkgs.mktemp
+        pkgs.coreutils
+        pkgs.moreutils # for sponge
+      ];
+      runtimeEnv = {
+        HOST_NAME = vmSystem.config.system.name;
+      };
+    };
+  in
+    lib.mkIf cfg.enable {
+      environment.systemPackages = [
+        nixos-shell
+      ];
+
+      system.build.nixos-shell = vmSystem.config.system.build.vm;
+    };
+}
diff --git a/modules/by-name/ni/nixos-shell/nixos-shell.sh b/modules/by-name/ni/nixos-shell/nixos-shell.sh
new file mode 100755
index 00000000..3b34019a
--- /dev/null
+++ b/modules/by-name/ni/nixos-shell/nixos-shell.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env dash
+
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Jörg Thalheim and contributors
+# SPDX-License-Identifier: MIT
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+SHARED_DIR="$(mktemp -t --directory "nixos_shell_XXXXXXXXX")"
+cleanup() {
+    rm --recursive "$SHARED_DIR"
+}
+trap cleanup EXIT
+export SHARED_DIR
+
+TMPDIR="$SHARED_DIR"
+export TMPDIR
+
+cat <<EOF >"$SHARED_DIR/.env_variables"
+{
+    "pwd": "$PWD",
+    "term": "$TERM",
+    "path": "$PATH"
+}
+EOF
+
+mk_tag() {
+    additional_path="$1"
+
+    # tags must be shorter than 32 bytes
+    # and must not begin with a digit.
+    {
+        printf "a"
+        echo "$additional_path" | sha256sum | head -c 30
+    }
+}
+
+for raw_additional_path in "$@"; do
+    additional_path="$(realpath "$raw_additional_path")"
+    tag="$(mk_tag "$additional_path")"
+
+    if [ "$(jq --arg mount "$tag" '.mount.[$mount]' "$SHARED_DIR/.env_variables")" != "null" ]; then
+        echo "Path '$additional_path' alread added."
+        shift 1
+        continue
+    fi
+
+    jq --arg mount "$tag" --arg target "$additional_path" \
+        '. + {mount: {$mount: $target}}' "$SHARED_DIR/.env_variables" | sponge "$SHARED_DIR/.env_variables"
+
+    set -- "$@" -virtfs "local,path=$additional_path,security_model=none,readonly=on,mount_tag=$tag"
+    shift 1
+done
+
+# Do not exec here, as we don't want to lose our cleanup hooks.
+"run-$HOST_NAME-vm" "$@"
diff --git a/modules/by-name/ni/nixos-shell/shell_setup.nix b/modules/by-name/ni/nixos-shell/shell_setup.nix
new file mode 100644
index 00000000..75af0678
--- /dev/null
+++ b/modules/by-name/ni/nixos-shell/shell_setup.nix
@@ -0,0 +1,191 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Jörg Thalheim and contributors
+# SPDX-License-Identifier: MIT
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+# This file contains the code that is used to setup the VM shell.
+{cfg}: {
+  lib,
+  config,
+  pkgs,
+  modulesPath,
+  ...
+}: let
+  mkVMDefault = lib.mkOverride 970;
+
+  env_file = "/tmp/shared/.env_variables";
+in {
+  imports = [
+    (modulesPath + "/profiles/qemu-guest.nix")
+    (modulesPath + "/virtualisation/qemu-vm.nix")
+  ];
+
+  config = {
+    assertions = [
+      {
+        assertion = builtins.elem cfg.user_name (lib.mapAttrsToList (name: value: name) config.users.users);
+        message = ''
+          Your user ${cfg.user_name} is not a recorded user in `config.users.users`.
+          Auto-login will not work.
+        '';
+      }
+    ];
+
+    # Lock root login.
+    users.users.root.hashedPassword = "";
+
+    # Remove unneeded clutter.
+    system.switch.enable = false;
+
+    virtualisation = {
+      # See https://wiki.qemu.org/Documentation/9psetup#Performance_Considerations.
+      # It is effectively a balance between ram and IO speed.
+      msize = let
+        kib = x: x * 1024;
+      in
+        mkVMDefault (kib 512);
+
+      graphics = mkVMDefault false;
+      memorySize = mkVMDefault 1700; # in MB
+      cores = mkVMDefault 16;
+
+      # Do not persist this VM.
+      diskImage = mkVMDefault null;
+
+      fileSystems =
+        lib.mapAttrs'
+        (_: mount: {
+          name = mount.target;
+
+          value = {
+            device = mount.tag;
+            fsType = "9p";
+            options =
+              [
+                "trans=virtio"
+                "version=9p2000.L"
+                "cache=${mount.cache_mode}"
+                "msize=${toString config.virtualisation.msize}"
+              ]
+              ++ lib.optionals mount.readOnly ["ro"];
+          };
+        })
+        cfg.mounts;
+
+      qemu = {
+        consoles = lib.mkIf (!config.virtualisation.graphics) ["tty0" "hvc0"];
+
+        options = let
+          mkMount = options: "-virtfs " + (builtins.concatStringsSep "," options);
+        in
+          lib.optionals (!config.virtualisation.graphics) [
+            "-serial null"
+            "-device virtio-serial"
+            "-chardev stdio,mux=on,id=char0,signal=off"
+            "-mon chardev=char0,mode=readline"
+            "-device virtconsole,chardev=char0,nr=0"
+          ]
+          ++ (lib.mapAttrsToList
+            (hostPath: mount:
+              mkMount [
+                "local"
+                "path=${builtins.toString hostPath}"
+                "security_model=none"
+                "readonly=on"
+                "mount_tag=${mount.tag}"
+              ])
+            cfg.mounts);
+      };
+    };
+
+    services = {
+      getty.helpLine = ''
+        If you are connect via serial console:
+        Type Ctrl-a c to switch to the qemu console
+        and `quit` to stop the VM.
+      '';
+
+      getty.autologinUser = cfg.user_name;
+    };
+
+    system.activationScripts = {
+      mountAdditionalPaths =
+        # bash
+        ''
+          PATH="${pkgs.jq}/bin:${pkgs.util-linux}/bin:$PATH"
+          export PATH
+
+          max_index="$(jq '.mount | keys | length' --raw-output ${env_file})"
+          index=0
+
+          mount --mkdir --type=tmpfs none "/.rw" --options=rw,relatime,mode=0755
+          while [ "$index" -lt "$max_index" ]; do
+            what="$(jq --argjson index "$index" '.mount | keys | map(.)[$index]' --raw-output ${env_file})"
+            where="$(jq --argjson index "$index" '.mount | map(.)[$index]' --raw-output ${env_file})"
+
+            mkdir "/.rw/$what"
+            mount --mkdir "$what" "/.ro/$what" \
+              --type=9p \
+              --options=ro,trans=virtio,version=9p2000.L,msize=${toString config.virtualisation.msize},x-systemd.requires=modprobe@9pnet_virtio.service
+
+            mkdir "/.rw/work-$what"
+            mount --mkdir --type=overlay overlay \
+              --options=rw,relatime,lowerdir="/.ro/$what",upperdir="/.rw/$what",workdir="/.rw/work-$what",uuid=on \
+              "/.ov/$what"
+
+            index="$((index + 1))"
+          done
+        '';
+    };
+
+    systemd.services.mountAdditionalPaths = {
+      after = ["local-fs.target"];
+      wantedBy = ["multi-user.target"];
+      path = [pkgs.jq];
+      script =
+        # bash
+        ''
+          max_index="$(jq '.mount | keys | length' --raw-output ${env_file})"
+          index=0
+
+          while [ "$index" -lt "$max_index" ]; do
+            what="$(jq --argjson index "$index" '.mount | keys | map(.)[$index]' --raw-output ${env_file})"
+            where="$(jq --argjson index "$index" '.mount | map(.)[$index]' --raw-output ${env_file})"
+
+            systemd-mount --type none "/.ov/$what" "$where" --options=bind
+
+            # HACK(@bpeetz): Nearly all of the paths are in $HOME anyways. So simply avoid
+            # the permission issue.
+            # Ideally, we would pass the original owners along with the mount. <2025-05-17>
+            chown --recursive soispha:users "/home/soispha"
+
+            index="$((index + 1))"
+          done
+        '';
+    };
+
+    environment = {
+      systemPackages = [
+        pkgs.jq
+      ];
+
+      sessionVariables = {
+        IN_NIXOS_SHELL = "true";
+      };
+
+      loginShellInit =
+        # bash
+        ''
+          cd "$(jq '.pwd' --raw-output ${env_file})"
+          export TERM="$(jq '.term' --raw-output ${env_file})"
+          export PATH="$(jq '.path' --raw-output ${env_file}):$PATH"
+        '';
+    };
+
+    networking.firewall.enable = mkVMDefault true;
+  };
+}
diff --git a/modules/by-name/ni/nixpkgs/config.nix b/modules/by-name/ni/nixpkgs/config.nix
deleted file mode 100644
index 0d99336c..00000000
--- a/modules/by-name/ni/nixpkgs/config.nix
+++ /dev/null
@@ -1,43 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  cfg,
-  myPkgs,
-  lib,
-  ...
-}: let
-  myPkgsOverlay = self: super: myPkgs;
-in {
-  nixpkgs = {
-    hostPlatform = cfg.systemName;
-
-    overlays = [
-      myPkgsOverlay
-    ];
-
-    config = {
-      # TODO: this fails because of the root tempsize, which should be increased
-      # contentAddressedByDefault = true;
-
-      hostSystem = cfg.systemName;
-
-      allowUnfreePredicate = pkg:
-        builtins.elem (lib.getName pkg) [
-          "pypemicro" # required by pynitrokey
-
-          # TODO(@bpeetz): Allow moving them to their respective module. <2025-04-25>
-          "steam"
-          "steam-unwrapped"
-          "steam-original"
-          "steam-run"
-        ];
-    };
-  };
-}
diff --git a/modules/by-name/ni/nixpkgs/module.nix b/modules/by-name/ni/nixpkgs/module.nix
index 07beae3e..502bcff2 100644
--- a/modules/by-name/ni/nixpkgs/module.nix
+++ b/modules/by-name/ni/nixpkgs/module.nix
@@ -10,8 +10,9 @@
 {
   lib,
   config,
+  packageSets,
   ...
-} @ args: let
+}: let
   cfg = config.soispha.nixpkgs;
 in {
   options.soispha.nixpkgs = {
@@ -22,5 +23,29 @@ in {
       type = lib.types.str;
     };
   };
-  config = lib.mkIf cfg.enable (import ./config.nix (args // {inherit cfg;}));
+  config = let
+    myPkgsOverlay = self: super: packageSets.soispha;
+  in
+    lib.mkIf cfg.enable
+    {
+      nixpkgs = {
+        hostPlatform = cfg.systemName;
+
+        overlays = [
+          myPkgsOverlay
+        ];
+
+        config = {
+          # TODO: this fails because of the root tempsize, which should be increased
+          # contentAddressedByDefault = true;
+
+          hostSystem = cfg.systemName;
+
+          allowUnfreePredicate = pkg:
+            builtins.elem (lib.getName pkg) [
+              "pypemicro" # required by pynitrokey
+            ];
+        };
+      };
+    };
 }
diff --git a/modules/by-name/ns/nscd/module.nix b/modules/by-name/ns/nscd/module.nix
new file mode 100644
index 00000000..94ca4874
--- /dev/null
+++ b/modules/by-name/ns/nscd/module.nix
@@ -0,0 +1,18 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.nscd;
+in {
+  options.soispha.nscd = {
+    enable = (lib.mkEnableOption "nscd") // {default = config.services.nscd.enableNsncd;};
+  };
+
+  config = lib.mkIf cfg.enable {
+    users = {
+      users.nscd.uid = config.soispha.constants.ids.uids.nscd;
+      groups.nscd.gid = config.soispha.constants.ids.gids.nscd;
+    };
+  };
+}
diff --git a/modules/by-name/nv/nvim/mappings/default.nix b/modules/by-name/nv/nvim/mappings/default.nix
index 2e14cc80..683b0465 100644
--- a/modules/by-name/nv/nvim/mappings/default.nix
+++ b/modules/by-name/nv/nvim/mappings/default.nix
@@ -27,34 +27,6 @@ in {
           action = "<cmd>noh<CR><Esc>";
           options.desc = "Disable the search highlighting and send Escape";
         }
-        {
-          key = "hh";
-          mode = ["i"];
-          action.__raw = ''
-            function()
-              local cmp = require('cmp');
-              local luasnip = require('luasnip');
-
-              if cmp.visible() then
-                  cmp.select_next_item()
-              elseif luasnip.expand_or_locally_jumpable() then
-                  luasnip.expand_or_jump()
-              end
-            end
-          '';
-          options.desc = "completion trigger/ forward in completen menu";
-        }
-        {
-          key = "uu";
-          mode = ["i"];
-          action.__raw = ''
-            function()
-              local cmp = require('cmp');
-              cmp.confirm()
-            end
-          '';
-          options.desc = "confirm the selected item";
-        }
 
         {
           key = "<C-Tab>";
@@ -217,12 +189,13 @@ in {
           action = "\"_dP";
           options.desc = "keep the cut thing in the base register";
         }
-        {
-          mode = ["n"];
-          key = "<leader>c";
-          action = "\"_c";
-          options.desc = "change without saving to register";
-        }
+        # Overlaps with the femaco mapping (`<Space>cc`).
+        # {
+        #   mode = ["n"];
+        #   key = "<leader>c";
+        #   action = "\"_c";
+        #   options.desc = "change without saving to register";
+        # }
 
         {
           mode = ["n"];
diff --git a/modules/by-name/nv/nvim/module.nix b/modules/by-name/nv/nvim/module.nix
index f394db3b..81d7febf 100644
--- a/modules/by-name/nv/nvim/module.nix
+++ b/modules/by-name/nv/nvim/module.nix
@@ -11,17 +11,27 @@
   pkgs,
   lib,
   config,
+  modules,
+  libraries,
   ...
 }: let
   cfg = config.soispha.programs.nvim;
+
+  plgs = builtins.attrValues (libraries.extra.mkByName {
+    useShards = false;
+    baseDirectory = ./plgs;
+    fileName = "default.nix";
+  });
 in {
-  imports = [
-    ./autocmds
-    ./clipboard
-    ./mappings
-    ./options
-    ./plgs
-  ];
+  imports =
+    [
+      ./autocmds
+      ./clipboard
+      ./mappings
+      ./options
+      ./performance
+    ]
+    ++ plgs;
 
   options.soispha.programs.nvim = {
     enable = lib.mkEnableOption "custom nvim config";
@@ -33,11 +43,16 @@ in {
 
   config = lib.mkIf cfg.enable {
     home-manager.users.soispha = {
+      imports = [
+        modules.nixvim.homeModules.nixvim
+      ];
+
       home.sessionVariables = {
         EDITOR = "nvim";
         VISUAL = "nvim";
         CODEEDITOR = "nvim";
       };
+
       programs.nixvim = {
         enable = true;
 
@@ -58,21 +73,21 @@ in {
           ---------------------------------------------------------------------------
         '';
 
-        extraPackages = with pkgs; [
+        extraPackages = [
           /*
           These are mostly linters and formatters used for different file types.
           Including them here is fine, as they are not necessarily-sync able to different people.
           */
           # nix
-          alejandra
-          statix
+          pkgs.alejandra
+          pkgs.statix
 
           # yaml
-          yamllint
+          pkgs.yamllint
 
           # shell
-          shellcheck
-          shfmt
+          pkgs.shellcheck
+          pkgs.shfmt
         ];
       };
     };
diff --git a/modules/by-name/nv/nvim/options/default.nix b/modules/by-name/nv/nvim/options/default.nix
index 0f529ca3..301f0ac0 100644
--- a/modules/by-name/nv/nvim/options/default.nix
+++ b/modules/by-name/nv/nvim/options/default.nix
@@ -32,7 +32,6 @@ in {
 
     confirm = true; # confirm to save changes before closing modified buffer
     colorcolumn = "+1"; # show a +1 before the 'textwidth'
-    completeopt = ["menuone" "noselect"]; # have a better completion experience
 
     # https://www.compart.com/en/unicode/U+XXXX (unicode character code)
     fillchars = {
diff --git a/modules/by-name/nv/nvim/performance/default.nix b/modules/by-name/nv/nvim/performance/default.nix
new file mode 100644
index 00000000..a392a672
--- /dev/null
+++ b/modules/by-name/nv/nvim/performance/default.nix
@@ -0,0 +1,24 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.programs.nvim;
+in {
+  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
+    performance = {
+      combinePlugins = {
+        enable = true;
+      };
+
+      byteCompileLua = {
+        enable = true;
+        configs = true;
+        initLua = true;
+        luaLib = true;
+        nvimRuntime = true;
+        plugins = true;
+      };
+    };
+  };
+}
diff --git a/modules/by-name/nv/nvim/plgs/comment-nvim/default.nix b/modules/by-name/nv/nvim/plgs/comment-nvim/default.nix
index b404843e..68a88d32 100644
--- a/modules/by-name/nv/nvim/plgs/comment-nvim/default.nix
+++ b/modules/by-name/nv/nvim/plgs/comment-nvim/default.nix
@@ -26,6 +26,7 @@ in {
         };
       };
     };
+
     keymaps = [
       {
         key = "gcc";
diff --git a/modules/by-name/nv/nvim/plgs/debugprint/default.nix b/modules/by-name/nv/nvim/plgs/debugprint/default.nix
deleted file mode 100644
index 79e557bd..00000000
--- a/modules/by-name/nv/nvim/plgs/debugprint/default.nix
+++ /dev/null
@@ -1,82 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  pkgs,
-  lib,
-  config,
-  ...
-}: let
-  cfg = config.soispha.programs.nvim;
-in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    # TODO: package debugprint though a module
-    extraConfigLuaPost = ''
-      ${lib.strings.fileContents ./lua/debugprint.lua}
-    '';
-    extraPlugins = [
-      pkgs.vimExtraPlugins.debugprint-nvim
-    ];
-
-    keymaps = [
-      {
-        key = "g?v";
-        mode = ["v" "n"];
-        action.__raw = ''
-          function()
-            return require('debugprint').debugprint({variable = true;});
-          end
-        '';
-        options.expr = true;
-        options.desc = ''
-          'variable' debug line below the current line
-        '';
-      }
-      {
-        key = "g?V";
-        mode = ["v" "n"];
-        action.__raw = ''
-          function()
-            return require('debugprint').debugprint({above = true; variable = true;}) ;
-          end
-        '';
-        options.expr = true;
-        options.desc = ''
-          'variable' debug line above the current line
-        '';
-      }
-      {
-        key = "g?p";
-        mode = "n";
-        action.__raw = ''
-          function()
-            return require('debugprint').debugprint();
-          end
-        '';
-        options.expr = true;
-        options.desc = ''
-          'plain' debug line below the current line
-        '';
-      }
-      {
-        key = "g?P";
-        mode = "n";
-        action.__raw = ''
-          function()
-            return require('debugprint').debugprint({above = true;});
-          end
-        '';
-        options.expr = true;
-        options.desc = ''
-          'plain' debug line above the current line
-        '';
-      }
-    ];
-  };
-}
diff --git a/modules/by-name/nv/nvim/plgs/debugprint/lua/debugprint.lua b/modules/by-name/nv/nvim/plgs/debugprint/lua/debugprint.lua
deleted file mode 100644
index b934d619..00000000
--- a/modules/by-name/nv/nvim/plgs/debugprint/lua/debugprint.lua
+++ /dev/null
@@ -1,13 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-require("debugprint").setup({
-  create_keymaps = false,
-})
diff --git a/modules/by-name/nv/nvim/plgs/default.nix b/modules/by-name/nv/nvim/plgs/default.nix
deleted file mode 100644
index aaebb3b1..00000000
--- a/modules/by-name/nv/nvim/plgs/default.nix
+++ /dev/null
@@ -1,42 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  imports =
-    [
-      # Plugins not yet packaged in nixpkgs
-      # ./debugprint
-      ./lf-nvim
-      # ./lsp-progress-nvim
-    ]
-    ++ [
-      # Already packaged in nixpkgs
-      ./colorscheme
-      ./comment-nvim
-      ./femaco
-      ./flatten-nvim
-      ./goto-preview
-      ./harpoon
-      ./leap
-      ./lsp
-      ./lspkind
-      ./ltex_extra
-      ./lualine
-      ./luasnip
-      ./neorg
-      ./nvim-cmp
-      ./nvim-lint
-      ./raw_plugins
-      ./telescope
-      ./todo-comments
-      ./treesitter
-      ./vim-tex
-      ./which-key
-    ];
-}
diff --git a/modules/by-name/nv/nvim/plgs/femaco/default.nix b/modules/by-name/nv/nvim/plgs/femaco/default.nix
index a30bb59f..eac6b393 100644
--- a/modules/by-name/nv/nvim/plgs/femaco/default.nix
+++ b/modules/by-name/nv/nvim/plgs/femaco/default.nix
@@ -8,21 +8,22 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
-  pkgs,
   lib,
   config,
   ...
 }: let
   cfg = config.soispha.programs.nvim;
 in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    # TODO: package femaco through a module
+  # TODO: Re-active this plugin, when it does no longer depend on `treesitter-legacy` <2026-01-18>
+  home-manager.users.soispha.programs.nixvim = lib.mkIf false {
+    plugins.femaco = {
+      enable = true;
+    };
+
     extraConfigLuaPost = ''
       ${lib.strings.fileContents ./lua/femaco.lua}
     '';
-    extraPlugins = [
-      pkgs.vimPlugins.nvim-FeMaco-lua
-    ];
+
     keymaps = [
       {
         key = "<leader>cc";
diff --git a/modules/by-name/nv/nvim/plgs/femaco/lua/femaco.lua b/modules/by-name/nv/nvim/plgs/femaco/lua/femaco.lua
index 1371a825..50a6cb23 100644
--- a/modules/by-name/nv/nvim/plgs/femaco/lua/femaco.lua
+++ b/modules/by-name/nv/nvim/plgs/femaco/lua/femaco.lua
@@ -8,7 +8,9 @@
 -- You should have received a copy of the License along with this program.
 -- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
+
 local clip_val = require("femaco.utils").clip_val
+
 require("femaco").setup({
   -- should prepare a new buffer and return the winid
   -- by default opens a floating window
@@ -17,7 +19,8 @@ require("femaco").setup({
   prepare_buffer = function(opts)
     local buf = vim.api.nvim_create_buf(false, false)
     return vim.api.nvim_open_win(buf, true, opts)
-  end,
+  end;
+
   -- should return options passed to nvim_open_win
   -- @param code_block: data about the code-block with the keys
   --   * range
@@ -25,30 +28,43 @@ require("femaco").setup({
   --   * lang
   float_opts = function(code_block)
     return {
-      relative = "cursor",
-      width = clip_val(5, 120, vim.api.nvim_win_get_width(0) - 10), -- TODO: how to offset sign column etc?
-      height = clip_val(5, #code_block.lines, vim.api.nvim_win_get_height(0) - 6),
-      anchor = "NW",
-      row = 0,
-      col = 0,
-      style = "minimal",
-      border = "rounded",
-      zindex = 1,
+      relative = "cursor";
+      width = clip_val(5, 120, vim.api.nvim_win_get_width(0) - 10); -- TODO how to offset sign column etc?
+      height = clip_val(5, #code_block.lines, vim.api.nvim_win_get_height(0) - 6);
+      anchor = "NW";
+      row = 0;
+      col = 0;
+      style = "minimal";
+      border = "rounded";
+      zindex = 1;
     }
-  end,
+  end;
+
   -- return filetype to use for a given lang
   -- lang can be nil
-  ft_from_lang = function(lang) return lang end,
+  ft_from_lang = function(lang)
+    return lang
+  end;
+
   -- what to do after opening the float
-  post_open_float = function(winnr) vim.wo.signcolumn = "no" end,
+  post_open_float = function(winnr)
+    vim.wo.signcolumn = "no"
+  end;
+
   -- create the path to a temporary file
-  create_tmp_filepath = function(filetype) return os.tmpname() end,
+  create_tmp_filepath = function(filetype)
+    return os.tmpname()
+  end;
+
   -- if a newline should always be used, useful for multiline injections
   -- which separators needs to be on separate lines such as markdown, neorg etc
   -- @param base_filetype: The filetype which FeMaco is called from, not the
   -- filetype of the injected language (this is the current buffer so you can
   -- get it from vim.bo.filetyp).
-  ensure_newline = function(base_filetype) return false end,
+  ensure_newline = function(base_filetype)
+    return base_filetype == "nix"
+  end;
+
   -- Return true if the indentation should be normalized. Useful when the
   -- injected language inherits indentation from the construction scope (e.g. an
   -- inline multiline sql string). If true, the leading indentation is detected,
@@ -57,5 +73,7 @@ require("femaco").setup({
   -- @param base_filetype: The filetype which FeMaco is called from, not the
   -- filetype of the injected language (this is the current buffer, so you can
   -- get it from vim.bo.filetype).
-  normalize_indent = function(base_filetype) return false end,
+  normalize_indent = function(base_filetype)
+    return base_filetype == "nix"
+  end;
 })
diff --git a/modules/by-name/nv/nvim/plgs/flatten-nvim/default.nix b/modules/by-name/nv/nvim/plgs/flatten-nvim/default.nix
deleted file mode 100644
index 8d61d859..00000000
--- a/modules/by-name/nv/nvim/plgs/flatten-nvim/default.nix
+++ /dev/null
@@ -1,33 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  pkgs,
-  lib,
-  config,
-  ...
-}: let
-  cfg = config.soispha.programs.nvim;
-in {
-  # TODO: Get this plugin working again <2025-01-29>
-  home-manager.users.soispha.programs.nixvim = lib.mkIf false {
-    # TODO: package flatten-nvim though a module
-
-    extraConfigLuaPre = ''
-      ${lib.strings.fileContents ./lua/flatten-nvim.lua}
-      if os.getenv("NVIM") ~= nil then
-        -- Avoid loading plugins because the host will take control of the instance anyways
-        return
-      end
-    '';
-    extraPlugins = [
-      pkgs.vimPlugins.flatten-nvim
-    ];
-  };
-}
diff --git a/modules/by-name/nv/nvim/plgs/flatten-nvim/lua/flatten-nvim.lua b/modules/by-name/nv/nvim/plgs/flatten-nvim/lua/flatten-nvim.lua
deleted file mode 100644
index 0c86cd27..00000000
--- a/modules/by-name/nv/nvim/plgs/flatten-nvim/lua/flatten-nvim.lua
+++ /dev/null
@@ -1,114 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
----Types:
---
--- Passed to callbacks that handle opening files
----@alias BufInfo { fname: string, bufnr: buffer }
---
--- Needed aliases
----@alias buffer integer: Buffer id
----@alias window integer: Window id
---
--- The first argument is a list of BufInfo tables representing the newly opened files.
--- The third argument is a single BufInfo table, only provided when a buffer is created from stdin.
---
--- IMPORTANT: For `block_for` to work, you need to return a buffer number OR a buffer number and a window number.
---            The `winnr` return value is not required, `vim.fn.bufwinid(bufnr)` is used if it is not provided.
---            The `filetype` of this buffer will determine whether block should happen or not.
---
----@alias OpenHandler fun(files: BufInfo[], argv: string[], stdin_buf: BufInfo, guest_cwd: string):window, buffer
---
-require("flatten").setup({
-  callbacks = {
-    ---Called to determine if a nested session should wait for the host to close the file.
-    ---param argv: a list of all the arguments in the nested session
-    ---@type fun(argv: table): boolean
-    should_block = require("flatten").default_should_block,
-
-    ---If this returns true, the nested session will be opened.
-    ---If false, default behavior is used, and
-    ---config.nest_if_no_args is respected.
-    ---@type fun(host: channel):boolean
-    should_nest = require("flatten").default_should_nest,
-
-    ---Called before a nested session is opened.
-    pre_open = function() end,
-
-    ---Called after a nested session is opened.
-    ---@param bufnr buffer
-    ---@param winnr window
-    ---@param filetype string
-    ---@param is_blocking boolean
-    ---@param is_diff boolean
-    post_open = function(bufnr, winnr, filetype, is_blocking, is_diff)
-      -- If the file is a git commit, create one-shot autocmd to delete its buffer on write
-      if filetype == "gitcommit" or filetype == "gitrebase" then
-        vim.api.nvim_create_autocmd("BufWritePost", {
-          buffer = bufnr,
-          once = true,
-          callback = vim.schedule_wrap(function() vim.api.nvim_buf_delete(bufnr, {}) end),
-        })
-      end
-    end,
-
-    ---Called when a nested session is done waiting for the host.
-    ---@param filetype string
-    block_end = function(filetype) end,
-  },
-  -- <String, Bool> dictionary of filetypes that should be blocking
-  block_for = {
-    gitcommit = true,
-  },
-  -- Command passthrough
-  allow_cmd_passthrough = true,
-  -- Allow a nested session to open if Neovim is opened without arguments
-  nest_if_no_args = false,
-  -- Window options
-  window = {
-    -- Options:
-    -- current        -> open in current window (default)
-    -- alternate      -> open in alternate window (recommended)
-    -- tab            -> open in new tab
-    -- split          -> open in split
-    -- vsplit         -> open in vsplit
-    -- smart          -> smart open (avoids special buffers)
-    -- OpenHandler    -> allows you to handle file opening yourself (see Types)
-    --
-    -- TODO: Open gitcommit filetypes in the current buffer, everything else in a new tab <2023-08-29>
-    open = "split",
-
-    -- Options:
-    -- vsplit         -> opens files in diff vsplits
-    -- split          -> opens files in diff splits
-    -- tab_vsplit     -> creates a new tabpage, and opens diff vsplits
-    -- tab_split      -> creates a new tabpage, and opens diff splits
-    -- OpenHandler    -> allows you to handle file opening yourself (see Types)
-    diff = "tab_vsplit",
-
-    -- Affects which file gets focused when opening multiple at once
-    -- Options:
-    -- "first"        -> open first file of new files (default)
-    -- "last"         -> open last file of new files
-    focus = "first",
-  },
-  -- Override this function to use a different socket to connect to the host
-  -- On the host side this can return nil or the socket address.
-  -- On the guest side this should return the socket address
-  -- or a non-zero channel id from `sockconnect`
-  -- flatten.nvim will detect if the address refers to this instance of nvim, to determine if this is a host or a guest
-  pipe_path = require("flatten").default_pipe_path,
-  -- The `default_pipe_path` will treat the first nvim instance within a single kitty/wezterm session as the host
-  -- You can configure this behaviour using the following:
-  one_per = {
-    kitty = true, -- Flatten all instance in the current Kitty session
-    wezterm = true, -- Flatten all instance in the current Wezterm session
-  },
-})
diff --git a/modules/by-name/nv/nvim/plgs/leap/default.nix b/modules/by-name/nv/nvim/plgs/leap/default.nix
deleted file mode 100644
index e5c42d2f..00000000
--- a/modules/by-name/nv/nvim/plgs/leap/default.nix
+++ /dev/null
@@ -1,74 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  config,
-  lib,
-  ...
-}: let
-  cfg = config.soispha.programs.nvim;
-in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    plugins.leap = {
-      enable = true;
-      addDefaultMappings = false; # They don't work with dvorak.
-      safeLabels = [
-        "f"
-        "j"
-        "k"
-        "l"
-        "/"
-        "z"
-        "S"
-        "F"
-        "J"
-        "K"
-        "L"
-        "H"
-        "W"
-        "E"
-        "M"
-        "B"
-        "U"
-        "X"
-        "?"
-        "Z"
-      ];
-    };
-    keymaps = [
-      {
-        key = "j";
-        action = "<Plug>(leap-forward-to)";
-        options.desc = "jump forward to";
-      }
-      {
-        key = "J";
-        action = "<Plug>(leap-backward-to)";
-        options.desc = "jump backward to";
-      }
-      {
-        key = "gj";
-        action = "<Plug>(leap-from-window)";
-        options.desc = "jump to enterable windows";
-      }
-      /*
-            {key= "x";
-              mode = "v";
-              action = "<Plug>(leap-forward-till)";
-      options.desc = "leap forward till";
-            }
-            {key= "X";
-              mode = "v";
-              action = "<Plug>(leap-backward-till)";
-      options.desc = "leap backward till";
-            }
-      */
-    ];
-  };
-}
diff --git a/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix b/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix
index 3a1c6bf9..e652a60d 100644
--- a/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix
+++ b/modules/by-name/nv/nvim/plgs/lf-nvim/default.nix
@@ -8,21 +8,88 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
-  pkgs,
   lib,
   config,
   ...
 }: let
   cfg = config.soispha.programs.nvim;
 in {
-  # TODO: package lf-nvim though a module
   # TODO: change the nvim path, when I change the path with lf
   home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    extraConfigLuaPost = ''
-      ${lib.strings.fileContents ./lua/lf-nvim.lua}
-    '';
-    extraPlugins = [
-      pkgs.vimPlugins.lf-nvim
-    ];
+    plugins.lf = {
+      enable = true;
+
+      settings = {
+        default_actions = {
+          "<C-o>" = "tab drop";
+          "<C-t>" = "tabedit";
+          "<C-v>" = "vsplit";
+          "<C-x>" = "split";
+        };
+
+        default_action = "drop";
+
+        winblend = 10;
+        dir = "";
+        direction = "float";
+        border = "rounded";
+        height.__raw = "vim.fn.float2nr(vim.fn.round(0.75 * vim.o.lines))";
+        width.__raw = "vim.fn.float2nr(vim.fn.round(0.75 * vim.o.columns))";
+        escape_quit = true;
+        focus_on_open = true;
+        mappings = true;
+        tmux = false;
+        default_file_manager = true;
+        disable_netrw_warning = true;
+        highlights = {
+          Normal = {link = "Normal";};
+          NormalFloat = {link = "Normal";};
+          FloatBorder = {
+            guifg = "#cdcbe0";
+            guibg = "#191726";
+          };
+        };
+
+        layout_mapping = "<M-u>";
+        views = [
+          {
+            width = 0.800;
+            height = 0.800;
+          }
+          {
+            width = 0.600;
+            height = 0.600;
+          }
+          {
+            width = 0.950;
+            height = 0.950;
+          }
+          {
+            width = 0.500;
+            height = 0.500;
+            col = 0;
+            row = 0;
+          }
+          {
+            width = 0.500;
+            height = 0.500;
+            col = 0;
+            row = 0.5;
+          }
+          {
+            width = 0.500;
+            height = 0.500;
+            col = 0.5;
+            row = 0;
+          }
+          {
+            width = 0.500;
+            height = 0.500;
+            col = 0.5;
+            row = 0.5;
+          }
+        ];
+      };
+    };
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/lf-nvim/lua/lf-nvim.lua b/modules/by-name/nv/nvim/plgs/lf-nvim/lua/lf-nvim.lua
deleted file mode 100644
index 8c40ab50..00000000
--- a/modules/by-name/nv/nvim/plgs/lf-nvim/lua/lf-nvim.lua
+++ /dev/null
@@ -1,53 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-local fn = vim.fn
-
--- Defaults
-require("lf").setup({
-  default_action = "drop", -- default action when `Lf` opens a file
-  -- TODO: what do these mappings do?
-  default_actions = { -- default action keybindings
-    ["<C-t>"] = "tabedit",
-    ["<C-x>"] = "split",
-    ["<C-v>"] = "vsplit",
-    ["<C-o>"] = "tab drop",
-  },
-
-  winblend = 10, -- psuedotransparency level
-  dir = "", -- directory where `lf` starts ('gwd' is git-working-directory, ""/nil is CWD)
-  direction = "float", -- window type: float horizontal vertical
-  border = "rounded", -- border kind: single double shadow curved
-  height = fn.float2nr(fn.round(0.75 * vim.o.lines)), -- height of the *floating* window
-  width = fn.float2nr(fn.round(0.75 * vim.o.columns)), -- width of the *floating* window
-  escape_quit = true, -- map escape to the quit command (so it doesn't go into a meta normal mode)
-  focus_on_open = true, -- focus the current file when opening Lf (experimental)
-  mappings = true, -- whether terminal buffer mapping is enabled
-  tmux = false, -- tmux statusline can be disabled on opening of Lf
-  default_file_manager = true, -- make lf default file manager
-  disable_netrw_warning = true, -- don't display a message when opening a directory with `default_file_manager` as true
-  highlights = { -- highlights passed to toggleterm
-    Normal = { link = "Normal" },
-    NormalFloat = { link = "Normal" },
-    FloatBorder = { guifg = "#cdcbe0", guibg = "#191726" },
-  },
-
-  -- Layout configurations
-  layout_mapping = "<M-u>", -- resize window with this key
-  views = { -- window dimensions to rotate through
-    { width = 0.800, height = 0.800 },
-    { width = 0.600, height = 0.600 },
-    { width = 0.950, height = 0.950 },
-    { width = 0.500, height = 0.500, col = 0, row = 0 },
-    { width = 0.500, height = 0.500, col = 0, row = 0.5 },
-    { width = 0.500, height = 0.500, col = 0.5, row = 0 },
-    { width = 0.500, height = 0.500, col = 0.5, row = 0.5 },
-  },
-})
diff --git a/modules/by-name/nv/nvim/plgs/lsp-progress-nvim/default.nix b/modules/by-name/nv/nvim/plgs/lsp-progress-nvim/default.nix
deleted file mode 100644
index 85458310..00000000
--- a/modules/by-name/nv/nvim/plgs/lsp-progress-nvim/default.nix
+++ /dev/null
@@ -1,62 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  lib,
-  config,
-  pkgs,
-  ...
-}: let
-  cfg = config.soispha.programs.nvim;
-in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    # TODO: package lsp-progress-nvim though a module
-    extraConfigLuaPost = ''
-      ${lib.strings.fileContents ./lua/lsp-progress-nvim.lua}
-    '';
-    extraPlugins = [
-      pkgs.vimExtraPlugins.lsp-progress-nvim
-    ];
-
-    # Status line setup
-    autoGroups.lsp_refresh.clear = true;
-    autoCmd = [
-      {
-        event = ["User LspProgressStatusUpdated"];
-        pattern = ["*"];
-        callback =
-          /*
-          lua
-          */
-          {
-            __raw = ''
-              require("lualine").refresh
-            '';
-          };
-        group = "lsp_refresh";
-        description = "Refresh the statusbar when the lsp status was updated.";
-      }
-    ];
-    plugins.lualine = let
-      get_lsp_progress = {
-        __raw =
-          /*
-          lua
-          */
-          ''
-            require('lsp-progress').progress
-          '';
-      };
-    in {
-      sections = {
-        lualine_c = [{name = get_lsp_progress;}];
-      };
-    };
-  };
-}
diff --git a/modules/by-name/nv/nvim/plgs/lsp-progress-nvim/lua/lsp-progress-nvim.lua b/modules/by-name/nv/nvim/plgs/lsp-progress-nvim/lua/lsp-progress-nvim.lua
deleted file mode 100644
index 2886d821..00000000
--- a/modules/by-name/nv/nvim/plgs/lsp-progress-nvim/lua/lsp-progress-nvim.lua
+++ /dev/null
@@ -1,156 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
---- @type table<string, any>
-require("lsp-progress").setup({
-  -- Spinning icons.
-  --
-  --- @type string[]
-  spinner = { "⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷" },
-
-  -- Spinning update time in milliseconds.
-  --
-  --- @type integer
-  spin_update_time = 200,
-
-  -- Last message cached decay time in milliseconds.
-  --
-  -- Message could be really fast(appear and disappear in an
-  -- instant) that user cannot even see it, thus we cache the last message
-  -- for a while for user view.
-  --
-  --- @type integer
-  decay = 700,
-
-  -- User event name.
-  --
-  --- @type string
-  event = "LspProgressStatusUpdated",
-
-  -- Event update time limit in milliseconds.
-  --
-  -- Sometimes progress handler could emit many events in an instant, while
-  -- refreshing statusline cause too heavy synchronized IO, so we limit the
-  -- event rate to reduce this cost.
-  --
-  --- @type integer
-  event_update_time_limit = 100,
-
-  -- Max progress string length, by default -1 is unlimited.
-  --
-  --- @type integer
-  max_size = -1,
-
-  -- Regular internal update time.
-  --
-  -- Emit user event to update the lsp progress status, even there's no new
-  -- message.
-  --
-  --- @type integer
-  regular_internal_update_time = 500,
-
-  -- Disable emitting events on specific mode/filetype.
-  -- User events would interrupt insert mode, thus break which-key like plugins behaviour.
-  -- See:
-  --  * https://github.com/linrongbin16/lsp-progress.nvim/issues/50
-  --  * https://neovim.io/doc/user/builtin.html#mode()
-  --
-  --- @type table[]
-  disable_events_opts = { { mode = "i", filetype = "TelescopePrompt" } },
-
-  -- Format series message.
-  --
-  -- By default it looks like: `formatting isort (100%) - done`.
-  --
-  --- @param title string|nil
-  ---     Message title.
-  --- @param message string|nil
-  ---     Message body.
-  --- @param percentage number|nil
-  ---     Progress in percentage numbers: 0-100.
-  --- @param done boolean
-  ---     Indicate whether this series is the last one in progress.
-  --- @return string|nil messages
-  ---     The returned value will be passed to function `client_format` as
-  ---     one of the `series_messages` array, or ignored if return nil.
-  series_format = function(title, message, percentage, done)
-    local builder = {}
-    local has_title = false
-    local has_message = false
-    if title and title ~= "" then
-      table.insert(builder, title)
-      has_title = true
-    end
-    if message and message ~= "" then
-      table.insert(builder, message)
-      has_message = true
-    end
-    if percentage and (has_title or has_message) then table.insert(builder, string.format("(%.0f%%%%)", percentage)) end
-    if done and (has_title or has_message) then table.insert(builder, "- done") end
-    return table.concat(builder, " ")
-  end,
-
-  -- Format client message.
-  --
-  -- By default it looks like:
-  -- `[null-ls] ⣷ formatting isort (100%) - done, formatting black (50%)`.
-  --
-  --- @param client_name string
-  ---     Client name.
-  --- @param spinner string
-  ---     Spinner icon.
-  --- @param series_messages string[]|table[]
-  ---     Messages array.
-  --- @return string|nil messages
-  ---     The returned value will be passed to function `format` as one of the
-  ---     `client_messages` array, or ignored if return nil.
-  client_format = function(client_name, spinner, series_messages)
-    return #series_messages > 0
-        and ("[" .. client_name .. "] " .. spinner .. " " .. table.concat(series_messages, ", "))
-      or nil
-  end,
-
-  -- Format (final) message.
-  --
-  -- By default it looks like:
-  -- ` LSP [null-ls] ⣷ formatting isort (100%) - done, formatting black (50%)`
-  --
-  --- @param client_messages string[]|table[]
-  ---     Client messages array.
-  --- @return nil|string message
-  ---     The returned value will be returned from `progress` API.
-  format = function(client_messages)
-    local sign = " LSP" -- nf-fa-gear \uf013
-    return #client_messages > 0 and (sign .. " " .. table.concat(client_messages, " ")) or sign
-  end,
-
-  -- Enable debug.
-  --
-  --- @type boolean
-  debug = false,
-
-  -- Print log to console(command line).
-  --
-  --- @type boolean
-  console_log = false,
-
-  -- Print log to file.
-  --
-  --- @type boolean
-  file_log = true,
-
-  -- Log file to write, work with `file_log=true`.
-  --
-  -- For Windows: `$env:USERPROFILE\AppData\Local\nvim-data\lsp-progress.log`.
-  -- For *NIX: `~/.local/share/nvim/lsp-progress.log`.
-  --
-  --- @type string
-  file_log_name = "lsp-progress.log",
-})
diff --git a/modules/by-name/nv/nvim/plgs/lsp/servers/default.nix b/modules/by-name/nv/nvim/plgs/lsp/servers/default.nix
index 8ff130fe..b6e47ca4 100644
--- a/modules/by-name/nv/nvim/plgs/lsp/servers/default.nix
+++ b/modules/by-name/nv/nvim/plgs/lsp/servers/default.nix
@@ -9,7 +9,6 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {...}: {
   imports = [
-    # ./servers/pylyzer.nix
     ./servers/bashls.nix
     ./servers/ccls.nix
     ./servers/quick-lint-js.nix
diff --git a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/openscad.nix b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/openscad.nix
index fba1113f..3d55adfa 100644
--- a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/openscad.nix
+++ b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/openscad.nix
@@ -25,9 +25,9 @@ in {
           cmd = {"openscad-lsp", "--stdio", "--fmt-style", "WebKit"},
         }
       '';
-    extraPackages = with pkgs; [
-      openscad-lsp
-      clang-tools # Need to satisfy `clang-format` (which is used by openscad-lsp)
+    extraPackages = [
+      pkgs.openscad-lsp
+      pkgs.clang-tools # Need to satisfy `clang-format` (which is used by openscad-lsp)
     ];
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/quick-lint-js.nix b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/quick-lint-js.nix
index 82d3b5a9..404784f1 100644
--- a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/quick-lint-js.nix
+++ b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/quick-lint-js.nix
@@ -24,8 +24,8 @@ in {
         require('lspconfig').quick_lint_js.setup{
         }
       '';
-    extraPackages = with pkgs; [
-      quick-lint-js
+    extraPackages = [
+      pkgs.quick-lint-js
     ];
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ruff-lsp.nix b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ruff-lsp.nix
index 4f9834ee..3ad3ad8f 100644
--- a/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ruff-lsp.nix
+++ b/modules/by-name/nv/nvim/plgs/lsp/servers/servers/ruff-lsp.nix
@@ -21,6 +21,6 @@ in {
         enable = true;
       };
     };
-    extraPackages = with pkgs; [ruff];
+    extraPackages = [pkgs.ruff];
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/lspkind/default.nix b/modules/by-name/nv/nvim/plgs/lspkind/default.nix
index 6e966ad1..3846fa32 100644
--- a/modules/by-name/nv/nvim/plgs/lspkind/default.nix
+++ b/modules/by-name/nv/nvim/plgs/lspkind/default.nix
@@ -16,6 +16,6 @@
 in {
   home-manager.users.soispha.programs.nixvim.plugins.lspkind = lib.mkIf cfg.enable {
     enable = true;
-    preset = "default"; # "codicons" is only for a font patched with vscode-codeicons.
+    settings.preset = "default"; # "codicons" is only for a font patched with vscode-codeicons.
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/default.nix b/modules/by-name/nv/nvim/plgs/luasnip/default.nix
index 2faec553..222b5070 100644
--- a/modules/by-name/nv/nvim/plgs/luasnip/default.nix
+++ b/modules/by-name/nv/nvim/plgs/luasnip/default.nix
@@ -16,14 +16,81 @@
   cfg = config.soispha.programs.nvim;
 in {
   home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
+    keymaps = [
+      {
+        key = "<C-K>";
+        mode = ["i"];
+        action.__raw = ''
+          function()
+            require('luasnip').expand()
+          end
+        '';
+        options = {
+          # silent = true;
+          desc = "Expand the snippet";
+        };
+      }
+      {
+        key = "<C-L>";
+        mode = ["i" "s"];
+        action.__raw = ''
+          function()
+            require('luasnip').jump(1)
+          end
+        '';
+        options = {
+          # silent = true;
+          desc = "Jump forward in snippet insert nodes";
+        };
+      }
+      {
+        key = "<C-J>";
+        mode = ["i" "s"];
+        action.__raw = ''
+          function()
+            require('luasnip').jump(-1)
+          end
+        '';
+        options = {
+          # silent = true;
+          desc = "Jump backwards in snippet insert nodes";
+        };
+      }
+      {
+        key = "<C-E>";
+        mode = ["i" "s"];
+        action.__raw = ''
+          function()
+            if require('luasnip').choice_active() then
+              require('luasnip').change_choice(1)
+            end
+          end
+        '';
+        options = {
+          # silent = true;
+          desc = "Cycle through the snippets choice nodes";
+        };
+      }
+    ];
     plugins.luasnip = {
       enable = true;
+
+      settings = {
+        # Enable auto triggered snippets.
+        enable_autosnippets = true;
+
+        # Use Tab to trigger visual selection.
+        store_selection_keys = "<Tab>";
+      };
+
+      fromLua = [
+        {
+          paths = ./snippets;
+          lazyLoad = true;
+        }
+      ];
     };
-    extraConfigLuaPost = ''
-      ${lib.strings.fileContents ./lua/luasnip.lua};
-      require("luasnip.loaders.from_lua").load({paths = "${./lua/snippets}"});
-      require("luasnip.loaders.from_lua").lazy_load({paths = "${./lua/snippets}"});
-    '';
+
     extraPlugins = [
       # needed for the todo-comments snippets
       pkgs.vimPlugins.comment-nvim
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/lua/luasnip.lua b/modules/by-name/nv/nvim/plgs/luasnip/lua/luasnip.lua
deleted file mode 100644
index 88ced23a..00000000
--- a/modules/by-name/nv/nvim/plgs/luasnip/lua/luasnip.lua
+++ /dev/null
@@ -1,17 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-require("luasnip").config.set_config({
-  -- Enable auto triggered snippets
-  enable_autosnippets = true,
-
-  -- Use Tab (or some other key if you prefer) to trigger visual selection
-  store_selection_keys = "<Tab>",
-})
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/all.lua b/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/all.lua
deleted file mode 100644
index 1abb70cb..00000000
--- a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/all.lua
+++ /dev/null
@@ -1,221 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-local ls = require("luasnip")
--- auto_pairs  {{{
-local get_visual = function(args, parent)
-  if #parent.snippet.env.SELECT_RAW > 0 then
-    return sn(nil, i(1, parent.snippet.env.SELECT_RAW))
-  else
-    return sn(nil, i(1, ""))
-  end
-end
-local function char_count_same(c1, c2)
-  local line = vim.api.nvim_get_current_line()
-  -- '%'-escape chars to force explicit match (gsub accepts patterns).
-  -- second return value is number of substitutions.
-  local _, ct1 = string.gsub(line, "%" .. c1, "")
-  local _, ct2 = string.gsub(line, "%" .. c2, "")
-  return ct1 == ct2
-end
-
-local function even_count(c, ...)
-  local line = vim.api.nvim_get_current_line()
-  local _, ct = string.gsub(line, c, "")
-  return ct % 2 == 0
-end
-
--- This makes creation of pair-type snippets easier.
-local function pair(pair_begin, pair_end, file_types, condition_function)
-  -- FIXME(@Soispha): This only works if file_types == nil, otherwise the snippet does not expand.
-  -- It would be nice, if it would support both an empty array (`{}`) and nil <2023-08-27>
-  -- file_types = file_types or {};
-
-  return s(
-    { trig = pair_begin, wordTrig = false, snippetType = "autosnippet" },
-    { t({ pair_begin }), d(1, get_visual), t({ pair_end }) },
-    {
-      condition = function()
-        local filetype_check = true
-        if file_types ~= nil then filetype_check = file_types[vim.bo.filetype] or false end
-        return (not condition_function(pair_begin, pair_end)) and filetype_check
-      end,
-    }
-  )
-end
-
-local auto_pairs = {
-  pair("(", ")", nil, char_count_same),
-  pair("{", "}", nil, char_count_same),
-  pair("[", "]", nil, char_count_same),
-  pair("<", ">", { ["rust"] = true, ["tex"] = true }, char_count_same),
-  pair("'", "'", nil, even_count),
-  pair("\"", "\"", nil, even_count),
-  pair("`", "`", nil, even_count),
-}
-
-ls.add_snippets("all", auto_pairs, { type = "snippets", key = "auto_pairs" })
--- }}}
-
--- todo_comments {{{
-local calculate_comment_string = require("Comment.ft").calculate
-local utils = require("Comment.utils")
-
-local read_git_config = function(config_value)
-  local command = string.format("git config \"%s\"", config_value)
-  local handle = io.popen(command)
-  if handle == nil then return error(string.format("Failed to call `%s`.", command)) end
-  local result = handle:read("*a")
-  handle:close()
-  -- stripped = string.gsub(str, '%s+', '')
-  return string.gsub(result, "\n", "")
-end
-
-local name_to_handle = function(name)
-  -- from: https://stackoverflow.com/a/7615129
-  local split = function(inputstr, sep)
-    local t = {}
-    for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
-      table.insert(t, str)
-    end
-    return t
-  end
-
-  local parts = split(name, "%s")
-
-  local output_name = ""
-  if #parts > 2 then
-    for _, val in ipairs(parts) do
-      output_name = string.format("%s%s", output_name, val:sub(1, 1))
-    end
-  elseif #parts == 2 then
-    output_name = string.format("%s%s", parts[1]:sub(1, 1), parts[2])
-  elseif #parts == 1 then
-    output_name = parts[1]
-  else
-    -- parts is 0
-    output_name = "<NoName>"
-  end
-  return string.format("@%s", output_name:lower())
-end
-
-_G.luasnip = {}
-_G.luasnip.vars = {
-  username = function() return name_to_handle(read_git_config("user.name")) end,
-  email = function() return read_git_config("user.email") end,
-}
-
---- Get the comment string {beg,end} table
----@param ctype integer 1 for `line`-comment and 2 for `block`-comment
----@return table comment_strings {begcstring, endcstring}
-local get_cstring = function(ctype)
-  -- use the `Comments.nvim` API to fetch the comment string for the region (eq. '--%s' or '--[[%s]]' for `lua`)
-  local cstring = calculate_comment_string({ ctype = ctype, range = utils.get_region() }) or vim.bo.commentstring
-  -- as we want only the strings themselves and not strings ready for using `format` we want to split the left and right side
-  local left, right = utils.unwrap_cstr(cstring)
-  -- create a `{left, right}` table for it
-  return { left, right }
-end
-
---- Options for marks to be used in a TODO comment
----@return table,table: The first table contains a node for the date, the second for the signature
-local marks = {
-  signature = function() return t("(" .. _G.luasnip.vars:username() .. ")"), t("") end,
-  date_signature = function() return t("<" .. os.date("%Y-%m-%d") .. ">"), t("(" .. _G.luasnip.vars:username() .. ")") end,
-  date = function() return t("<" .. os.date("%Y-%m-%d") .. ">"), t("") end,
-  empty = function() return t(""), t("") end,
-}
-
----@param alias string
----@param opts table
----@param mark_function function: This function should return two nodes
----@return table: Returns the comment node
-local todo_snippet_nodes = function(alias, opts, mark_function)
-  local date_node, signature_node = mark_function()
-  -- format them into the actual snippet
-  local comment_node = fmta("<> <><>: <> <> <>", {
-    f(function()
-      return get_cstring(opts.ctype)[1] -- get <comment-string[1]>
-    end),
-    t(alias), -- [name-of-comment]
-    signature_node,
-    i(0), -- {comment-text}
-    date_node,
-    f(function()
-      return get_cstring(opts.ctype)[2] -- get <comment-string[2]>
-    end),
-  })
-  return comment_node
-end
-
---- Generate a TODO comment snippet with an automatic description and docstring
----@param context table merged with the generated context table `trig` must be specified
----@param alias string of aliases for the todo comment (ex.: {FIX, ISSUE, FIXIT, BUG})
----@param opts table merged with the snippet opts table
----@param mark_function function: The function used to get the marks
-local todo_snippet = function(context, alias, opts, mark_function)
-  opts = opts or {}
-  context = context or {}
-  if not context.trig then
-    return error("context doesn't include a `trig` key which is mandatory", 2) -- all we need from the context is the trigger
-  end
-  opts.ctype = opts.ctype or 1 -- comment type can be passed in the `opts` table, but if it is not, we have to ensure, it is defined
-  local alias_string = alias -- `choice_node` documentation
-  context.name = context.name or (alias_string .. " comment") -- generate the `name` of the snippet if not defined
-  context.dscr = context.dscr or (alias_string .. " comment with a signature-mark") -- generate the `dscr` if not defined
-  context.docstring = context.docstring or (" {1:" .. alias_string .. "}: {3} <{2:mark}>{0} ") -- generate the `docstring` if not defined
-  local comment_node = todo_snippet_nodes(alias, opts, mark_function)
-  return s(context, comment_node, opts) -- the final todo-snippet constructed from our parameters
-end
-
----@param context table: The luasnip context
----@param opts table: The luasnip opts table, needs to have a ctype set
----@param aliases string: All aliases for a name
----@param marks table: Possible marks to account in snipped generation
----@return table: All possible snippets build from the marks
-local process_marks = function(context, aliases, opts, marks)
-  local output = {}
-  for mark_name, mark_function in pairs(marks) do
-    local contex_trig_local = context.trig
-    context.trig = context.trig .. "-" .. mark_name
-    output[#output + 1] = todo_snippet(context, aliases, opts, mark_function)
-    context.trig = contex_trig_local
-  end
-  return output
-end
-
-local todo_snippet_specs = {
-  { { trig = "todo" }, { "TODO" }, { ctype = 1 } },
-  { { trig = "fix" }, { "FIXME", "ISSUE" }, { ctype = 1 } },
-  { { trig = "hack" }, { "HACK" }, { ctype = 1 } },
-  { { trig = "warn" }, { "WARNING" }, { ctype = 1 } },
-  { { trig = "perf" }, { "PERFORMANCE", "OPTIMIZE" }, { ctype = 1 } },
-  { { trig = "note" }, { "NOTE", "INFO" }, { ctype = 1 } },
-
-  -- NOTE: Block commented todo-comments
-  { { trig = "todob" }, { "TODO" }, { ctype = 2 } },
-  { { trig = "fixb" }, { "FIXME", "ISSUE" }, { ctype = 2 } },
-  { { trig = "hackb" }, { "HACK" }, { ctype = 2 } },
-  { { trig = "warnb" }, { "WARNING" }, { ctype = 2 } },
-  { { trig = "perfb" }, { "PERF", "PERFORMANCE", "OPTIM", "OPTIMIZE" }, { ctype = 2 } },
-  { { trig = "noteb" }, { "NOTE", "INFO" }, { ctype = 2 } },
-}
-
-local todo_comment_snippets = {}
-for _, v in ipairs(todo_snippet_specs) do
-  local snippets = process_marks(v[1], v[2][1], v[3], marks)
-  for _, value in pairs(snippets) do
-    table.insert(todo_comment_snippets, value)
-  end
-end
-
-ls.add_snippets("all", todo_comment_snippets, { type = "snippets", key = "todo_comments" })
-
--- }}}
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/html/html.lua b/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/html/html.lua
deleted file mode 100644
index 4d5c4c9f..00000000
--- a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/html/html.lua
+++ /dev/null
@@ -1,112 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-local get_visual = function(args, parent)
-  if #parent.snippet.env.SELECT_RAW > 0 then
-    return sn(nil, i(1, parent.snippet.env.SELECT_RAW))
-  else
-    return sn(nil, i(1))
-  end
-end
-
-local line_begin = require("luasnip.extras.expand_conditions").line_begin
-
-return {
-  -- HEADER
-  s(
-    {
-      trig = "h([123456])",
-      regTrig = true,
-      wordTrig = false,
-      snippetType = "autosnippet",
-    },
-    fmt(
-      [[
-          <h{}>{}</h{}>
-        ]],
-      {
-        f(function(_, snip) return snip.captures[1] end),
-        d(1, get_visual),
-        f(function(_, snip) return snip.captures[1] end),
-      }
-    ),
-    { condition = line_begin }
-  ), -- PARAGRAPH
-  s(
-    { trig = "pp", snippetType = "autosnippet" },
-    fmt(
-      [[
-          <p>{}</p>
-        ]],
-      { d(1, get_visual) }
-    ),
-    { condition = line_begin }
-  ), -- UNORDERED LIST
-  s(
-    { trig = "itt", snippetType = "autosnippet" },
-    fmt(
-      [[
-          <ul>
-            <li>{}</li>{}
-          </ul>
-        ]],
-      { i(1), i(0) }
-    ),
-    { condition = line_begin }
-  ), -- LIST ITEM
-  s(
-    { trig = "ii", snippetType = "autosnippet" },
-    fmt(
-      [[
-            <li>{}</li>
-        ]],
-      { d(1, get_visual) }
-    ),
-    { condition = line_begin }
-  ),
-  -- DOCUMENT TEMPLATE
-  s(
-    { trig = "base" },
-    fmt(
-      [[
-        <!doctype HTML>
-        <html lang="en">
-        <head>
-          <meta charset="UTF-8">
-          <title>{}</title>
-        </head>
-        <body>
-          {}
-        </body>
-        </html>
-        ]],
-      { i(1, "FooBar"), i(0) }
-    ),
-    { condition = line_begin }
-  ), -- ANCHOR TAG
-  s(
-    {
-      trig = "([^%l])aa",
-      regTrig = true,
-      wordTrig = false,
-      snippetType = "autosnippet",
-    },
-    fmt(
-      [[
-          {}<a href="{}">{}</a>
-        ]],
-      {
-        f(function(_, snip) return snip.captures[1] end),
-        i(1),
-        d(2, get_visual),
-      }
-    )
-  ),
-}
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/delimiter.lua b/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/delimiter.lua
deleted file mode 100644
index 371fe627..00000000
--- a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/delimiter.lua
+++ /dev/null
@@ -1,38 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-local get_visual = function(args, parent)
-  if #parent.snippet.env.SELECT_RAW > 0 then
-    return sn(nil, i(1, parent.snippet.env.SELECT_RAW))
-  else
-    return sn(nil, i(1, ""))
-  end
-end
-
-local translation_table = { ["("] = ")", ["{"] = "}", ["["] = "]" }
-
--- Return snippet tables
-return {
-  -- LEFT/RIGHT ALL BRACES
-  s(
-    {
-      trig = "([^%a])l([%(%[%{])",
-      regTrig = true,
-      wordTrig = false,
-      snippetType = "autosnippet",
-    },
-    fmta("<>\\left<><>\\right<>", {
-      f(function(_, snip) return snip.captures[1] end),
-      f(function(_, snip) return snip.captures[2] end),
-      d(1, get_visual),
-      f(function(_, snip) return translation_table[snip.captures[2]] end),
-    })
-  ),
-}
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/greek.lua b/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/greek.lua
deleted file mode 100644
index 4a5651ce..00000000
--- a/modules/by-name/nv/nvim/plgs/luasnip/lua/snippets/tex/greek.lua
+++ /dev/null
@@ -1,47 +0,0 @@
--- nixos-config - My current NixOS configuration
---
--- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
--- SPDX-License-Identifier: GPL-3.0-or-later
---
--- This file is part of my nixos-config.
---
--- You should have received a copy of the License along with this program.
--- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
--- Return snippet tables
-return {
-  s({ trig = ";a", snippetType = "autosnippet" }, { t("\\alpha") }),
-  s({ trig = ";b", snippetType = "autosnippet" }, { t("\\beta") }),
-  s({ trig = ";g", snippetType = "autosnippet" }, { t("\\gamma") }),
-  s({ trig = ";G", snippetType = "autosnippet" }, { t("\\Gamma") }),
-  s({ trig = ";d", snippetType = "autosnippet" }, { t("\\delta") }),
-  s({ trig = ";D", snippetType = "autosnippet" }, { t("\\Delta") }),
-  s({ trig = ";e", snippetType = "autosnippet" }, { t("\\epsilon") }),
-  s({ trig = ";ve", snippetType = "autosnippet" }, { t("\\varepsilon") }),
-  s({ trig = ";z", snippetType = "autosnippet" }, { t("\\zeta") }),
-  s({ trig = ";h", snippetType = "autosnippet" }, { t("\\eta") }),
-  s({ trig = ";o", snippetType = "autosnippet" }, { t("\\theta") }),
-  s({ trig = ";vo", snippetType = "autosnippet" }, { t("\\vartheta") }),
-  s({ trig = ";O", snippetType = "autosnippet" }, { t("\\Theta") }),
-  s({ trig = ";k", snippetType = "autosnippet" }, { t("\\kappa") }),
-  s({ trig = ";l", snippetType = "autosnippet" }, { t("\\lambda") }),
-  s({ trig = ";L", snippetType = "autosnippet" }, { t("\\Lambda") }),
-  s({ trig = ";m", snippetType = "autosnippet" }, { t("\\mu") }),
-  s({ trig = ";n", snippetType = "autosnippet" }, { t("\\nu") }),
-  s({ trig = ";x", snippetType = "autosnippet" }, { t("\\xi") }),
-  s({ trig = ";X", snippetType = "autosnippet" }, { t("\\Xi") }),
-  s({ trig = ";i", snippetType = "autosnippet" }, { t("\\pi") }),
-  s({ trig = ";I", snippetType = "autosnippet" }, { t("\\Pi") }),
-  s({ trig = ";r", snippetType = "autosnippet" }, { t("\\rho") }),
-  s({ trig = ";s", snippetType = "autosnippet" }, { t("\\sigma") }),
-  s({ trig = ";S", snippetType = "autosnippet" }, { t("\\Sigma") }),
-  s({ trig = ";t", snippetType = "autosnippet" }, { t("\\tau") }),
-  s({ trig = ";f", snippetType = "autosnippet" }, { t("\\phi") }),
-  s({ trig = ";vf", snippetType = "autosnippet" }, { t("\\varphi") }),
-  s({ trig = ";F", snippetType = "autosnippet" }, { t("\\Phi") }),
-  s({ trig = ";c", snippetType = "autosnippet" }, { t("\\chi") }),
-  s({ trig = ";p", snippetType = "autosnippet" }, { t("\\psi") }),
-  s({ trig = ";P", snippetType = "autosnippet" }, { t("\\Psi") }),
-  s({ trig = ";w", snippetType = "autosnippet" }, { t("\\omega") }),
-  s({ trig = ";W", snippetType = "autosnippet" }, { t("\\Omega") }),
-}
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/snippets/all.lua b/modules/by-name/nv/nvim/plgs/luasnip/snippets/all.lua
new file mode 100644
index 00000000..371f5539
--- /dev/null
+++ b/modules/by-name/nv/nvim/plgs/luasnip/snippets/all.lua
@@ -0,0 +1,338 @@
+-- nixos-config - My current NixOS configuration
+--
+-- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+-- SPDX-License-Identifier: GPL-3.0-or-later
+--
+-- This file is part of my nixos-config.
+--
+-- You should have received a copy of the License along with this program.
+-- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+local ls = require("luasnip")
+local fmt = require("luasnip.extras.fmt").fmt
+
+--- Get the comment string {begin,end} table
+---
+---@param comment_type integer 1 for `line`-comment and 2 for `block`-comment
+---@return table comment_strings {["begin"]=begin_comment_string, ["end"]=end_comment_string}
+local get_comment_string = function(comment_type)
+  local calculate_comment_string = require("Comment.ft").calculate
+  local utils = require("Comment.utils")
+
+  -- use the `Comments.nvim` API to fetch the comment string for the region (eq. '--%s' or '--[[%s]]' for `lua`)
+  local cstring =
+    calculate_comment_string({ ctype = comment_type; range = utils.get_region(); })
+
+  if cstring == nil then
+    -- TODO: Use `vim.bo.commentstring` <2025-05-02>
+
+    -- Use some useful default values.
+    return { ["begin"] = "#"; ["end"] = ""; }
+  end
+
+  -- as we want only the strings themselves and not strings ready for using `format` we want to split the left and right side
+  local left, right = utils.unwrap_cstr(cstring)
+
+  -- create a `{left, right}` table for it
+  return { ["begin"] = left; ["end"] = right; }
+end
+
+--- Wraps a table of snippet nodes in two comment function nodes.
+---
+---@param comment_type integer 1 for `line`-comment and 2 for `block`-comment
+---@param nodes table The nodes that should be wrapped
+---@return table wrapped_nodes The now wrapped `nodes` table.
+local wrap_snippet_in_comments = function(comment_type, nodes)
+  local output = {}
+
+  table.insert(output, ls.function_node(function()
+    return get_comment_string(comment_type)["begin"]
+  end))
+
+
+  for _, v in ipairs(nodes) do
+    table.insert(output, v)
+  end
+
+  table.insert(output, ls.function_node(function()
+    return get_comment_string(comment_type)["end"]
+  end))
+
+  return output
+end
+
+-- auto_pairs  {{{
+local get_visual = function(_, parent)
+  if #parent.snippet.env.SELECT_RAW > 0 then
+    return ls.snippet_node(nil, ls.insert_node(1, parent.snippet.env.SELECT_RAW))
+  else
+    return ls.snippet_node(nil, ls.insert_node(1, ""))
+  end
+end
+
+local function char_count_same(c1, c2)
+  local line = vim.api.nvim_get_current_line()
+  -- '%'-escape chars to force explicit match (gsub accepts patterns).
+  -- second return value is number of substitutions.
+  local _, ct1 = string.gsub(line, "%" .. c1, "")
+  local _, ct2 = string.gsub(line, "%" .. c2, "")
+  return ct1 == ct2
+end
+
+local function even_count(c, ...)
+  local line = vim.api.nvim_get_current_line()
+  local _, ct = string.gsub(line, c, "")
+  return ct % 2 == 0
+end
+
+-- This makes creation of pair-type snippets easier.
+local function pair(pair_begin, pair_end, file_types, condition_function)
+  -- FIXME(@Soispha): This only works if file_types == nil, otherwise the snippet does not expand.
+  -- It would be nice, if it would support both an empty array (`{}`) and nil <2023-08-27>
+  -- file_types = file_types or {};
+
+  return ls.snippet(
+    {
+      trig = pair_begin;
+      wordTrig = false;
+      snippetType = "autosnippet";
+    },
+    {
+      ls.text_node({ pair_begin; });
+      ls.dynamic_node(1, get_visual);
+      ls.text_node({ pair_end; });
+    },
+    {
+      condition = function()
+        local filetype_check = true
+
+        if file_types ~= nil then
+          filetype_check = file_types[vim.bo.filetype] or false
+        end
+
+        return (not condition_function(pair_begin, pair_end)) and filetype_check
+      end;
+    }
+  )
+end
+
+local auto_pairs = {
+  pair("(", ")", nil, char_count_same);
+  pair("{", "}", nil, char_count_same);
+  pair("[", "]", nil, char_count_same);
+  pair("<", ">", { ["rust"] = true; ["tex"] = true; }, char_count_same);
+  pair("'", "'", nil, even_count);
+  pair("\"", "\"", nil, even_count);
+  pair("`", "`", nil, even_count);
+}
+
+ls.add_snippets("all", auto_pairs, { type = "snippets"; key = "auto_pairs"; })
+-- }}}
+
+-- todo_comments {{{
+local read_git_config = function(config_value)
+  local command = string.format("git config \"%s\"", config_value)
+
+  local handle = io.popen(command)
+  if handle == nil then
+    return error(string.format("Failed to call `%s`.", command))
+  end
+
+  local result = handle:read("*a")
+  handle:close()
+
+  -- stripped = string.gsub(str, '%s+', '')
+  return string.gsub(result, "\n", "")
+end
+
+--- Create a @handle from a full name.
+---
+--- Example:
+--- “Benedikt Peetz” -> “@bpeetz”
+local handle_from_name = function(name)
+  -- from: https://stackoverflow.com/a/7615129
+  local split = function(inputstr, sep)
+    local t = {}
+    for str in string.gmatch(inputstr, "([^" .. sep .. "]+)") do
+      table.insert(t, str)
+    end
+    return t
+  end
+
+  -- Split on spaces
+  local parts = split(name, "%s")
+
+  local output_name = ""
+
+  if #parts > 2 then
+    -- Only use the first chars.
+    --
+    -- Example:
+    -- “Richard Matthew Stallman” -> “rms”
+    for _, val in ipairs(parts) do
+      output_name = string.format("%s%s", output_name, val:sub(1, 1))
+    end
+  elseif #parts == 2 then
+    output_name = string.format("%s%s", parts[1]:sub(1, 1), parts[2])
+  elseif #parts == 1 then
+    output_name = parts[1]
+  elseif #parts == 0 then
+    output_name = "<NoName>"
+  end
+
+  return string.format("@%s", output_name:lower())
+end
+
+--- Generate a comment snippet
+---
+---@param trig string The trigger
+---@param name string name for the comment (ex.: {FIX, ISSUE, FIXIT, BUG})
+---@param comment_type integer The comment type.
+---@param mark_function function: The function used to get the marks
+local todo_snippet = function(trig, name, comment_type, mark_function)
+  assert(trig, "context doesn't include a `trig` key which is mandatory")
+  assert(comment_type == 1 or comment_type == 2)
+
+  local context = {}
+  context.name = name .. " comment"
+  context.trig = trig
+
+  local date_node, signature_node = mark_function()
+
+  local nodes = fmt("{} {}{}: {} {} {}", wrap_snippet_in_comments(comment_type, {
+    ls.text_node(name);
+    signature_node;
+    ls.insert_node(1, "content");
+    date_node;
+  }))
+
+  return ls.snippet(context, nodes, { ctype = comment_type; })
+end
+
+---@param trigger string: The luasnip trigger
+---@param comment_type integer: The luasnip comment type
+---@param name string: All aliases for a name
+---@return table: All possible snippets build from the marks
+local process_marks = function(trigger, name, comment_type)
+  local username = function()
+    return handle_from_name(read_git_config("user.name"))
+  end
+
+  local marks = {
+    signature = function()
+      return ls.text_node("(" .. username() .. ")"), ls.text_node("")
+    end;
+
+    date_signature = function()
+      return ls.text_node("<" .. os.date("%Y-%m-%d") .. ">"), ls.text_node("(" .. username() .. ")")
+    end;
+
+    date = function()
+      return ls.text_node("<" .. os.date("%Y-%m-%d") .. ">"), ls.text_node("")
+    end;
+
+    empty = function()
+      return ls.text_node(""), ls.text_node("")
+    end;
+  }
+
+  local output = {}
+  for mark_name, mark_function in pairs(marks) do
+    local trig = trigger .. "-" .. mark_name
+
+    output[#output + 1] = todo_snippet(trig, name, comment_type, mark_function)
+  end
+
+  return output
+end
+
+local todo_snippet_specs = {
+  { { trig = "todo"; };  { "TODO"; };                                     { ctype = 1; }; };
+  { { trig = "fix"; };   { "FIXME"; "ISSUE"; };                           { ctype = 1; }; };
+  { { trig = "hack"; };  { "HACK"; };                                     { ctype = 1; }; };
+  { { trig = "warn"; };  { "WARNING"; };                                  { ctype = 1; }; };
+  { { trig = "perf"; };  { "PERFORMANCE"; "OPTIMIZE"; };                  { ctype = 1; }; };
+  { { trig = "note"; };  { "NOTE"; "INFO"; };                             { ctype = 1; }; };
+
+  -- NOTE: Block commented todo-comments
+  { { trig = "todob"; }; { "TODO"; };                                     { ctype = 2; }; };
+  { { trig = "fixb"; };  { "FIXME"; "ISSUE"; };                           { ctype = 2; }; };
+  { { trig = "hackb"; }; { "HACK"; };                                     { ctype = 2; }; };
+  { { trig = "warnb"; }; { "WARNING"; };                                  { ctype = 2; }; };
+  { { trig = "perfb"; }; { "PERF"; "PERFORMANCE"; "OPTIM"; "OPTIMIZE"; }; { ctype = 2; }; };
+  { { trig = "noteb"; }; { "NOTE"; "INFO"; };                             { ctype = 2; }; };
+}
+
+local todo_comment_snippets = {}
+for _, v in ipairs(todo_snippet_specs) do
+  local snippets = process_marks(v[1].trig, v[2][1], v[3].ctype)
+  for _, value in pairs(snippets) do
+    table.insert(todo_comment_snippets, value)
+  end
+end
+
+ls.add_snippets("all", todo_comment_snippets, { type = "snippets"; key = "todo_comments"; })
+-- }}}
+
+-- spdx snippets {{{
+local generate_spdx_snippet = function(comment_type, spdx_license_expr, trigger)
+  assert(trigger, "context doesn't include a `trig` key which is mandatory")
+  assert(comment_type == 1 or comment_type == 2)
+
+  local context = {}
+  context.name = trigger .. " spdx snippet expr"
+  context.trig = trigger
+
+
+  local nodes = {
+    fmt("{} SPDX-SnippetBegin {}", wrap_snippet_in_comments(comment_type, {}));
+
+    fmt("{} SPDX-SnippetCopyrightText: {} {} <{}> {}",
+        wrap_snippet_in_comments(comment_type, {
+          ls.insert_node(1, "year");
+          ls.insert_node(2, "author");
+          ls.insert_node(3, "email");
+        })
+    );
+
+    fmt("{} SPDX-License-Identifier: {} {}", wrap_snippet_in_comments(comment_type, {
+      ls.text_node(spdx_license_expr);
+    }));
+
+    { ls.insert_node(4, "content"); };
+
+    fmt("{} SPDX-SnippetEnd {}", wrap_snippet_in_comments(comment_type, {}));
+
+    { ls.insert_node(0); };
+  }
+
+  local newline_nodes = {}
+  for _, sub_nodes in ipairs(nodes) do
+    for _, node in ipairs(sub_nodes) do
+      table.insert(newline_nodes, node)
+    end
+
+    -- luasnip requires newlines to be encoded like this:
+    table.insert(newline_nodes, ls.text_node({ ""; ""; }))
+  end
+
+  return ls.snippet(context, newline_nodes, { ctype = comment_type; })
+end
+
+local spdx = {
+  { trigger = "spdx-AGPL3+"; license = "AGPL-3.0-or-later"; };
+  { trigger = "spdx-GPL3+";  license = "GPL-3.0-or-later"; };
+  { trigger = "spdx-MIT";    license = "MIT"; };
+}
+
+local spdx_snippets = {}
+for _, value in ipairs(spdx) do
+  local snippet = generate_spdx_snippet(1, value.license, value.trigger)
+  table.insert(spdx_snippets, snippet)
+
+  snippet = generate_spdx_snippet(2, value.license, value.trigger .. "-block")
+  table.insert(spdx_snippets, snippet)
+end
+
+ls.add_snippets("all", spdx_snippets, { type = "snippets"; key = "spdx_snippets"; })
+-- }}}
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/delimiter.lua b/modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/delimiter.lua
new file mode 100644
index 00000000..bcd128f7
--- /dev/null
+++ b/modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/delimiter.lua
@@ -0,0 +1,41 @@
+-- nixos-config - My current NixOS configuration
+--
+-- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+-- SPDX-License-Identifier: GPL-3.0-or-later
+--
+-- This file is part of my nixos-config.
+--
+-- You should have received a copy of the License along with this program.
+-- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+local ls = require("luasnip")
+local fmt = require("luasnip.extras.fmt").fmt
+
+local get_visual = function(_, parent)
+  if #parent.snippet.env.SELECT_RAW > 0 then
+    return ls.snippet_node(nil, ls.insert_node(1, parent.snippet.env.SELECT_RAW))
+  else
+    return ls.snippet_node(nil, ls.insert_node(1, ""))
+  end
+end
+
+local translation_table = { ["("] = ")"; ["{"] = "}"; ["["] = "]"; }
+
+-- Return snippet tables
+return {
+  -- LEFT/RIGHT ALL BRACES
+  ls.snippet(
+    {
+      trig = "([^%a])l([%(%[%{])";
+      regTrig = true;
+      wordTrig = false;
+      snippetType = "autosnippet";
+    },
+    fmt("{}\\left{}{}\\right{}", {
+      ls.function_node(function(_, snip) return snip.captures[1] end);
+      ls.function_node(function(_, snip) return snip.captures[2] end);
+      ls.dynamic_node(1, get_visual);
+      ls.function_node(function(_, snip) return translation_table[snip.captures[2]] end);
+    })
+  );
+}
diff --git a/modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/greek.lua b/modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/greek.lua
new file mode 100644
index 00000000..21aa7414
--- /dev/null
+++ b/modules/by-name/nv/nvim/plgs/luasnip/snippets/tex/greek.lua
@@ -0,0 +1,49 @@
+-- nixos-config - My current NixOS configuration
+--
+-- Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+-- SPDX-License-Identifier: GPL-3.0-or-later
+--
+-- This file is part of my nixos-config.
+--
+-- You should have received a copy of the License along with this program.
+-- If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+local ls = require("luasnip")
+
+-- Return snippet tables
+return {
+  ls.snippet({ trig = ";a"; snippetType = "autosnippet"; }, { ls.text_node("\\alpha"); });
+  ls.snippet({ trig = ";b"; snippetType = "autosnippet"; }, { ls.text_node("\\beta"); });
+  ls.snippet({ trig = ";g"; snippetType = "autosnippet"; }, { ls.text_node("\\gamma"); });
+  ls.snippet({ trig = ";G"; snippetType = "autosnippet"; }, { ls.text_node("\\Gamma"); });
+  ls.snippet({ trig = ";d"; snippetType = "autosnippet"; }, { ls.text_node("\\delta"); });
+  ls.snippet({ trig = ";D"; snippetType = "autosnippet"; }, { ls.text_node("\\Delta"); });
+  ls.snippet({ trig = ";e"; snippetType = "autosnippet"; }, { ls.text_node("\\epsilon"); });
+  ls.snippet({ trig = ";ve"; snippetType = "autosnippet"; }, { ls.text_node("\\varepsilon"); });
+  ls.snippet({ trig = ";z"; snippetType = "autosnippet"; }, { ls.text_node("\\zeta"); });
+  ls.snippet({ trig = ";h"; snippetType = "autosnippet"; }, { ls.text_node("\\eta"); });
+  ls.snippet({ trig = ";o"; snippetType = "autosnippet"; }, { ls.text_node("\\theta"); });
+  ls.snippet({ trig = ";vo"; snippetType = "autosnippet"; }, { ls.text_node("\\vartheta"); });
+  ls.snippet({ trig = ";O"; snippetType = "autosnippet"; }, { ls.text_node("\\Theta"); });
+  ls.snippet({ trig = ";k"; snippetType = "autosnippet"; }, { ls.text_node("\\kappa"); });
+  ls.snippet({ trig = ";l"; snippetType = "autosnippet"; }, { ls.text_node("\\lambda"); });
+  ls.snippet({ trig = ";L"; snippetType = "autosnippet"; }, { ls.text_node("\\Lambda"); });
+  ls.snippet({ trig = ";m"; snippetType = "autosnippet"; }, { ls.text_node("\\mu"); });
+  ls.snippet({ trig = ";n"; snippetType = "autosnippet"; }, { ls.text_node("\\nu"); });
+  ls.snippet({ trig = ";x"; snippetType = "autosnippet"; }, { ls.text_node("\\xi"); });
+  ls.snippet({ trig = ";X"; snippetType = "autosnippet"; }, { ls.text_node("\\Xi"); });
+  ls.snippet({ trig = ";i"; snippetType = "autosnippet"; }, { ls.text_node("\\pi"); });
+  ls.snippet({ trig = ";I"; snippetType = "autosnippet"; }, { ls.text_node("\\Pi"); });
+  ls.snippet({ trig = ";r"; snippetType = "autosnippet"; }, { ls.text_node("\\rho"); });
+  ls.snippet({ trig = ";s"; snippetType = "autosnippet"; }, { ls.text_node("\\sigma"); });
+  ls.snippet({ trig = ";S"; snippetType = "autosnippet"; }, { ls.text_node("\\Sigma"); });
+  ls.snippet({ trig = ";t"; snippetType = "autosnippet"; }, { ls.text_node("\\tau"); });
+  ls.snippet({ trig = ";f"; snippetType = "autosnippet"; }, { ls.text_node("\\phi"); });
+  ls.snippet({ trig = ";vf"; snippetType = "autosnippet"; }, { ls.text_node("\\varphi"); });
+  ls.snippet({ trig = ";F"; snippetType = "autosnippet"; }, { ls.text_node("\\Phi"); });
+  ls.snippet({ trig = ";c"; snippetType = "autosnippet"; }, { ls.text_node("\\chi"); });
+  ls.snippet({ trig = ";p"; snippetType = "autosnippet"; }, { ls.text_node("\\psi"); });
+  ls.snippet({ trig = ";P"; snippetType = "autosnippet"; }, { ls.text_node("\\Psi"); });
+  ls.snippet({ trig = ";w"; snippetType = "autosnippet"; }, { ls.text_node("\\omega"); });
+  ls.snippet({ trig = ";W"; snippetType = "autosnippet"; }, { ls.text_node("\\Omega"); });
+}
diff --git a/modules/by-name/nv/nvim/plgs/neorg/default.nix b/modules/by-name/nv/nvim/plgs/neorg/default.nix
index eafc161f..5ed87f0e 100644
--- a/modules/by-name/nv/nvim/plgs/neorg/default.nix
+++ b/modules/by-name/nv/nvim/plgs/neorg/default.nix
@@ -14,7 +14,9 @@
 }: let
   cfg = config.soispha.programs.nvim;
 in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
+  # TODO: Re-active, whence neorg actually builds with all the treesitter grammars
+  # activated <2026-01-18>
+  home-manager.users.soispha.programs.nixvim = lib.mkIf false {
     extraFiles = {
       "ftplugin/norg.lua".text = ''
         ${lib.strings.fileContents ./key_mappings.lua}
@@ -53,11 +55,7 @@ in {
               __empty = null;
             };
             "core.dirman".config = {
-              workspaces = {
-                general = "~/repos/notes/general";
-                journal = "~/repos/notes/journal";
-                projects = "~/repos/notes/projects";
-              };
+              workspaces = { };
             };
             "core.export".config = {
               __empty = null;
diff --git a/modules/by-name/nv/nvim/plgs/nvim-cmp/default.nix b/modules/by-name/nv/nvim/plgs/nvim-cmp/default.nix
index 80363ba4..315f3fc7 100644
--- a/modules/by-name/nv/nvim/plgs/nvim-cmp/default.nix
+++ b/modules/by-name/nv/nvim/plgs/nvim-cmp/default.nix
@@ -14,49 +14,82 @@
 }: let
   cfg = config.soispha.programs.nvim;
 in {
-  home-manager.users.soispha.programs.nixvim.plugins.cmp = lib.mkIf cfg.enable {
-    /*
-    TODO: integrate this:
-    ```lua
-      enabled = {
-      function()
-          -- disable completion in comments
-          local context = require 'cmp.config.context'
-          -- keep command mode completion enabled when cursor is in a comment
-          -- te
-          if vim.api.nvim_get_mode().mode == 'c' then
-              return true
-          else
-              return not context.in_treesitter_capture("comment")
-                  and not context.in_syntax_group("Comment")
+  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
+    opts.completeopt = [
+      "menu" # Show completions in a menu
+      "menuone" # Also open menu, when only one completion exists
+      "noselect" # Do not pre select one of the completions
+    ];
+
+    keymaps = [
+      {
+        key = "hh";
+        mode = ["i"];
+        action.__raw = ''
+          function()
+            require('cmp').select_next_item()
           end
-      end
-      },
-    ```
-    */
-    enable = true;
-    autoEnableSources = true;
-    settings = {
-      mapping = {
-        # TODO: add support for desc and which key here
-        "<C-d>" = "cmp.mapping.scroll_docs(-4)"; # desc = "Scroll up by four lines"
-        "<C-f>" = "cmp.mapping.scroll_docs(4)"; # desc = "Scroll down by four lines"
-        "HH" = "cmp.mapping.complete()"; # desc = "Confirm snipped"
-      };
+        '';
+        options.desc = "go forward in completion menu";
+      }
+      {
+        key = "uu";
+        mode = ["i"];
+        action.__raw = ''
+          function()
+            require('cmp').confirm()
+          end
+        '';
+        options.desc = "confirm the selected item";
+      }
+
+      {
+        key = "<C-d>";
+        mode = ["i"];
+        action.__raw = ''
+          function()
+            require('cmp').mapping.scroll_docs(-4)
+          end
+        '';
+        options.desc = "Scroll up by four lines";
+      }
+      {
+        key = "<C-f>";
+        mode = ["i"];
+        action.__raw = ''
+          function()
+            require('cmp').mapping.scroll_docs(4)
+          end
+        '';
+        options.desc = "Scroll down by four lines";
+      }
+    ];
+
+    plugins.cmp = {
+      enable = true;
+      autoEnableSources = true;
 
-      snippet.expand = "function(args) require('luasnip').lsp_expand(args.body) end";
+      settings = {
+        mapping = {};
 
-      sources = [
-        {name = "nvim_lsp";}
-        {name = "luasnip";}
-        {name = "path";}
-        {name = "git";} # TODO: I might want to add config to allow all issues/prs <2023-10-16>
-        # {name = "convertionalcommits";} # TODO: Useless without commitlint [https://commitlint.js.org/] <2023-10-16>
-        # {name = "rg";} # TODO: This might really RIP-grep my system <2023-10-16>
-        # {name = "buffer";}
-        # {name = "digraphs";}
-        {name = "calc";}
-      ];
+        snippet.expand.__raw = ''
+          function(args)
+            require('luasnip').lsp_expand(args.body)
+          end
+        '';
+
+        sources = [
+          {name = "nvim_lsp";}
+          {name = "luasnip";}
+          {name = "path";}
+          {name = "git";} # TODO: I might want to add config to allow all issues/prs <2023-10-16>
+          # {name = "convertionalcommits";} # TODO: Useless without commitlint [https://commitlint.js.org/] <2023-10-16>
+          # {name = "rg";} # TODO: This might really RIP-grep my system <2023-10-16>
+          # {name = "buffer";}
+          # {name = "digraphs";}
+          {name = "calc";}
+        ];
+      };
     };
   };
 }
diff --git a/modules/by-name/nv/nvim/plgs/raw_plugins/default.nix b/modules/by-name/nv/nvim/plgs/raw_plugins/default.nix
deleted file mode 100644
index c981ee08..00000000
--- a/modules/by-name/nv/nvim/plgs/raw_plugins/default.nix
+++ /dev/null
@@ -1,26 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  config,
-  lib,
-  ...
-}: let
-  cfg = config.soispha.programs.nvim;
-in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
-    # Not all plugins have own modules
-    # You can add missing plugins here
-    # `pkgs.vimExtraPlugins` is added by the overlay you added at the beginning
-    # For a list of available plugins, look here:
-    # https://github.com/jooooscha/nixpkgs-vim-extra-plugins/blob/main/plugins.md
-    extraPlugins = [
-    ];
-  };
-}
diff --git a/modules/by-name/nv/nvim/plgs/treesitter/default.nix b/modules/by-name/nv/nvim/plgs/treesitter/default.nix
index c8b48cd1..1377cb8a 100644
--- a/modules/by-name/nv/nvim/plgs/treesitter/default.nix
+++ b/modules/by-name/nv/nvim/plgs/treesitter/default.nix
@@ -26,45 +26,23 @@ in {
     plugins.treesitter = {
       enable = true;
 
+      highlight.enable = true;
+      indent.enable = true;
+      folding.enable = false;
+
       # inject nixvim specific highlighting (eg in extraConfigLua).
       nixvimInjections = true;
 
-      nixGrammars = true;
-      grammarPackages =
-        # Append the `tree-sitter-yts` grammar to all the other grammars.
-        # TODO: Find a better way to do this. <2024-11-08>
-        config.home-manager.users.soispha.programs.nixvim.plugins.treesitter.package.passthru.allGrammars
-        ++ [pkgs.tree-sitter-yts];
-
-      settings = {
-        auto_install = false;
-        ensureInstalled = "all";
-        indent.enable = true;
-        disabledLanguages = [];
+      grammarPackages = pkgs.vimPlugins.nvim-treesitter.allGrammars ++ [pkgs.tree-sitter-yts];
 
-        highlight = {
-          enable = true;
-          disable = [];
+      # Register the parser to filetype
+      languageRegister.yts = "yts";
+    };
 
-          #  Setting this to true will run `:h syntax` and tree-sitter at the same time.
-          #  Set this to `true` if you depend on 'syntax' being enabled (like for indentation).
-          #  Using this option may slow down your editor; and you may see some duplicate highlights.
-          #  Instead of true it can also be a list of languages
-          additionalVimRegexHighlighting = ["latex"];
-        };
+    # TODO: Is that necessary? <2026-01-18>
+    # extraPlugins = [pkgs.tree-sitter-yts];
 
-        incrementalSelection = {
-          enable = true;
-          keymaps = {
-            # TODO: include these in the which-key description
-            initSelection = "gnn"; #  set to `false` to disable one of the mappings
-            nodeIncremental = "grn";
-            scopeIncremental = "grc";
-            nodeDecremental = "grm";
-          };
-        };
-      };
-    };
+    # TODO: Remove this by moving the queries in the package to `queries/<lang>/...`' <2026-01-18>
     extraFiles = {
       "queries/yts/highlights.scm".text = ''
         ${lib.strings.fileContents "${pkgs.tree-sitter-yts}/queries/highlights.scm"}
diff --git a/modules/by-name/nv/nvim/plgs/vim-tex/default.nix b/modules/by-name/nv/nvim/plgs/vim-tex/default.nix
index 739b69d9..71422f94 100644
--- a/modules/by-name/nv/nvim/plgs/vim-tex/default.nix
+++ b/modules/by-name/nv/nvim/plgs/vim-tex/default.nix
@@ -14,7 +14,8 @@
 }: let
   cfg = config.soispha.programs.nvim;
 in {
-  home-manager.users.soispha.programs.nixvim = lib.mkIf cfg.enable {
+  # TODO: Do I still need this module at all? <2026-01-18>
+  home-manager.users.soispha.programs.nixvim = lib.mkIf false {
     opts.conceallevel = 0;
 
     plugins.vimtex = {
diff --git a/modules/by-name/oo/oomd/module.nix b/modules/by-name/oo/oomd/module.nix
new file mode 100644
index 00000000..ca332939
--- /dev/null
+++ b/modules/by-name/oo/oomd/module.nix
@@ -0,0 +1,18 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.systemd.oomd;
+in {
+  options.soispha.systemd.oomd = {
+    enable = (lib.mkEnableOption "oomd") // {default = config.systemd.oomd.enable;};
+  };
+
+  config = lib.mkIf cfg.enable {
+    users = {
+      users.systemd-oom.uid = config.soispha.constants.ids.uids.systemd-oom;
+      groups.systemd-oom.gid = config.soispha.constants.ids.gids.systemd-oom;
+    };
+  };
+}
diff --git a/modules/by-name/op/openssh/module.nix b/modules/by-name/op/openssh/module.nix
index 97cf7fd7..f77c357b 100644
--- a/modules/by-name/op/openssh/module.nix
+++ b/modules/by-name/op/openssh/module.nix
@@ -7,18 +7,36 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  services.openssh = {
-    enable = true;
-    hostKeys = [
-      {
-        path = "/srv/sshd/ssh_host_ed25519_key";
-        rounds = 1000;
-        type = "ed25519";
-      }
-    ];
-    settings = {
-      PasswordAuthentication = false;
+{
+  config,
+  lib,
+  libraries,
+  ...
+}: let
+  cfg = config.soispha.services.openssh;
+in {
+  options.soispha.services.openssh = {
+    enable = libraries.base.options.mkEnable "openssh";
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.openssh = {
+      enable = true;
+      hostKeys = [
+        {
+          path = "/srv/sshd/ssh_host_ed25519_key";
+          rounds = 1000;
+          type = "ed25519";
+        }
+      ];
+
+      settings = {
+        PasswordAuthentication = false;
+      };
+    };
+    users = {
+      users.sshd.uid = config.soispha.constants.ids.uids.sshd;
+      groups.sshd.gid = config.soispha.constants.ids.gids.sshd;
     };
   };
 }
diff --git a/modules/by-name/po/polkit/module.nix b/modules/by-name/po/polkit/module.nix
index c6d1c750..d8dd51b0 100644
--- a/modules/by-name/po/polkit/module.nix
+++ b/modules/by-name/po/polkit/module.nix
@@ -17,7 +17,10 @@ in {
   options.soispha.polkit = {
     enable = lib.mkEnableOption "polkit";
   };
+
   config = lib.mkIf cfg.enable {
     security.polkit.enable = true;
+
+    users.groups.polkituser.gid = config.soispha.constants.ids.gids.polkituser;
   };
 }
diff --git a/modules/by-name/pi/printing/module.nix b/modules/by-name/pr/printing/module.nix
index cfcd2154..2e230570 100644
--- a/modules/by-name/pi/printing/module.nix
+++ b/modules/by-name/pr/printing/module.nix
@@ -19,6 +19,10 @@ in {
   };
 
   config = lib.mkIf cfg.enable {
+    soispha.impermanence.directories = [
+      "/var/lib/cups"
+    ];
+
     services.avahi = {
       enable = true;
       nssmdns4 = true;
@@ -26,29 +30,21 @@ in {
       openFirewall = true;
     };
 
+    users = {
+      users.avahi.uid = config.soispha.constants.ids.uids.avahi;
+      groups.avahi.gid = config.soispha.constants.ids.gids.avahi;
+      groups.lpadmin.gid = config.soispha.constants.ids.gids.lpadmin;
+    };
+
     services.printing = {
       enable = true;
       startWhenNeeded = true;
       webInterface = true;
 
       # deletes `/var/cache/cups`, `/var/lib/cups` and `/var/spool/cups` on cups startup
-      stateless = true;
+      stateless = false;
 
       drivers = [];
     };
-
-    hardware = {
-      printers = {
-        ensurePrinters = [
-          {
-            name = "Brother";
-            description = "Brother DCP-9022CDW";
-            model = "everywhere";
-            deviceUri = "dnssd://Brother%20DCP-9022CDW._ipp._tcp.local/?uuid=e3248000-80ce-11db-8000-30055c773bcf";
-          }
-        ];
-        ensureDefaultPrinter = "Brother";
-      };
-    };
   };
 }
diff --git a/modules/by-name/qu/qutebrowser/include/redirects.py b/modules/by-name/qu/qutebrowser/include/redirects.py
new file mode 100644
index 00000000..63a44ecf
--- /dev/null
+++ b/modules/by-name/qu/qutebrowser/include/redirects.py
@@ -0,0 +1,64 @@
+# Based on the redirect scripts from here:
+# - https://github.com/Phantop/dotfiles/blob/9f6256820dbb99cdf5afd373b74d93fe8b8972d7/qutebrowser/include/redirects.py
+# - https://gitlab.com/jgkamat/dotfiles/-/blob/0e5f05d347079a9839cb2c7878fd81d9850928ce/qutebrowser/.config/qutebrowser/pyconfig/redirectors.py
+
+from qutebrowser.api import interceptor, message
+
+import operator
+import typing
+
+from PyQt6.QtCore import QUrl
+
+
+def get_host(url: QUrl, base: bool = False) -> str:
+    host = url.host()
+    if base:
+        # www.someSite.com -> someSite.com
+        return ".".join(host.split(".")[-2:])
+    else:
+        return host
+
+
+def partial(func, *part_args):
+    def wrapper(*extra_args):
+        return func(*part_args, *extra_args)
+
+    return wrapper
+
+
+def farside_redir(target: str, url: QUrl) -> bool:
+    url.setHost("farside.link")
+    url.setPath("/" + target + url.path())
+    return True
+
+
+# Any return value other than a literal 'False' means we redirect
+REDIRECT_MAP: typing.Dict[str, typing.Callable[..., typing.Optional[bool]]] = {
+    "reddit.com": operator.methodcaller("setHost", "redlib.vhack.eu"),
+    # Source: https://libredirect.github.io/
+    "medium.com": partial(farside_redir, "scribe"),
+    "stackoverflow.com": partial(farside_redir, "anonymousoverflow"),
+    # "goodreads.com": partial(farside_redir, "biblioreads"),
+}
+
+
+def rewrite(info: interceptor.Request):
+    if (
+        info.resource_type != interceptor.ResourceType.main_frame
+        or info.request_url.scheme() in {"data", "blob"}
+    ):
+        return
+
+    url = info.request_url
+
+    redir = REDIRECT_MAP.get(get_host(url, base=False))
+    if redir is None:
+        # Try again, but now only with the base host.
+        redir = REDIRECT_MAP.get(get_host(url, base=True))
+
+    if redir is not None and redir(url) is not False:
+        message.info("Redirecting to " + url.toString())
+        info.redirect(url)
+
+
+interceptor.register(rewrite)
diff --git a/modules/by-name/qu/qutebrowser/module.hm.nix b/modules/by-name/qu/qutebrowser/module.hm.nix
new file mode 100644
index 00000000..3f0f0d52
--- /dev/null
+++ b/modules/by-name/qu/qutebrowser/module.hm.nix
@@ -0,0 +1,490 @@
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}: let
+  cfg = config.programs.qutebrowser;
+
+  /*
+  Flattens an attribute set of key values to stringified keys and their values.
+
+  This is necessary, as qutebrowser only understands key value settings.
+
+  ## Determining the keys and values
+
+  Currently, this function will recursively iterate through the `configAttrs`, whilst
+  adding up the attribute keys, until one of the following conditions apply:
+  - The value is not an attribute set.
+  - The value is “marked” as being a raw attribute set. This is done automatically via the
+    `apply` functions in the option that take attribute sets (i.e., dictionaries) as
+    values.
+
+  ## Marking an attribute set as value
+  Currently, this function assumes that a attribute set is meant as value, if it's key is
+  `__raw`. For example:
+  ```nix
+    {
+      bindings.command.__raw = {
+          normal.L = "close";
+      };
+    }
+  ```
+
+  # Type
+
+  flattenSettings :: AttrSet -> [{key :: String; value :: Any}]
+
+  # Arguments
+
+  configAttrs
+  : The configuration attribute set to flatten.
+
+  # Examples
+
+  flattenSettings {aliases.__raw = {c = "close";}; colors.background = "0xffffff00";}
+  => [
+    {key = "aliases"; value = {c = "close";};}
+    {key = "colors.background"; value = "0xffffff00";}
+  ]
+  */
+  flattenSettings = let
+    isValue = aS: (builtins.attrNames aS) == ["__raw"];
+  in
+    configAttrs:
+      lib.collect (aS: (builtins.attrNames aS) == ["key" "value"]) (
+        lib.attrsets.mapAttrsRecursiveCond (a: !(isValue a)) (
+          path: value:
+            assert builtins.isList path; {
+              key = lib.concatStringsSep "." path;
+              inherit value;
+            }
+        )
+        configAttrs
+      );
+
+  pythonize = identCount: v: let
+    nextIdentCount = identCount + 2;
+    prevIdentCount = identCount - 2;
+    ident = builtins.concatStringsSep "" (builtins.genList (_: " ") identCount);
+    prevIdent = builtins.concatStringsSep "" (builtins.genList (_: " ") prevIdentCount);
+  in
+    if v == null
+    then "None"
+    else if builtins.isBool v
+    then
+      (
+        if v
+        then "True"
+        else "False"
+      )
+    else if builtins.isString v
+    then ''"${lib.escape ["\"" "\\"] v}"''
+    else if builtins.isInt v
+    then builtins.toString v
+    else if builtins.isList v
+    then
+      (
+        let
+          items = builtins.map (pythonize nextIdentCount) v;
+        in
+          if (builtins.length items) < 2
+          then "[${builtins.concatStringsSep "," items}]"
+          else "[\n${ident}${builtins.concatStringsSep ",\n${ident}" items}\n${prevIdent}]"
+      )
+    else if builtins.isAttrs v
+    then
+      if (v ? __raw && v.__raw == null)
+      # Make it possible to skip values, as we would otherwise unconditional override the
+      # non-set default values with `{}`.
+      then null
+      else if (v ? __raw && builtins.isList v.__raw)
+      # The raw value is already pre-rendered (e.g., used by the bindings.commands to use
+      # the `config.bind` functions instead of setting the keys directly.)
+      then v.__raw
+      else
+        (
+          # {key = "value"; other = "other";} -> "{'key': 'value', 'other': 'other'}"
+          let
+            items =
+              lib.attrsets.mapAttrsToList
+              (key: value: ''${pythonize nextIdentCount key}: ${pythonize nextIdentCount value}'')
+              (v.__raw or v);
+          in
+            if (builtins.length items) == 0
+            then "{}"
+            else "{\n${ident}${builtins.concatStringsSep ",\n${ident}" items}\n${prevIdent}}"
+        )
+    else builtins.throw "Cannot serialize a '${builtins.typeOf v}' as python value.";
+
+  configSet = keyValue: maybe_url: let
+    value = pythonize 2 keyValue.value;
+  in
+    if value == null
+    then ""
+    else if builtins.isList value
+    then builtins.concatStringsSep "\n" value
+    else "config.set(${pythonize 2 keyValue.key}, ${value}${
+      if (maybe_url != null)
+      then ", ${maybe_url}"
+      else ""
+    })";
+  urlConfigSet = url: conf: builtins.map (c: configSet c url) (flattenSettings conf);
+  extraConfigSet = name: path_or_string: ''config.source("${
+      if (builtins.isPath path_or_string)
+      then path_or_string
+      else pkgs.writeText name path_or_string
+    }")'';
+
+  mkRaw = value: {__raw = value;};
+  formatQuickmarks = n: s: "${n} ${s}";
+
+  settingsType = lib.types.submodule {
+    freeformType = lib.types.attrsOf lib.types.anything;
+    options = {
+      # A list of config keys, that take dicts and need special handling:
+      # (See their configdata.yml for the source of this list)
+      #    aliases
+      #    bindings.commands
+      #    bindings.default
+      #    bindings.key_mappings
+      #    content.headers.custom
+      #    content.javascript.log
+      #    hints.selectors
+      #    statusbar.padding
+      #    url.searchengines
+
+      aliases = lib.mkOption {
+        type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
+        default = null;
+        apply = mkRaw;
+      };
+
+      bindings = let
+        keyBindType = lib.types.nullOr (lib.types.attrsOf (
+          lib.types.attrsOf (
+            lib.types.nullOr (
+              lib.types.separatedString " ;; "
+            )
+          )
+        ));
+      in {
+        key_mappings = lib.mkOption {
+          type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
+          default = null;
+          apply = mkRaw;
+        };
+
+        # This is special, as we need to use the `config.bind` command, instead of the
+        # normal one.
+        commands = lib.mkOption {
+          type = keyBindType;
+          default = null;
+          apply = v:
+            if v == null
+            then null
+            else {
+              __raw =
+                lib.lists.flatten
+                (lib.mapAttrsToList
+                  (mode: mappings:
+                    lib.mapAttrsToList
+                    (key: value: "config.bind(${pythonize 0 key}, ${pythonize 0 value}, mode=${pythonize 0 mode})")
+                    mappings)
+                  v);
+            };
+          example = lib.literalExpression ''
+            {
+              normal = {
+                "<Ctrl-v>" = "spawn mpv {url}";
+                ",p" = "spawn --userscript qute-pass";
+                ",l" = '''config-cycle spellcheck.languages ["en-GB"] ["en-US"]''';
+                "<F1>" = mkMerge [
+                  "config-cycle tabs.show never always"
+                  "config-cycle statusbar.show in-mode always"
+                  "config-cycle scrolling.bar never always"
+                ];
+              };
+              prompt = {
+                "<Ctrl-y>" = "prompt-yes";
+              };
+            }
+          '';
+        };
+
+        default = lib.mkOption {
+          type = keyBindType;
+          default = null;
+          apply = mkRaw;
+        };
+      };
+
+      content = {
+        headers = {
+          custom = lib.mkOption {
+            type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
+            default = null;
+            apply = mkRaw;
+          };
+        };
+        javascript = {
+          log = lib.mkOption {
+            type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
+            default = null;
+            apply = mkRaw;
+          };
+        };
+      };
+
+      hints = {
+        selectors = lib.mkOption {
+          type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
+          default = null;
+          apply = mkRaw;
+        };
+      };
+
+      qt = {
+        environ = lib.mkOption {
+          type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
+          default = null;
+          apply = mkRaw;
+        };
+      };
+
+      url = {
+        searchengines = lib.mkOption {
+          type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
+          default = null;
+          apply = mkRaw;
+          example = lib.literalExpression ''
+            {
+              w = "https://en.wikipedia.org/wiki/Special:Search?search={}&go=Go&ns0=1";
+              aw = "https://wiki.archlinux.org/?search={}";
+              nw = "https://wiki.nixos.org/index.php?search={}";
+              g = "https://www.google.com/search?hl=en&q={}";
+            }
+          '';
+        };
+      };
+      statusbar = {
+        padding = lib.mkOption {
+          type = lib.types.nullOr (lib.types.attrsOf lib.types.int);
+          default = null;
+          apply = mkRaw;
+        };
+      };
+    };
+  };
+in {
+  options.programs.qutebrowser = {
+    enable = lib.mkEnableOption "qutebrowser";
+
+    package = lib.mkPackageOption pkgs "qutebrowser" {};
+
+    loadAutoconfig = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = ''
+        Load settings configured via the GUI.
+      '';
+    };
+
+    settings = lib.mkOption {
+      type = settingsType;
+
+      default = {};
+      description = ''
+        Options to add to qutebrowser {file}`config.py` file.
+        See <https://qutebrowser.org/doc/help/settings.html>
+        for options.
+      '';
+      example = lib.literalExpression ''
+        {
+          colors = {
+            hints = {
+              bg = "#000000";
+              fg = "#ffffff";
+            };
+            tabs.bar.bg = "#000000";
+          };
+          tabs.tabs_are_windows = true;
+        }
+      '';
+    };
+
+    quickmarks = lib.mkOption {
+      type = lib.types.attrsOf lib.types.str;
+      default = {};
+      description = ''
+        Quickmarks to add to qutebrowser's {file}`quickmarks` file.
+        Note that when Home Manager manages your quickmarks, you cannot edit them at runtime.
+      '';
+      example = lib.literalExpression ''
+        {
+          nixpkgs = "https://github.com/NixOS/nixpkgs";
+          home-manager = "https://github.com/nix-community/home-manager";
+        }
+      '';
+    };
+
+    greasemonkey = lib.mkOption {
+      type = lib.types.listOf lib.types.package;
+      default = [];
+      example = lib.literalExpression ''
+        [
+          (pkgs.fetchurl {
+            url = "https://raw.githubusercontent.com/afreakk/greasemonkeyscripts/1d1be041a65c251692ee082eda64d2637edf6444/youtube_sponsorblock.js";
+            sha256 = "sha256-e3QgDPa3AOpPyzwvVjPQyEsSUC9goisjBUDMxLwg8ZE=";
+          })
+          (pkgs.writeText "some-script.js" '''
+            // ==UserScript==
+            // @name  Some Greasemonkey script
+            // ==/UserScript==
+          ''')
+        ]
+      '';
+      description = ''
+        Greasemonkey userscripts to add to qutebrowser's {file}`greasemonkey`
+        directory.
+      '';
+    };
+
+    perUrlSettings = lib.mkOption {
+      type = lib.types.attrsOf settingsType;
+      default = {};
+      description = ''
+        Options to set, as in {option}`settings` but per url pattern.
+
+        See <https://qutebrowser.org/doc/help/settings.html> for options,
+        but beware, that not every option supports being set per-url.
+      '';
+      example = lib.literalExpression ''
+        {
+          "zoom.us" = {
+            content = {
+              autoplay = true;
+              media.audio_capture = true;
+              media.video_capture = true;
+            };
+          };
+          "github.com".colors.webpage.darkmode.enabled = false;
+        };
+      '';
+    };
+
+    extraConfig = lib.mkOption {
+      type = lib.types.attrsOf (lib.types.either lib.types.str lib.types.pathInStore);
+      default = {};
+      description = ''
+        Extra config snippets. The attribute name is their name, and the value their
+        value.
+      '';
+      example = lib.literalExpression ''
+        {
+          "redirects" = ' '
+            from PyQt5.QtCore import QUrl
+            from qutebrowser.api import interceptor
+
+            def intercept(info: interceptor.Request):
+                if info.request_url.host() == 'www.youtube.com':
+                    new_url = QUrl(info.request_url)
+                    new_url.setHost('www.invidio.us')
+                    try:
+                        info.redirect(new_url)
+                    except interceptors.RedirectFailedException:
+                        pass
+
+            interceptor.register(intercept)
+          ' '
+        }
+      '';
+    };
+  };
+
+  config = let
+    qutebrowserConfig = lib.concatStringsSep "\n" (
+      [
+        (
+          if cfg.loadAutoconfig
+          then "config.load_autoconfig()"
+          else "config.load_autoconfig(False)"
+        )
+      ]
+      ++ builtins.map (c: configSet c null) (flattenSettings cfg.settings)
+      ++ lib.lists.flatten (lib.mapAttrsToList urlConfigSet cfg.perUrlSettings)
+      ++ lib.mapAttrsToList extraConfigSet cfg.extraConfig
+    );
+
+    quickmarksFile = lib.optionals (cfg.quickmarks != {}) lib.concatStringsSep "\n" (
+      lib.mapAttrsToList formatQuickmarks cfg.quickmarks
+    );
+
+    greasemonkeyDir =
+      lib.optionals (
+        cfg.greasemonkey != []
+      )
+      pkgs.linkFarmFromDrvs "greasemonkey-userscripts"
+      cfg.greasemonkey;
+  in
+    lib.mkIf cfg.enable {
+      home = {
+        packages = [cfg.package];
+
+        file = {
+          ".qutebrowser/config.py" = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin {
+            text = qutebrowserConfig;
+          };
+
+          ".qutebrowser/quickmarks" =
+            lib.mkIf (cfg.quickmarks != {} && pkgs.stdenv.hostPlatform.isDarwin)
+            {
+              text = quickmarksFile;
+            };
+
+          ".qutebrowser/greasemonkey" =
+            lib.mkIf (cfg.greasemonkey != [] && pkgs.stdenv.hostPlatform.isDarwin)
+            {
+              source = greasemonkeyDir;
+            };
+        };
+      };
+
+      xdg = {
+        configFile = {
+          "qutebrowser/config.py" = lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
+            text = qutebrowserConfig;
+            onChange = ''
+              hash="$(echo -n "$USER" | md5sum | cut -d' ' -f1)"
+              socket="''${XDG_RUNTIME_DIR:-/run/user/$UID}/qutebrowser/ipc-$hash"
+              if [[ -S $socket ]]; then
+                command=${
+                lib.escapeShellArg (
+                  builtins.toJSON {
+                    args = [":config-source"];
+                    target_arg = null;
+                    protocol_version = 1;
+                  }
+                )
+              }
+                echo "$command" | ${pkgs.socat}/bin/socat -lf /dev/null - UNIX-CONNECT:"$socket"
+              fi
+              unset hash socket command
+            '';
+          };
+
+          "qutebrowser/quickmarks" =
+            lib.mkIf (cfg.quickmarks != {} && pkgs.stdenv.hostPlatform.isLinux)
+            {
+              text = quickmarksFile;
+            };
+
+          "qutebrowser/greasemonkey" =
+            lib.mkIf (cfg.greasemonkey != [] && pkgs.stdenv.hostPlatform.isLinux)
+            {
+              source = greasemonkeyDir;
+            };
+        };
+      };
+    };
+}
diff --git a/modules/by-name/qu/qutebrowser/module.nix b/modules/by-name/qu/qutebrowser/module.nix
new file mode 100644
index 00000000..dab06237
--- /dev/null
+++ b/modules/by-name/qu/qutebrowser/module.nix
@@ -0,0 +1,106 @@
+{
+  config,
+  lib,
+  pkgs,
+  self,
+  ...
+}: let
+  cfg = config.soispha.programs.qutebrowser;
+
+  qutebrowsersWithProfiles = let
+    xdg_data_home = config.home-manager.users.soispha.xdg.dataHome;
+    xdg_config_home = config.home-manager.users.soispha.xdg.configHome;
+
+    mkQutebrowser = name: let
+      statusbar_widgets = [
+        "keypress"
+        "text:${name}"
+        "search_match"
+        "url"
+        "scroll"
+        "history"
+        "tabs"
+        "progress"
+      ];
+
+      statusbar_widgets_str =
+        # NOTE(@bpeetz): We need either two layers of escaping or the binary wrapper, as we first inline this
+        # into the runCommand below, and then into the actual qutebrowser wrapper script. <2025-06-16>
+        lib.strings.escapeShellArg (builtins.toJSON statusbar_widgets);
+    in
+      pkgs.runCommandLocal "qutebrowser-${name}" {
+        nativeBuildInputs = [
+          pkgs.makeBinaryWrapper
+        ];
+      }
+      ''
+        makeWrapper ${lib.getExe pkgs.qutebrowser-patched} "$out/bin/qutebrowser-${name}" \
+          --add-flags --no-err-windows \
+          --add-flags --basedir \
+          --add-flags "${xdg_data_home}/qutebrowser/${name}" \
+          --add-flags --config \
+          --add-flags "${xdg_config_home}/qutebrowser/config.py" \
+          --add-flags --set \
+          --add-flags statusbar.widgets \
+          --add-flags ${statusbar_widgets_str}
+      '';
+  in
+    builtins.filter (val: val != null) (lib.mapAttrsToList (name: value:
+      if value.enable
+      then mkQutebrowser name
+      else null)
+    cfg.profiles);
+in {
+  options.soispha.programs.qutebrowser = {
+    enable = lib.mkEnableOption "qutebrowser";
+
+    key = lib.mkOption {
+      type = lib.types.str;
+      description = ''
+        The gpg key, used when decrypting the keepassxc connection key.
+      '';
+    };
+
+    profiles = lib.mkOption {
+      type = lib.types.attrsOf (lib.types.submodule {
+        options = {
+          enable =
+            (lib.mkEnableOption "this profile")
+            // {
+              default = true;
+            };
+        };
+      });
+
+      description = "A name enable map of profies to create besides the default `default` profile.";
+      default = {};
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      disabledModules = [
+        "${self.inputs.home-manager}/modules/programs/qutebrowser.nix"
+      ];
+      imports = [
+        ./module.hm.nix
+      ];
+
+      home.packages = qutebrowsersWithProfiles;
+
+      programs.qutebrowser = {
+        enable = true;
+        package = pkgs.hello; # TODO: Set to null, once supported <2025-06-06>
+
+        settings = import ./settings {
+          inherit lib pkgs;
+          cfg = config.soispha.programs.qutebrowser;
+        };
+
+        extraConfig = {
+          "redirects" = ./include/redirects.py;
+        };
+      };
+    };
+  };
+}
diff --git a/modules/by-name/qu/qutebrowser/settings/default.nix b/modules/by-name/qu/qutebrowser/settings/default.nix
new file mode 100644
index 00000000..282c5816
--- /dev/null
+++ b/modules/by-name/qu/qutebrowser/settings/default.nix
@@ -0,0 +1,537 @@
+{
+  lib,
+  pkgs,
+  cfg,
+}: let
+  millisecond = 1;
+  second = 1000 * millisecond;
+
+  wordlist =
+    pkgs.runCommandLocal "wordlist" {
+      nativeBuildInputs = [pkgs.python3];
+    }
+    ''
+      python ${
+        pkgs.writeText "normalize-words"
+        # python
+        ''
+          import string
+          import os
+
+          # Perform qutebrowser's normalizations, to reduce our dependency closure.
+          # See <//qutebrowser/qutebrowser/browser/hints.py> for them.
+          with open("${pkgs.scowl}/share/dict/words.txt", encoding = "latin1") as wordfile:
+            alphabet = set(string.ascii_lowercase)
+            hints = set()
+            lines = (line.rstrip().lower() for line in wordfile)
+            for word in lines:
+                if len(word) > 4:
+                    # we don't need words longer than 4
+                    continue
+                if set(word) - alphabet:
+                    # contains none-alphabetic chars
+                    continue
+                for i in range(len(word)):
+                    # remove all prefixes of this word
+                    hints.discard(word[:i + 1])
+                hints.add(word)
+
+          with open(os.environ["out"], "w") as out:
+            for word in hints:
+              out.write(word)
+              out.write("\n")
+        ''
+      }
+    '';
+in {
+  aliases = {
+    q = "close";
+    qa = "quit";
+    w = "session-save";
+    wq = "quit --save";
+    wqa = "quit --save";
+    read = "spawn --userscript readability";
+  };
+
+  auto_save = {
+    interval = 10 * second;
+    session = true; # Safe/restore the session
+  };
+
+  backend = "webengine";
+
+  bindings = {
+    default = {}; # Disable the default key bindings
+
+    commands = import ./keybindings.nix {inherit cfg lib;};
+
+    key_mappings = {
+      "<Ctrl-6>" = "<Ctrl-^>";
+      "<Ctrl-Enter>" = "<Ctrl-Return>";
+      "<Ctrl-I>" = "<Tab>";
+      "<Ctrl-J>" = "<Return>";
+      "<Ctrl-M>" = "<Return>";
+      "<Ctrl-[>" = "<Escape>";
+      "<Enter>" = "<Return>";
+      "<Shift-Enter>" = "<Return>";
+      "<Shift-Return>" = "<Return>";
+    };
+  };
+
+  changelog_after_upgrade = "minor";
+
+  fonts = {};
+  colors = {
+    # TODO(@bpeetz): Use a nord color scheme (or stylix). <2025-05-31>
+
+    # Make things readable.
+    messages.error.fg = "black";
+    completion.match.fg = "black";
+
+    webpage = {
+      darkmode = {
+        enabled = true;
+        algorithm = "lightness-cielab";
+        policy = {
+          images = "smart";
+          page = "smart";
+        };
+        threshold = {
+          background = 0; # 0 -> always
+          foreground = 256; # 256 -> always
+        };
+      };
+      preferred_color_scheme = "auto";
+    };
+  };
+
+  completion = {
+    cmd_history_max_items = -1; # No limit.
+    delay = 0; # delay before updating completions in milliseconds.
+    favorite_paths = [];
+    height = "50%";
+    min_chars = 1;
+    open_categories = ["searchengines" "quickmarks" "bookmarks" "history" "filesystem"];
+
+    quick = true; # Select, when only one left.
+
+    scrollbar = {
+      padding = 0;
+      width = 0;
+    };
+
+    show = "auto"; # Only show, when selected
+
+    shrink = true;
+
+    use_best_match = false;
+    web_history = {
+      exclude = [];
+      max_items = -1; # unlimited.
+    };
+  };
+
+  confirm_quit = [
+    "downloads"
+  ];
+
+  content = {
+    autoplay = false;
+
+    blocking = {
+      enabled = true;
+
+      # Sources for brave's adblocker
+      adblock = {
+        lists = [
+          "https://easylist.to/easylist/easylist.txt"
+          "https://easylist.to/easylist/easyprivacy.txt"
+        ];
+      };
+
+      # Sources for the (simpler) /etc/hosts based one.
+      hosts = {
+        block_subdomains = true;
+        lists = [];
+      };
+
+      method = "adblock"; # Only brave's
+      whitelist = [];
+    };
+
+    # Allow websites to read canvas elements.
+    canvas_reading = true;
+
+    cookies = {
+      store = true;
+      accept = "no-3rdparty";
+    };
+
+    default_encoding = "utf-8";
+
+    dns_prefetch = true;
+
+    fullscreen = {
+      # Fullscreen is limited to the browser window.
+      window = true;
+      overlay_timeout = 3 * second;
+    };
+
+    headers = {
+      accept_language = "en-CA,sv,en;q=0.9";
+      custom = {};
+      do_not_track = true;
+      referer = "same-domain";
+      user_agent = "Mozilla/5.0 ({os_info}) AppleWebKit/{webkit_version} (KHTML, like Gecko) {upstream_browser_key}/{upstream_browser_version_short} Safari/{webkit_version}";
+    };
+
+    hyperlink_auditing = false;
+
+    # Auto-load images.
+    images = true;
+
+    javascript = {
+      enabled = true;
+
+      can_open_tabs_automatically = false;
+      alert = true;
+      clipboard = "ask";
+      legacy_touch_events = "never";
+
+      log = {
+        error = "debug";
+        warning = "debug";
+        info = "debug";
+        unknown = "debug";
+      };
+
+      modal_dialog = false;
+      prompt = true;
+    };
+
+    local_content_can_access_file_urls = true;
+    local_content_can_access_remote_urls = false;
+
+    local_storage = true;
+
+    desktop_capture = "ask";
+    geolocation = "ask";
+    persistent_storage = "ask";
+    mouse_lock = "ask";
+    register_protocol_handler = "ask";
+    media = {
+      audio_capture = "ask";
+      audio_video_capture = "ask";
+      video_capture = "ask";
+    };
+
+    mute = false;
+
+    notifications = {
+      # TODO(@bpeetz): I might change that. <2025-05-31>
+      enabled = true;
+
+      presenter = "libnotify";
+      show_origin = true;
+    };
+
+    pdfjs = false;
+
+    # TODO(@bpeetz): What are “plugins in Web pages”? <2025-05-31>
+    plugins = false;
+
+    prefers_reduced_motion = false;
+    print_element_backgrounds = true;
+    private_browsing = false;
+    proxy = "system";
+
+    site_specific_quirks = {
+      enabled = true;
+      skip = [];
+    };
+
+    tls = {
+      certificate_errors = "ask";
+    };
+
+    unknown_url_scheme_policy = "allow-from-user-interaction";
+    user_stylesheets = [];
+
+    webgl = true;
+
+    webrtc_ip_handling_policy = "all-interfaces";
+    xss_auditing = false;
+  };
+
+  downloads = {
+    location = {
+      # Use OS default.
+      directory = null;
+      prompt = true;
+      remember = true;
+      suggestion = "path";
+    };
+
+    # TODO(@bpeetz): I might want to set that. <2025-05-31>
+    open_dispatcher = null;
+
+    position = "top";
+    prevent_mixed_content = true;
+
+    # Never remove downloads without my intervention.
+    remove_finished = -1;
+  };
+
+  editor = {
+    command = [
+      "${lib.getExe pkgs.alacritty}"
+      "--title"
+      "floating please"
+      "--command"
+      "nvim"
+      "-c"
+      "normal {line}G{column0}|"
+      "{file}"
+    ];
+    encoding = "utf-8";
+    remove_file = true;
+  };
+
+  fileselect = {
+    handler = "default";
+  };
+
+  hints = {
+    auto_follow = "unique-match";
+    auto_follow_timeout = 0;
+
+    chars = "asdfghjkl";
+    dictionary = "${wordlist}";
+
+    hide_unmatched_rapid_hints = true;
+    leave_on_load = false;
+
+    min_chars = 1;
+    next_regexes = ["\\bnext\\b" "\\bmore\\b" "\\bnewer\\b" "\\b[>→≫]\\b" "\\b(>>|»)\\b" "\\bcontinue\\b"];
+    prev_regexes = ["\\bprev(ious)?\\b" "\\bback\\b" "\\bolder\\b" "\\b[<←≪]\\b" "\\b(<<|«)\\b"];
+
+    scatter = true;
+    uppercase = false;
+    mode = "word";
+  };
+
+  input = {
+    escape_quits_reporter = false;
+    forward_unbound_keys = "auto";
+
+    insert_mode = {
+      auto_enter = true;
+      auto_leave = true;
+      auto_load = false;
+      leave_on_load = true;
+      plugins = false;
+    };
+
+    links_included_in_focus_chain = true;
+    match_counts = true;
+
+    media_keys = true;
+
+    mode_override = null;
+
+    mouse = {
+      back_forward_buttons = true;
+      rocker_gestures = false;
+    };
+
+    partial_timeout = 0;
+    spatial_navigation = false;
+  };
+
+  keyhint = {
+    blacklist = [];
+    delay = 250 * millisecond;
+  };
+
+  logging = {
+    level = {
+      console = "info";
+      ram = "debug";
+    };
+  };
+
+  messages = {
+    timeout = 3 * second;
+  };
+
+  new_instance_open_target = "tab";
+  new_instance_open_target_window = "last-focused";
+
+  prompt = {
+    filebrowser = true;
+  };
+
+  qt = {
+    args = [];
+
+    chromium = {
+      experimental_web_platform_features = "auto";
+      low_end_device_mode = "auto";
+      process_model = "process-per-site-instance";
+      sandboxing = "enable-all";
+    };
+
+    environ = {};
+    force_platform = null;
+    force_platformtheme = null;
+    force_software_rendering = "none";
+
+    highdpi = true;
+
+    workarounds = {
+      disable_accelerated_2d_canvas = "auto";
+      disable_hangouts_extension = false;
+      locale = false;
+      remove_service_workers = false;
+    };
+  };
+
+  scrolling = {
+    bar = "never";
+    smooth = false;
+  };
+
+  search = {
+    ignore_case = "smart";
+    incremental = true;
+    wrap = true;
+    wrap_messages = true;
+  };
+
+  session = {
+    default_name = null;
+    lazy_restore = true;
+  };
+
+  spellcheck = {
+    # TODO(@bpeetz): Installing them (reproducibly) is simply not worth the hassle, as
+    # qutebrowser already provides quick access to an editor. <2025-06-04>
+    # languages = ["en-GB" "sv-SE" "de-DE"];
+  };
+
+  statusbar = {
+    padding = {
+      bottom = 5;
+      left = 5;
+      right = 5;
+      top = 5;
+    };
+
+    position = "top";
+    show = "always";
+    widgets = [
+      /*
+      Already set in the wrappers
+      */
+    ];
+  };
+
+  tabs = {
+    background = true;
+    close_mouse_button = "middle";
+    close_mouse_button_on_bar = "new-tab";
+
+    favicons = {
+      scale = 1;
+      show = "always";
+    };
+
+    focus_stack_size = 10;
+
+    last_close = "default-page";
+
+    max_width = -1;
+    min_width = -1;
+
+    mode_on_change = "normal";
+
+    mousewheel_switching = true;
+
+    new_position = {
+      related = "next";
+      unrelated = "next";
+      stacking = true;
+    };
+
+    pinned = {
+      frozen = true;
+      shrink = true;
+    };
+
+    position = "top";
+
+    select_on_remove = "last-used";
+
+    show = "multiple";
+    show_switching_delay = 2 * second;
+
+    tabs_are_windows = false;
+    title = {
+      alignment = "center";
+      elide = "middle";
+      format = "{audio}{index}: {current_title}";
+      format_pinned = "{index}";
+    };
+
+    tooltips = true;
+    undo_stack_size = 100;
+    width = "15%";
+    wrap = true;
+  };
+
+  url = {
+    auto_search = "naive";
+    default_page = "qute://start";
+    incdec_segments = ["path" "query"];
+
+    open_base_url = false; # Of search engine.
+    searchengines = rec {
+      DEFAULT = duckduckgo;
+
+      duckduckgo = "https://duckduckgo.com/search?q={}";
+      "@du" = duckduckgo;
+
+      # NIX
+      "@np" = "https://search.nixos.org/packages?type=packages&query={}"; # Nix packages
+
+      "@ng" = "https://noogle.dev/q?term={}"; # Nix functions
+
+      "@no" = "https://search.nixos.org/options?type=options&query={}"; # NixOS options
+      "@nh" = "https://home-manager-options.extranix.com/?query={}&release=master"; # Home-Manager options
+
+      "@ni" = "https://github.com/NixOS/nixpkgs/issues?q=is%3Aissue+is%3Aopen+{}"; # Nixpkgs issues
+      "@nr" = "https://github.com/NixOS/nixpkgs/pulls?q=is%3Apr+is%3Aopen+{}"; # Nixpkgs pull requests
+
+      "@nt" = "https://nixpk.gs/pr-tracker.html?pr={}"; # Nixpkgs pull requests tracker
+      "@nw" = "https://wiki.nixos.org/w/index.php?search={}"; # NixOS Wiki
+
+      # RUST
+      "@rs" = "https://doc.rust-lang.org/std/?search={}"; # Rust std
+      "@rt" = "https://docs.rs/tokio/latest/tokio/index.html?search={}"; # Rust tokio
+
+      # OTHER
+      "@gs" = "https://scholar.google.com/scholar?hl=en&q={}"; # Google Scholar
+      "@wp" = "https://en.wikipedia.org/wiki/{}"; # Wikipedia
+      "@aw" = "https://wiki.archlinux.org/index.php?search={}"; # Arch Wiki
+    };
+
+    start_pages = ["qute://start"];
+    yank_ignored_parameters = ["ref" "utm_source" "utm_medium" "utm_campaign" "utm_term" "utm_content" "utm_name"];
+  };
+
+  window = {
+    hide_decoration = true;
+    title_format = "{perc}{current_title}{title_sep}qutebrowser";
+    transparent = false;
+  };
+}
diff --git a/modules/by-name/qu/qutebrowser/settings/keybindings.nix b/modules/by-name/qu/qutebrowser/settings/keybindings.nix
new file mode 100644
index 00000000..fde78457
--- /dev/null
+++ b/modules/by-name/qu/qutebrowser/settings/keybindings.nix
@@ -0,0 +1,289 @@
+{
+  cfg,
+  lib,
+}: {
+  caret = {
+    "<Escape>" = "mode-leave";
+
+    H = "scroll left";
+    T = "scroll down";
+    N = "scroll up";
+    S = "scroll right";
+    h = "move-to-prev-char";
+    t = "move-to-next-line";
+    n = "move-to-prev-line";
+    s = "move-to-next-char";
+
+    "$" = "move-to-end-of-line";
+    "0" = "move-to-start-of-line";
+    G = "move-to-end-of-document";
+    gg = "move-to-start-of-document";
+
+    b = "move-to-prev-word";
+    c = "mode-enter normal";
+    e = "move-to-end-of-word";
+    w = "move-to-next-word";
+
+    "{" = "move-to-end-of-prev-block";
+    "}" = "move-to-end-of-next-block";
+    "[" = "move-to-start-of-prev-block";
+    "]" = "move-to-start-of-next-block";
+
+    y = "yank selection";
+    Y = "yank selection -s";
+    V = "selection-toggle --line";
+    v = "selection-toggle";
+    "<Ctrl-Space>" = "selection-drop";
+    "<Return>" = "yank selection";
+    "<Space>" = "selection-toggle";
+    o = "selection-reverse";
+  };
+
+  command = {
+    "<Alt-B>" = "rl-backward-word";
+    "<Alt-Backspace>" = "rl-backward-kill-word";
+    "<Alt-D>" = "rl-kill-word";
+    "<Alt-F>" = "rl-forward-word";
+    "<Ctrl-?>" = "rl-delete-char";
+    "<Ctrl-A>" = "rl-beginning-of-line";
+    "<Ctrl-B>" = "rl-backward-char";
+    "<Ctrl-C>" = "completion-item-yank";
+    "<Ctrl-D>" = "completion-item-del";
+    "<Ctrl-E>" = "rl-end-of-line";
+    "<Ctrl-F>" = "rl-forward-char";
+    "<Ctrl-H>" = "rl-backward-delete-char";
+    "<Ctrl-K>" = "rl-kill-line";
+    "<Ctrl-N>" = "command-history-next";
+    "<Ctrl-P>" = "command-history-prev";
+    "<Ctrl-Return>" = "command-accept --rapid";
+    "<Ctrl-Shift-C>" = "completion-item-yank --sel";
+    "<Ctrl-Shift-Tab>" = "completion-item-focus prev-category";
+    "<Ctrl-Shift-W>" = "rl-filename-rubout";
+    "<Ctrl-Tab>" = "completion-item-focus next-category";
+    "<Ctrl-U>" = "rl-unix-line-discard";
+    "<Ctrl-W>" = "rl-rubout \" \"";
+    "<Ctrl-Y>" = "rl-yank";
+    "<Down>" = "completion-item-focus --history next";
+    "<Escape>" = "mode-leave";
+    "<PgDown>" = "completion-item-focus next-page";
+    "<PgUp>" = "completion-item-focus prev-page";
+    "<Return>" = "command-accept";
+    "<Shift-Delete>" = "completion-item-del";
+    "<Shift-Tab>" = "completion-item-focus prev";
+    "<Tab>" = "completion-item-focus next";
+    "<Up>" = "completion-item-focus --history prev";
+  };
+
+  hint = {
+    "<Ctrl-B>" = "hint all tab-bg";
+    "<Ctrl-F>" = "hint links";
+    "<Ctrl-R>" = "hint --rapid links tab-bg";
+    "<Escape>" = "mode-leave";
+    "<Return>" = "hint-follow";
+  };
+
+  insert = {
+    "<Ctrl-E>" = "edit-text";
+    "<Escape>" = "mode-leave";
+    "<Shift-Escape>" = "fake-key <Escape>";
+    "<Shift-Ins>" = "insert-text -- {primary}";
+    "<Ctrl-k>" = "spawn --userscript qute-keepassxc --key ${lib.escapeShellArg cfg.key}";
+  };
+
+  normal = {
+    #  a
+    #  b
+    #  c
+    #  d -> download management
+    #  e -> [e]merge tab
+    #  f -> `hint all`
+    #  g -> tabs [g]oing
+    #  h -> `back`
+    #  i -> `mode-enter insert`
+    #  j -> inputs
+    #  k
+    #  l -> `search-next`
+    #  m -> in page movement
+    #  n -> `scroll up`
+    #  o
+    #  p
+    #  q -> `macro-record`
+    #  r
+    #  s -> `forward`
+    #  t -> `scroll down`
+    #  u -> `undo`
+    #  v -> `mode-enter caret`
+    #  w -> theme switching
+    #  x -> hinting
+    #  y -> yanking
+    #  z
+
+    # Theme switching
+    wd = "set --temp colors.webpage.darkmode.enabled true";
+    wl = "set --temp colors.webpage.darkmode.enabled false";
+
+    # Tab [g]oing
+    "g$" = "tab-focus -1";
+    g0 = "tab-focus 1";
+    gh = "home";
+    gH = "history";
+    gs = "cmd-set-text --space :open";
+    gP = "open -- {primary}";
+    gp = "open -- {clipboard}";
+    go = "cmd-set-text :open {url:pretty}";
+    gt = "cmd-set-text --space :tab-select";
+    # TODO(@bpeetz): Make this to a lf tab listing. <2025-05-31>
+    "\\f" = "cmd-set-text --space --relative :tab-focus";
+
+    eP = "open --tab -- {primary}";
+    ep = "open --tab -- {clipboard}";
+    ea = "open --tab";
+    es = "cmd-set-text --space :open --tab";
+    eo = "cmd-set-text :open --tab --related {url:pretty}";
+    eh = "back --tab";
+    en = "forward --tab";
+    ec = "tab-clone";
+    em = "tab-move";
+    ed = "tab-close";
+    eR = "reload --force";
+    er = "reload";
+
+    # Download management
+    dm = "download";
+    dc = "download-cancel";
+    dp = "download-clear";
+    do = "download-open";
+    dr = "download-retry";
+
+    # In page hierarchy [m]ovement
+    mi = "navigate increment";
+    md = "navigate increment";
+    mp = "navigate prev";
+    mn = "navigate next";
+    mu = "navigate up";
+    mh = "navigate strip";
+
+    # Page movement
+    H = "scroll left";
+    t = "scroll down";
+    n = "scroll up";
+    S = "scroll right";
+    h = "back";
+    T = "tab-prev";
+    N = "tab-next";
+    s = "forward";
+    G = "scroll-to-perc";
+    gg = "scroll-to-perc 0";
+
+    l = "search-next";
+    L = "search-prev";
+
+    "+" = "zoom-in";
+    "-" = "zoom-out";
+    "=" = "zoom";
+
+    "." = "cmd-repeat-last";
+    "/" = "cmd-set-text /";
+    "?" = "cmd-set-text ?";
+    ":" = "cmd-set-text :";
+
+    # Hinting
+    xI = "hint images tab";
+    xi = "hint images";
+    xO = "hint links fill :open --tab --related {hint-url}";
+    xo = "hint links fill :open {hint-url}";
+    xY = "hint links yank-primary";
+    xy = "hint links yank";
+    xb = "hint all tab-bg";
+    xf = "hint all tab-fg";
+    xd = "hint links download";
+    xh = "hint all hover";
+    xr = "hint --rapid links tab-bg";
+    xt = "hint inputs";
+    f = "hint all";
+
+    # Inputs
+    jf = "hint inputs --first";
+    jk = "spawn --userscript qute-keepassxc --key ${lib.escapeShellArg cfg.key}";
+
+    # Yanking
+    yD = "yank domain --sel";
+    yM = "yank inline [{title}]({url:yank}) --sel";
+    yP = "yank pretty-url --sel";
+    yT = "yank title --sel";
+    yY = "yank --sel";
+    yd = "yank domain";
+    ym = "yank inline [{title}]({url:yank})";
+    yp = "yank pretty-url";
+    yt = "yank title";
+    yy = "yank";
+
+    "<Escape>" = "clear-keychain ;; search ;; fullscreen --leave ;; clear-messages";
+    "<Shift-Space>" = "scroll-page 0 -1";
+    "<Space>" = "scroll-page 0 1";
+    "<Ctrl-Return>" = "selection-follow --tab";
+    "<Return>" = "selection-follow";
+    "<back>" = "back";
+    "<forward>" = "forward";
+
+    i = "mode-enter insert";
+    "'" = "mode-enter jump_mark";
+    "`" = "mode-enter set_mark";
+    v = "mode-enter caret";
+    V = "mode-enter caret ;; selection-toggle --line";
+    "<Ctrl-V>" = "mode-enter passthrough";
+
+    q = "macro-record";
+    "@" = "macro-run";
+    u = "undo";
+    U = "undo --window";
+  };
+
+  passthrough = {
+    "<Shift-Escape>" = "mode-leave";
+  };
+
+  prompt = {
+    "<Alt-B>" = "rl-backward-word";
+    "<Alt-Backspace>" = "rl-backward-kill-word";
+    "<Alt-D>" = "rl-kill-word";
+    "<Alt-E>" = "prompt-fileselect-external";
+    "<Alt-F>" = "rl-forward-word";
+    "<Alt-Shift-Y>" = "prompt-yank --sel";
+    "<Alt-Y>" = "prompt-yank";
+    "<Ctrl-?>" = "rl-delete-char";
+    "<Ctrl-A>" = "rl-beginning-of-line";
+    "<Ctrl-B>" = "rl-backward-char";
+    "<Ctrl-E>" = "rl-end-of-line";
+    "<Ctrl-F>" = "rl-forward-char";
+    "<Ctrl-H>" = "rl-backward-delete-char";
+    "<Ctrl-K>" = "rl-kill-line";
+    "<Ctrl-P>" = "prompt-open-download --pdfjs";
+    "<Ctrl-Shift-W>" = "rl-filename-rubout";
+    "<Ctrl-U>" = "rl-unix-line-discard";
+    "<Ctrl-W>" = "rl-rubout \" \"";
+    "<Ctrl-X>" = "prompt-open-download";
+    "<Ctrl-Y>" = "rl-yank";
+    "<Down>" = "prompt-item-focus next";
+    "<Escape>" = "mode-leave";
+    "<Return>" = "prompt-accept";
+    "<Shift-Tab>" = "prompt-item-focus prev";
+    "<Tab>" = "prompt-item-focus next";
+    "<Up>" = "prompt-item-focus prev";
+  };
+
+  register = {
+    "<Escape>" = "mode-leave";
+  };
+
+  yesno = {
+    "<Alt-Shift-Y>" = "prompt-yank --sel";
+    "<Alt-Y>" = "prompt-yank";
+    "<Escape>" = "mode-leave";
+    "<Return>" = "prompt-accept";
+    N = "prompt-accept --save no";
+    Y = "prompt-accept --save yes";
+    n = "prompt-accept no";
+    y = "prompt-accept yes";
+  };
+}
diff --git a/modules/by-name/re/resolvconf/module.nix b/modules/by-name/re/resolvconf/module.nix
new file mode 100644
index 00000000..e1817e2b
--- /dev/null
+++ b/modules/by-name/re/resolvconf/module.nix
@@ -0,0 +1,15 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.resolvconf;
+in {
+  options.soispha.resolvconf = {
+    enable = lib.mkEnableOption "resolvconf" // {default = config.networking.resolvconf.enable;};
+  };
+
+  config = lib.mkIf cfg.enable {
+    users.groups.resolvconf.gid = config.soispha.constants.ids.gids.resolvconf;
+  };
+}
diff --git a/modules/by-name/ri/river/init_base.sh b/modules/by-name/ri/river/init_base.sh
index b92f59e0..edd7827f 100755
--- a/modules/by-name/ri/river/init_base.sh
+++ b/modules/by-name/ri/river/init_base.sh
@@ -10,8 +10,9 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-# NOTE: Keep this in sync with the file from `river-start` <2025-02-03>
-RIVER_LOG_FILE="$HOME/.local/share/river/log"
+RIVER_LOG_FILE="$HOME/.cache/river/init-log"
+
+echo >"$RIVER_LOG_FILE"
 
 err_fail() {
     if ! "$@"; then
diff --git a/modules/by-name/ri/river/keymap.nix b/modules/by-name/ri/river/keymap.nix
new file mode 100644
index 00000000..9bcbf387
--- /dev/null
+++ b/modules/by-name/ri/river/keymap.nix
@@ -0,0 +1,191 @@
+{
+  lib,
+  pkgs,
+  libraries,
+  config,
+  ...
+}: let
+  index2tag = input: builtins.toString (libraries.base.pow 2 (input - 1));
+
+  mkTagCommand = name: index: [name (index2tag index)];
+  mkSpawn' = pkg: binaryName: args: further: (further
+    // (let
+      maybeSpace =
+        if args == ""
+        then ""
+        else " ";
+      maybeQuote =
+        if args == ""
+        then ""
+        else "\"";
+    in {
+      command = [
+        "spawn"
+        "${lib.getExe pkgs.notify-run} \"${lib.getExe' pkg binaryName}\"${maybeSpace}${maybeQuote}${args}${maybeQuote}"
+      ];
+
+      description = "${binaryName}${maybeSpace}${args}";
+    }));
+
+  mkSpawn = pkg: args: further: (mkSpawn' pkg pkg.meta.mainProgram args further);
+
+  setMode = path: {
+    command = [
+      "enter-mode"
+      (builtins.concatStringsSep "" path)
+    ];
+  };
+
+  cfg = config.soispha.programs.river;
+in {
+  soispha.programs.river.init.mappings.keymap = lib.mkIf cfg.enable (lib.fixedPoints.fix
+    (self: {
+      "<LEFT_SUPER>" = {
+        # Spawn standard programs
+        "r" = {
+          "a" = mkSpawn pkgs.alacritty "" {};
+          "b" = mkSpawn pkgs.tskm "open select" {once = true;};
+          "k" = mkSpawn pkgs.keepassxc "" {once = true;};
+          "s" = mkSpawn pkgs.signal-desktop "" {once = true;};
+          "p" = mkSpawn pkgs.screenshot_persistent "" {once = true;};
+          "i" = mkSpawn pkgs.anki "" {once = true;};
+        };
+
+        # Client changes
+        "c" = {
+          "F" = setMode ["<LEFT_META>" "f"];
+
+          "f" = ["toggle-fullscreen"];
+          "c" = ["close"];
+          " " = ["toggle-float"];
+          "<ENTER>" = ["zoom"];
+        };
+
+        # This is a fill in for <Super-L>, as that is otherwise nearly impossible to input.
+        "l" = self."<LEFT_SUPER>".x.l;
+
+        # River compositor control.
+        "x" = {
+          "q" = ["exit"];
+          "l" = mkSpawn pkgs.lock "" {once = true;};
+          "h" = mkSpawn' pkgs.procps "pkill" "--signal USR1 i3bar-river" {once = true;};
+        };
+
+        # Media control
+        "m" = {
+          "u" = mkSpawn' pkgs.wireplumber "wpctl" "set-volume @DEFAULT_SINK@ 5%+" {};
+          "d" = mkSpawn' pkgs.wireplumber "wpctl" "set-volume @DEFAULT_SINK@ 5%-" {};
+          "m" = mkSpawn' pkgs.wireplumber "wpctl" "set-mute @DEFAULT_SINK@ toggle" {};
+          "n" = mkSpawn pkgs.mpp "next" {};
+          "p" = mkSpawn pkgs.mpp "prev" {};
+          "t" = mkSpawn pkgs.mpp "toggle" {};
+          "g" = mkSpawn' pkgs.mpdpopm "mpdpopm" "rating inc" {once = true;};
+          "b" = mkSpawn' pkgs.mpdpopm "mpdpopm" "rating decr" {once = true;};
+        };
+
+        # Select tags for view.
+        "v" = {
+          "c" = setMode ["<LEFT_META>" "c"];
+          "f" = setMode ["<LEFT_META>" "f"];
+
+          "t" = ["swap" "next"];
+          "n" = ["swap" "previous"];
+          "T" = ["send-to-output" "next"];
+          "N" = ["send-to-output" "previous"];
+
+          "0" = ["set-view-tags" (builtins.toString ((libraries.base.pow 2 32) - 1))];
+          "p" = ["send-to-previous-tags"];
+
+          "1" = mkTagCommand "set-view-tags" 1;
+          "2" = mkTagCommand "set-view-tags" 2;
+          "3" = mkTagCommand "set-view-tags" 3;
+          "4" = mkTagCommand "set-view-tags" 4;
+          "5" = mkTagCommand "set-view-tags" 5;
+          "6" = mkTagCommand "set-view-tags" 6;
+          "7" = mkTagCommand "set-view-tags" 7;
+          "8" = mkTagCommand "set-view-tags" 8;
+          "9" = mkTagCommand "set-view-tags" 9;
+
+          # Add tags to view.
+          "a" = {
+            "1" = mkTagCommand "toggle-view-tags" 1;
+            "2" = mkTagCommand "toggle-view-tags" 2;
+            "3" = mkTagCommand "toggle-view-tags" 3;
+            "4" = mkTagCommand "toggle-view-tags" 4;
+            "5" = mkTagCommand "toggle-view-tags" 5;
+            "6" = mkTagCommand "toggle-view-tags" 6;
+            "7" = mkTagCommand "toggle-view-tags" 7;
+            "8" = mkTagCommand "toggle-view-tags" 8;
+            "9" = mkTagCommand "toggle-view-tags" 9;
+          };
+        };
+
+        # Select tags to focus,
+        # and change focus
+        "f" = {
+          "c" = setMode ["<LEFT_META>" "c"];
+          "v" = setMode ["<LEFT_META>" "v"];
+
+          "t" = ["focus-view" "next"];
+          "n" = ["focus-view" "previous"];
+          "T" = ["focus-output" "next"];
+          "N" = ["focus-output" "previous"];
+
+          "0" = ["set-focused-tags" (builtins.toString ((libraries.base.pow 2 32) - 1))];
+          "p" = ["focus-previous-tags"];
+
+          "1" = mkTagCommand "set-focused-tags" 1;
+          "2" = mkTagCommand "set-focused-tags" 2;
+          "3" = mkTagCommand "set-focused-tags" 3;
+          "4" = mkTagCommand "set-focused-tags" 4;
+          "5" = mkTagCommand "set-focused-tags" 5;
+          "6" = mkTagCommand "set-focused-tags" 6;
+          "7" = mkTagCommand "set-focused-tags" 7;
+          "8" = mkTagCommand "set-focused-tags" 8;
+          "9" = mkTagCommand "set-focused-tags" 9;
+        };
+      };
+
+      # Screen locking
+      "<Super-l>" = self."<LEFT_SUPER>".x.l;
+
+      # Audio
+      "<MEDIA_RAISEVOLUME>" =
+        self."<LEFT_SUPER>".m.u
+        // {
+          allow_locked = true;
+        };
+      "<MEDIA_LOWERVOLUME>" =
+        self."<LEFT_SUPER>".m.d
+        // {
+          allow_locked = true;
+        };
+      "<MEDIA_MUTEVOLUME>" =
+        self."<LEFT_SUPER>".m.m
+        // {
+          allow_locked = true;
+        };
+      "<MEDIA_TRACKNEXT>" =
+        self."<LEFT_SUPER>".m.n
+        // {
+          allow_locked = true;
+        };
+      "<MEDIA_TRACKPREVIOUS>" =
+        self."<LEFT_SUPER>".m.p
+        // {
+          allow_locked = true;
+        };
+      "<MEDIA_PLAY>" =
+        self."<LEFT_SUPER>".m.t
+        // {
+          allow_locked = true;
+        };
+
+      # Mouse
+      "<Alt-<MOUSE_LEFT>>" = ["move-view"];
+      "<Alt-<MOUSE_RIGHT>>" = ["resize-view"];
+
+      # Screenshot
+      "<PRINTSCREEN>" = self."<LEFT_SUPER>".r.p;
+    }));
+}
diff --git a/modules/by-name/ri/river/module.nix b/modules/by-name/ri/river/module.nix
index 63e25f62..893fdc77 100644
--- a/modules/by-name/ri/river/module.nix
+++ b/modules/by-name/ri/river/module.nix
@@ -10,14 +10,14 @@
 {
   config,
   lib,
-  qmk_firmware,
   system,
   pkgs,
+  externalBinaries,
   ...
 }: let
   cfg = config.soispha.programs.river;
   esa = lib.strings.escapeShellArg;
-  riverctl = lib.getExe' pkgs.river "riverctl";
+  riverctl = lib.getExe' cfg.package "riverctl";
 
   mkOutputFlags = output: flags: let
     expandedFlags = builtins.concatStringsSep " " (lib.attrsets.mapAttrsToList (flag: value: "--${esa flag} ${esa value}") flags);
@@ -36,10 +36,22 @@
   longRunningPrograms = builtins.concatStringsSep "\n" (builtins.map mkLrProgram cfg.init.backgroundStart);
 
   keymapFormat = pkgs.formats.json {};
+  keymapGenerate = name: value:
+    pkgs.runCommandLocal "mk-${name}-and-check" {
+      nativeBuildInputs = [pkgs.river-mk-keymap];
+      preferLocalBuild = true;
+
+      env = {
+        JSON_FILE = keymapFormat.generate name value;
+      };
+    } ''
+      river-mk-keymap --keymap "$JSON_FILE" init --dry-run;
+      cp "$JSON_FILE" "$out"
+    '';
 
   keymappings = ''
     err_fail ${riverctl} keyboard-layout ${esa cfg.init.mappings.layout}
-    err_fail ${lib.getExe pkgs.river-mk-keymap} ${keymapFormat.generate "keys.json" cfg.init.mappings.keymap}
+    err_fail ${lib.getExe pkgs.river-mk-keymap} --keymap ${keymapGenerate "keys.json" cfg.init.mappings.keymap} init
   '';
 
   mkRule = {
@@ -72,6 +84,8 @@ in {
   options.soispha.programs.river = {
     enable = lib.mkEnableOption "river";
 
+    package = lib.mkPackageOption pkgs "river-classic" {};
+
     unicodeInput = {
       enable = lib.mkEnableOption "udev rules for rawhid based unicode input";
     };
@@ -175,8 +189,12 @@ in {
     };
   };
 
+  imports = [
+    ./keymap.nix
+  ];
+
   config = lib.mkIf cfg.enable {
-    services.udev.packages = lib.mkIf cfg.unicodeInput.enable [qmk_firmware.packages.${system}.qmk_unicode_type];
+    services.udev.packages = lib.mkIf cfg.unicodeInput.enable [externalBinaries.qmk_firmware.packages.${system}.qmk_unicode_type];
 
     home-manager.users.soispha = {
       home.sessionVariables = {
@@ -193,7 +211,8 @@ in {
       };
 
       home.packages = [
-        pkgs.river-start
+        (pkgs.callPackage ./river-start/package.nix {})
+        pkgs.swallow
       ];
 
       xdg.configFile."river/init" = {
@@ -219,7 +238,7 @@ in {
           + mkHeading "Background services" longRunningPrograms
           + mkHeading "Layout Setup" ''
             err_fail ${riverctl} default-layout rivertile
-            ${lib.getExe' pkgs.river "rivertile"} -main-ratio 0.5 -view-padding 1 -outer-padding 0
+            ${lib.getExe' cfg.package "rivertile"} -main-ratio 0.5 -view-padding 1 -outer-padding 0
           '';
       };
     };
diff --git a/pkgs/by-name/ri/river-start/package.nix b/modules/by-name/ri/river/river-start/package.nix
index 10957cc0..3ae204b7 100644
--- a/pkgs/by-name/ri/river-start/package.nix
+++ b/modules/by-name/ri/river/river-start/package.nix
@@ -9,13 +9,13 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
   writeShellApplication,
-  river,
+  river-classic,
 }:
 writeShellApplication {
   name = "river-start";
   text = builtins.readFile ./river-start.sh;
   runtimeInputs = [
-    river
+    river-classic
   ];
   meta = {
     mainProgram = "river-start";
diff --git a/pkgs/by-name/ri/river-start/river-start.sh b/modules/by-name/ri/river/river-start/river-start.sh
index e3a4adcb..55eddfcf 100755
--- a/pkgs/by-name/ri/river-start/river-start.sh
+++ b/modules/by-name/ri/river/river-start/river-start.sh
@@ -10,8 +10,7 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-# NOTE: Keep this in sync with the file from `base_init.sh` <2025-02-03>
-RIVER_LOG_FILE="$HOME/.local/share/river/log"
+RIVER_LOG_FILE="$HOME/.cache/river/wm-log"
 
 [ -d "$(dirname "$RIVER_LOG_FILE")" ] || mkdir --parents "$(dirname "$RIVER_LOG_FILE")"
 
diff --git a/modules/by-name/ro/rofi/module.nix b/modules/by-name/ro/rofi/module.nix
new file mode 100644
index 00000000..f2b404d6
--- /dev/null
+++ b/modules/by-name/ro/rofi/module.nix
@@ -0,0 +1,31 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  config,
+  lib,
+  libraries,
+  ...
+}: let
+  cfg = config.soispha.programs.rofi;
+in {
+  options.soispha.programs.rofi = {
+    enable = libraries.base.options.mkEnable "rofi";
+  };
+
+  config = lib.mkIf cfg.enable {
+    home-manager.users.soispha = {
+      programs.rofi = {
+        enable = true;
+        terminal = lib.getExe config.soispha.programs.alacritty.package;
+        theme = ./nord-twoLines.rasi;
+      };
+    };
+  };
+}
diff --git a/modules/home.legacy/conf/rofi/nord-twoLines.rasi b/modules/by-name/ro/rofi/nord-twoLines.rasi
index 612b907f..612b907f 100644
--- a/modules/home.legacy/conf/rofi/nord-twoLines.rasi
+++ b/modules/by-name/ro/rofi/nord-twoLines.rasi
diff --git a/modules/home.legacy/conf/rofi/nord-twoLines.rasi.license b/modules/by-name/ro/rofi/nord-twoLines.rasi.license
index eae6a84c..eae6a84c 100644
--- a/modules/home.legacy/conf/rofi/nord-twoLines.rasi.license
+++ b/modules/by-name/ro/rofi/nord-twoLines.rasi.license
diff --git a/modules/by-name/se/serverphone/module.currently_ignored.nix b/modules/by-name/se/serverphone/module.currently_ignored.nix
index 378fc7c3..f7280bed 100644
--- a/modules/by-name/se/serverphone/module.currently_ignored.nix
+++ b/modules/by-name/se/serverphone/module.currently_ignored.nix
@@ -12,11 +12,22 @@
   serverphone,
   system,
   lib,
+  modules,
   ...
-}: {
+}: let
+  cfg = config.soispha.serverphone;
+in {
   # FIXME: Reactive this module, when serverphone is working again <2024-05-11>
 
-  config = lib.mkIf config.soispha.secrets.enable {
+  options.soispha.serverphone = {
+    enable = lib.mkEnableOption "serverphone";
+  };
+
+  imports = [
+    modules.serverphone.nixosModules.default
+  ];
+
+  config = lib.mkIf cfg.enable {
     age.secrets = {
       serverphoneCa = {
         file = ./private_keys/ca.key;
diff --git a/modules/by-name/so/sound/module.nix b/modules/by-name/so/sound/module.nix
index 622cc01d..06df63e5 100644
--- a/modules/by-name/so/sound/module.nix
+++ b/modules/by-name/so/sound/module.nix
@@ -9,13 +9,14 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
   config,
+  libraries,
   lib,
   ...
 }: let
   cfg = config.soispha.sound;
 in {
   options.soispha.sound = {
-    enable = lib.mkEnableOption "sound based on pipewire";
+    enable = libraries.base.options.mkEnable "sound based on pipewire";
   };
 
   config = lib.mkIf cfg.enable {
@@ -30,6 +31,11 @@ in {
       jack.enable = true;
     };
 
+    users = {
+      users.rtkit.uid = config.soispha.constants.ids.uids.rtkit;
+      groups.rtkit.gid = config.soispha.constants.ids.gids.rtkit;
+    };
+
     # TODO: Find a better way to set the default volume <2024-03-10>
     #
     # environment.etc.pipewire-pulse-config = {
diff --git a/modules/by-name/ss/ssh/module.nix b/modules/by-name/ss/ssh/module.nix
index 91cc4aeb..f7218e36 100644
--- a/modules/by-name/ss/ssh/module.nix
+++ b/modules/by-name/ss/ssh/module.nix
@@ -14,6 +14,18 @@
   ...
 }: let
   cfg = config.soispha.programs.ssh;
+
+  mkDefaultMatchBlock = userKnownHostsFile: {
+    addKeysToAgent = "no";
+    compression = true;
+    controlMaster = "no";
+    controlPersist = "no";
+    forwardAgent = false;
+    hashKnownHosts = false;
+    serverAliveCountMax = 3;
+    serverAliveInterval = 240;
+    inherit userKnownHostsFile;
+  };
 in {
   options.soispha.programs.ssh = {
     enable = lib.mkEnableOption "ssh config";
@@ -34,21 +46,21 @@ in {
     home-manager.users = {
       root.programs.ssh = {
         enable = true;
-        compression = true;
-        hashKnownHosts = false;
-        serverAliveInterval = 240;
-        userKnownHostsFile = builtins.toString (pkgs.writeTextFile {
-          name = "root-known-hosts";
-          text = cfg.rootKnownHosts;
-        });
+        enableDefaultConfig = false;
+
+        matchBlocks."*" = mkDefaultMatchBlock (
+          builtins.toString (pkgs.writeTextFile {
+            name = "root-known-hosts";
+            text = cfg.rootKnownHosts;
+          })
+        );
       };
 
       soispha.programs.ssh = {
         enable = true;
-        compression = true;
-        hashKnownHosts = false;
-        serverAliveInterval = 240;
-        userKnownHostsFile = "${config.home-manager.users.soispha.xdg.dataHome}/ssh/known_hosts";
+        enableDefaultConfig = false;
+
+        matchBlocks."*" = mkDefaultMatchBlock "${config.home-manager.users.soispha.xdg.dataHome}/ssh/known_hosts";
       };
     };
   };
diff --git a/modules/by-name/st/steam/module.nix b/modules/by-name/st/steam/module.nix
index a02b2e4b..87cdc709 100644
--- a/modules/by-name/st/steam/module.nix
+++ b/modules/by-name/st/steam/module.nix
@@ -10,7 +10,6 @@
 {
   lib,
   config,
-  pkgs,
   ...
 }: let
   cfg = config.soispha.programs.steam;
@@ -22,8 +21,8 @@ in {
   config = lib.mkIf cfg.enable {
     nixpkgs.config.allowUnfreePredicate = pkg:
       builtins.elem (lib.getName pkg) [
-        # NOTE: These are not really applied. Look at
-        # <modules/by-name/ni/nixpkgs/config.nix> instead. <2025-04-25>
+        # NOTE: These are not really applied. Needs to be at
+        # <modules/by-name/ni/nixpkgs/config.nix> for some reason. <2025-04-25>
         "steam"
         "steam-unwrapped"
         "steam-original"
diff --git a/modules/by-name/ta/taskwarrior/module.nix b/modules/by-name/ta/taskwarrior/module.nix
index 4c174244..d757be90 100644
--- a/modules/by-name/ta/taskwarrior/module.nix
+++ b/modules/by-name/ta/taskwarrior/module.nix
@@ -16,7 +16,7 @@
   cfg = config.soispha.programs.taskwarrior;
 
   hooksDir =
-    pkgs.runCommandNoCCLocal "mk-taskwarrior-hooks" {}
+    pkgs.runCommandLocal "mk-taskwarrior-hooks" {}
     (''
         mkdir "$out"
       ''
@@ -76,6 +76,8 @@ in {
   options.soispha.programs.taskwarrior = {
     enable = lib.mkEnableOption "taskwarrior";
 
+    enableAge = lib.mkEnableOption "taskwarrior with age keys";
+
     includeFiles = lib.mkOption {
       type = lib.types.attrsOf lib.types.path;
       description = "Extra files to include in the taskwarrior config";
@@ -108,17 +110,17 @@ in {
       inherit mkHook;
     };
 
-    age.secrets.taskwarrior_sync_server_encryption_key = lib.mkIf cfg.enable {
+    age.secrets.taskwarrior_sync_server_encryption_key = lib.mkIf (cfg.enable && cfg.enableAge) {
       file = ./secrets/sync_server_encryption_key.age;
       mode = "700";
       owner = "soispha";
       group = "users";
     };
 
-    soispha.programs.taskwarrior.includeFiles.syncServerSecret = lib.mkIf cfg.enable config.age.secrets.taskwarrior_sync_server_encryption_key.path;
+    soispha.programs.taskwarrior.includeFiles.syncServerSecret = lib.mkIf (cfg.enable && cfg.enableAge) config.age.secrets.taskwarrior_sync_server_encryption_key.path;
 
     home-manager.users.soispha = lib.mkIf cfg.enable {
-      services.taskwarrior-sync = {
+      services.taskwarrior-sync = lib.mkIf cfg.enableAge {
         enable = true;
         package = pkgs.taskwarrior3;
       };
@@ -148,7 +150,7 @@ in {
             };
           };
 
-          sync.server = {
+          sync.server = lib.mkIf cfg.enableAge {
             client_id = "a3619d43-031f-4f85-848f-5512804f9a1d";
             url = "https://taskchampion.vhack.eu";
           };
diff --git a/modules/by-name/ts/tskm/module.nix b/modules/by-name/ts/tskm/module.nix
index f0d6a50d..6f6517f8 100644
--- a/modules/by-name/ts/tskm/module.nix
+++ b/modules/by-name/ts/tskm/module.nix
@@ -23,13 +23,13 @@
   in
     [name] ++ subprojects;
 
-  firefoxProfiles = builtins.listToAttrs (lib.imap0 (index: name:
-    lib.attrsets.nameValuePair name {
+  qutebrowserProfiles = builtins.listToAttrs (
+    builtins.map (name: {
       inherit name;
-      # Add one here, so that we can have the default profile at id 0.
-      id = index + 1;
+      value = {};
     })
-  allProjectNames);
+    allProjectNames
+  );
 
   contexts =
     builtins.concatStringsSep "\n"
@@ -99,7 +99,8 @@ in {
 
   config = lib.mkIf cfg.enable {
     soispha.programs = {
-      firefox.profiles = firefoxProfiles;
+      qutebrowser.profiles = qutebrowserProfiles;
+
       taskwarrior = {
         includeFiles = {
           tskm-contexts = contextsFile;
@@ -119,7 +120,7 @@ in {
     home-manager.users.soispha = {
       home.sessionVariables = {
         # TODO: Remove this hard-coded path with a reference. <2025-04-04>
-        "TSKM_PROJECT_FILE" = "/home/soispha/repos/nix/config/modules/common/projects.json";
+        "TSKM_PROJECT_FILE" = "/home/soispha/repos/nix/own/config/modules/common/projects.json";
       };
 
       programs.nixvim = {
diff --git a/modules/by-name/un/unison/module.nix b/modules/by-name/un/unison/module.nix
index ef1a4cc1..8d156b00 100644
--- a/modules/by-name/un/unison/module.nix
+++ b/modules/by-name/un/unison/module.nix
@@ -11,12 +11,11 @@
   lib,
   config,
   pkgs,
-  sysLib,
   ...
 }: let
   cfg = config.soispha.services.unison;
 
-  script = import ./shellScript.nix {inherit sysLib lib pkgs cfg;};
+  script = import ./shellScript.nix {inherit lib pkgs cfg;};
 in {
   options.soispha.services.unison = let
     homePath = lib.types.strMatching "^~.*";
diff --git a/modules/by-name/un/unison/shellScript.nix b/modules/by-name/un/unison/shellScript.nix
index a6916a52..df373805 100644
--- a/modules/by-name/un/unison/shellScript.nix
+++ b/modules/by-name/un/unison/shellScript.nix
@@ -8,7 +8,6 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
-  sysLib,
   lib,
   pkgs,
   cfg,
@@ -69,7 +68,7 @@
     lib.strings.concatStringsSep " " [
       "unison"
       "${serialiseArgs cfg.unisonOptions}"
-      "$EXTRA_OPTIONS"
+      "\"$@\""
       "${getIgnored cfg.pathsToIgnore path}"
       "${esa path}"
       (esa "ssh://${cfg.foreign.userName}@${cfg.foreign.address}/${path}")
@@ -77,24 +76,18 @@
 
   script = lib.strings.concatStringsSep "\n" (builtins.map mkScriptLine cfg.pathsToSync);
 in
-  sysLib.writeShellScript {
+  pkgs.writeShellApplication {
     name = "unison-sync";
-    src = builtins.toFile "unison-backup" (''
-        #!/usr/bin/env dash
+    text = script;
 
-        # shellcheck source=/dev/null
-        SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-        export UNISON=${esa cfg.dataDir};
-
-        EXTRA_OPTIONS="$UNISON_EXTRA_OPTIONS $*"
-      ''
-      + script);
+    runtimeEnv = {
+      UNISON = cfg.dataDir;
+    };
 
-    dependencies = with pkgs; [
-      unison
-      openssh # needed to connect to the other server
-      less # needed to show diffs
-      diffutils # needed to compute diffs
+    runtimeInputs = [
+      pkgs.unison
+      pkgs.openssh # needed to connect to the other server
+      pkgs.less # needed to show diffs
+      pkgs.diffutils # needed to compute diffs
     ];
   }
diff --git a/modules/by-name/up/upower/module.nix b/modules/by-name/up/upower/module.nix
new file mode 100644
index 00000000..f5a62ed7
--- /dev/null
+++ b/modules/by-name/up/upower/module.nix
@@ -0,0 +1,23 @@
+{
+  config,
+  lib,
+  ...
+}: let
+  cfg = config.soispha.services.upower;
+in {
+  options.soispha.services.upower = {
+    enable = lib.mkEnableOption "upower";
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.upower = {
+      enable = true;
+      usePercentageForPolicy = true;
+
+      percentageLow = 15;
+      percentageAction = 10;
+
+      criticalPowerAction = "Hibernate";
+    };
+  };
+}
diff --git a/modules/by-name/us/users/module.nix b/modules/by-name/us/users/module.nix
index 555e61f9..65b75d2e 100644
--- a/modules/by-name/us/users/module.nix
+++ b/modules/by-name/us/users/module.nix
@@ -25,7 +25,7 @@ in {
     };
     groups = lib.mkOption {
       type = lib.types.listOf lib.types.str;
-      default = ["wheel"];
+      default = ["wheel" "audio"];
       description = "The groups the soispha user should be part of";
     };
 
diff --git a/modules/by-name/xd/xdg/module.nix b/modules/by-name/xd/xdg/module.nix
index 94c5a975..9ff71ca0 100644
--- a/modules/by-name/xd/xdg/module.nix
+++ b/modules/by-name/xd/xdg/module.nix
@@ -26,7 +26,9 @@
     name = "url-handler";
 
     runtimeInputs = [pkgs.rofi pkgs.libnotify pkgs.zathura pkgs.tskm];
-    inheritPath = false;
+
+    # We need to run the browser in tskm or nvim and alacritty.
+    inheritPath = true;
 
     text = builtins.readFile ./scripts/url-handler.sh;
   };
@@ -98,20 +100,18 @@ in {
         };
         config = {
           common = {
-            # NOTE: The next entry is supposedly needed for gtk based apps <2023-08-31>
-            default = ["wlr" "gtk"];
+            default = ["wlr"];
             "org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
           };
 
           # TODO: Also activate, when on another wlr-based compositor <2023-11-25>
           river = {
-            default = ["wlr" "gtk"];
+            default = ["wlr"];
             "org.freedesktop.impl.portal.FileChooser" = ["termfilechooser"];
           };
         };
 
         extraPortals = [
-          pkgs.xdg-desktop-portal-gtk
           pkgs.xdg-desktop-portal-wlr
           pkgs.xdg-desktop-portal-termfilechooser
         ];
diff --git a/modules/by-name/ya/yambar/config/config.yml b/modules/by-name/ya/yambar/config/config.yml
deleted file mode 100644
index 14da18fd..00000000
--- a/modules/by-name/ya/yambar/config/config.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
----
-# Config file for yambar
-# Note that this may be version-dependent, this file is written for v1.8.0
-
-bar:
-  right:
-   # - network:
-   #    name: wlp5s0
-   #    poll-interval: 10
-   #    content:
-   #      map:
-   #        on-click: /bin/sh -c "nmtui"
-   #        conditions:
-   #          ~carrier: {empty: {}}
-   #          carrier:
-   #            string: {text: "  {ssid} ", deco: *combutil}
-   # - network:
-   #    name: enp4s0
-   #    content:
-   #      map:
-   #        on-click: /bin/sh -c "nmtui"
-   #        conditions:
-   #          ~carrier:
-   #            string: {text: "  Eth failed ", deco: *combutil}
-   #          carrier: {empty: {}}
-   # - script:   # Grade average
-   #     path: grade_average_script
-   #     content:
-   #       string:
-   #         text: "   {grade} "
-   #         deco: *combmem
-   # - script:   # tray
-   #    path: /home/dt/.config/yambar/scripts/yambar-tray
-   #    content:
-   #      empty: {}
-   # - script:
-   #    path: /home/dt/.config/yambar/scripts/yambar-tray-width
-   #    poll-interval: 10
-   #    content:
-   #      string:
-   #         text: "{padding}"
-   #         deco: *combmem
diff --git a/modules/by-name/ya/yambar/module.nix b/modules/by-name/ya/yambar/module.nix
deleted file mode 100644
index 5a7b2efc..00000000
--- a/modules/by-name/ya/yambar/module.nix
+++ /dev/null
@@ -1,80 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  config,
-  sysLib,
-  pkgs,
-  lib,
-  ...
-}: let
-  cfg = config.soispha.programs.yambar;
-
-  makeScript = {
-    name,
-    dependencies,
-    ...
-  }:
-    sysLib.writeShellScript {
-      inherit name;
-      src = ./scripts/${name}.sh;
-      dependencies = dependencies ++ (builtins.attrValues {inherit (pkgs) dash;});
-    }
-    + "/bin/${name}";
-
-  mkWrapper = bin: cmd:
-    pkgs.writeShellScript cmd ''
-      ${bin} ${cmd}
-    '';
-in {
-  options.soispha.programs.yambar = {
-    enable = lib.mkEnableOption "yambar";
-
-    laptop = lib.mkEnableOption "laptop specific settings";
-    backlight = lib.mkOption {
-      type = lib.types.str;
-      example = "intel_backlight";
-      description = "Which backlight to query for the screen brightness";
-    };
-  };
-
-  config = lib.mkIf cfg.enable {
-    home-manager.users.soispha = {
-      programs.yambar = {
-        enable = true;
-        settings = import ./settings {
-          inherit lib;
-          inherit (cfg) laptop;
-          laptopBacklightName = cfg.backlight;
-
-          scripts = {
-            mpd_song_name_script = makeScript {
-              dependencies = [pkgs.mpc];
-              name = "mpd_song_name";
-            };
-
-            volume_script = makeScript {
-              dependencies = with pkgs; [pulseaudio gawk coreutils];
-              name = "sound-volume";
-            };
-
-            cpu_script = mkWrapper (lib.getExe pkgs.yambar-modules) "cpu";
-
-            memory_script = mkWrapper (lib.getExe pkgs.yambar-modules) "memory";
-
-            disk_script = makeScript {
-              dependencies = with pkgs; [gawk btrfs-progs coreutils];
-              name = "disk";
-            };
-          };
-        };
-      };
-    };
-  };
-}
diff --git a/modules/by-name/ya/yambar/scripts/disk.sh b/modules/by-name/ya/yambar/scripts/disk.sh
deleted file mode 100755
index 4efe1384..00000000
--- a/modules/by-name/ya/yambar/scripts/disk.sh
+++ /dev/null
@@ -1,31 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-# Main loop
-while true; do
-    # vars
-    used_space=$(btrfs filesystem usage /srv 2>/dev/null | awk '{if ( /Used:/ ) { print $2 } } ' | head -n1)
-    all_space=$(btrfs filesystem usage /srv 2>/dev/null | awk '{if ( /Device size:/ ) { print $3 } } ' | head -n1 | tr -d "GiB")
-
-    # Check space available (4) and percentage used (5)
-    spaceperc=$(echo "$(echo "$used_space" | tr -d "GiB")" "$all_space" | awk '{div=$1/$2;div *= 100; printf"%2d%%\n",div }')
-
-    echo "diskspace|string|$used_space"
-    echo "diskperc|string|$spaceperc"
-    echo ""
-    sleep 1
-done
-
-# vim: ft=sh
diff --git a/modules/by-name/ya/yambar/scripts/network.sh b/modules/by-name/ya/yambar/scripts/network.sh
deleted file mode 100755
index d642e6c7..00000000
--- a/modules/by-name/ya/yambar/scripts/network.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-retest=120
-retest_if_con_fails=10
-backend=nmcli
-
-case "$backend" in
-"nmcli") # Test for connectivity with nmcli
-    while true; do
-        connection_status=$(nmcli networking connectivity)
-        if [ "$connection_status" = "full" ]; then
-            echo "internet|string|Connected"
-            echo ""
-            sleep $retest
-        else
-            echo "internet|string|Disconnected"
-            echo ""
-            sleep $retest_if_con_fails
-        fi
-    done
-    ;;
-"ping") # Test for connectivity with ping
-    ip_address='8.8.8.8'
-    ping_number=3
-
-    while true; do
-
-        ping_result=$(mktmp)
-        ping $ip_address -c $ping_number -q | awk 'BEGIN {FS="/"} END {print $5}' >"$ping_result"
-
-        if [ "$(wc -l <"$ping_result")" -eq 0 ]; then
-            echo "med|string|No connection"
-            echo ""
-            sleep $retest_if_con_fails
-        else
-            echo "med|string|$(cat "$ping_result") ms"
-            echo ""
-            sleep $retest
-        fi
-    done
-    ;;
-esac
-
-# vim: ft=sh
diff --git a/modules/by-name/ya/yambar/scripts/sound-volume.sh b/modules/by-name/ya/yambar/scripts/sound-volume.sh
deleted file mode 100755
index 9d9f7be8..00000000
--- a/modules/by-name/ya/yambar/scripts/sound-volume.sh
+++ /dev/null
@@ -1,30 +0,0 @@
-#! /usr/bin/env dash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# shellcheck source=/dev/null
-SHELL_LIBRARY_VERSION="2.1.2" . %SHELL_LIBRARY_PATH
-
-while true; do
-    volume="$(pactl get-sink-volume 0 | awk 'BEGIN { FS="/" } {gsub("%","",$2); gsub(" ","",$2)} {printf $2}')"
-
-    if [ "$volume" -eq 0 ]; then
-        echo "muted|bool|true"
-    else
-        echo "volume|string|$volume"
-        echo "muted|bool|false"
-    fi
-    echo ""
-
-    sleep 3
-done
-
-# vim: ft=sh
diff --git a/modules/by-name/ya/yambar/settings/default.nix b/modules/by-name/ya/yambar/settings/default.nix
deleted file mode 100644
index ebe17261..00000000
--- a/modules/by-name/ya/yambar/settings/default.nix
+++ /dev/null
@@ -1,383 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-# TODO: This should not do something depending on whether the host is a laptop or not. It
-# should instead match on monitor-width or scale factor. <2024-11-29>
-{
-  lib,
-  laptop ? false,
-  laptopBacklightName ? null,
-  scripts,
-}: let
-  mkUnderline = color: {
-    underline = {
-      inherit color;
-      size = 3;
-    };
-  };
-
-  shellExec = cmd: ''sh -c "${cmd}"'';
-
-  values = {
-    foreground = {
-      blue = "99d1dbff";
-      focus = "e78284ff";
-      green = "a6e3a1dd";
-      lavendar = "b4befedd";
-      mauve = "cba6f7dd";
-      none = "00000000";
-      normal = "c6ceefff";
-      peach = "fab387dd";
-      sapphire = "74c7ecdd";
-      teal = "94e2d5dd";
-    };
-    font = {
-      main = "Source Code Pro:pixelsize=${
-        builtins.toString (
-          if laptop
-          then 22
-          else 26
-        )
-      }";
-      aws = "Font Awesome 5 Free:style=solid:pixelsize=${
-        builtins.toString (
-          if laptop
-          then 20
-          else 23
-        )
-      }";
-    };
-    background = {
-      normal = "303446ff";
-      tag = "585b70ff";
-      tag2 = "45475aff";
-      urgent = "e78284ff";
-    };
-    backgroundBlock = {
-      normal = {background = {color = values.background.normal;};};
-      urgent = {background = {color = values.background.urgent;};};
-    };
-    underline = {
-      battery = mkUnderline values.foreground.sapphire;
-      clock = mkUnderline values.foreground.teal;
-      focused = mkUnderline values.foreground.focus;
-      resources = mkUnderline values.foreground.green;
-      title = mkUnderline values.background.tag;
-      urgent = mkUnderline values.foreground.blue;
-      utils = mkUnderline values.foreground.peach;
-      weather = mkUnderline values.foreground.lavendar;
-    };
-    combination = {
-      battery.stack = [
-        values.backgroundBlock.normal
-        values.underline.battery
-      ];
-      clock.stack = [
-        values.backgroundBlock.normal
-        values.underline.clock
-      ];
-      resources.stack = [
-        values.backgroundBlock.normal
-        values.underline.resources
-      ];
-      utils.stack = [
-        values.backgroundBlock.normal
-        values.underline.utils
-      ];
-      weather.stack = [
-        values.backgroundBlock.normal
-        values.underline.weather
-      ];
-    };
-  };
-in {
-  bar = {
-    background = values.foreground.none;
-    foreground = values.foreground.normal;
-
-    font = values.font.main;
-    height =
-      if laptop
-      then 25
-      else 45;
-    margin =
-      if laptop
-      then 5
-      else 10;
-    location = "top";
-    layer = "bottom";
-    spacing = 0;
-
-    border = {
-      margin = 0;
-      top-margin = 10;
-    };
-
-    left = [
-      {
-        river = let
-          tag_base_setting = {
-            map = let
-              normal = {
-                string = {
-                  margin = 10;
-                  text = "{id}";
-                };
-              };
-            in {
-              default = normal;
-              conditions = {
-                "state == focused" = {
-                  string = {
-                    deco = {
-                      stack = [
-                        {background = {color = values.background.tag;};}
-                        values.underline.focused
-                      ];
-                    };
-                    margin = 10;
-                    text = "{id}";
-                  };
-                };
-                "state == invisible" = {
-                  map = {
-                    conditions = {
-                      occupied = {
-                        string = {
-                          deco = {background = {color = values.background.tag2;};};
-                          margin = 10;
-                          text = "{id}";
-                        };
-                      };
-                      "~occupied" = normal;
-                    };
-                  };
-                };
-                "state == unfocused" = {
-                  string = {
-                    deco = {background = {color = values.background.tag2;};};
-                    margin = 10;
-                    text = "{id}";
-                  };
-                };
-                "state == urgent" = {
-                  string = {
-                    deco = {
-                      stack = [
-                        {background = {color = values.background.urgent;};}
-                        values.underline.urgent
-                      ];
-                    };
-                    margin = 10;
-                    text = "{id}";
-                  };
-                };
-              };
-            };
-          };
-        in {
-          content = {
-            map = {
-              conditions = {
-                "id == 1" = tag_base_setting;
-                "id == 2" = tag_base_setting;
-                "id == 3" = tag_base_setting;
-                "id == 4" = tag_base_setting;
-                "id == 5" = tag_base_setting;
-                "id == 6" = tag_base_setting;
-                "id == 7" = tag_base_setting;
-                "id == 8" = tag_base_setting;
-                "id == 9" = tag_base_setting;
-              };
-              on-click = {
-                left = shellExec "riverctl set-focused-tags $((1 << ({id} - 1)))";
-                middle = shellExec "riverctl toggle-view-tags $((1 << ({id} -1)))";
-                right = shellExec "riverctl toggle-focused-tags $((1 << ({id} -1)))";
-              };
-            };
-          };
-          title = {
-            map = {
-              conditions = {"title == \"\"" = {string = {text = "";};};};
-              default = {
-                string = {
-                  max = 35;
-                  deco = values.underline.title;
-                  left-margin = 12;
-                  right-margin = 12;
-                  text = "{title}";
-                };
-              };
-            };
-          };
-        };
-      }
-    ];
-
-    center = [
-      {
-        clock = {
-          date-format = "%d/%m/%y (%a)";
-          time-format = "%H:%M:%S %Z";
-          foreground = values.foreground.blue;
-          content = {
-            string = {
-              deco = values.combination.clock;
-              text = " {date} {time} ";
-            };
-          };
-        };
-      }
-    ];
-
-    right =
-      [
-        {
-          script = {
-            path = scripts.mpd_song_name_script;
-            content.map.conditions = {
-              playing = {
-                string = {
-                  deco = values.combination.weather;
-                  text = "{song} ";
-                };
-              };
-              "~playing" = {
-                string = {
-                  deco = values.combination.weather;
-                  text = "";
-                };
-              };
-            };
-          };
-        }
-        {
-          script = {
-            path = scripts.volume_script;
-            content.map = {
-              on-click = shellExec "pavucontrol";
-              conditions = {
-                muted = {
-                  string = {
-                    deco = values.backgroundBlock.urgent;
-                    text = " 󰝟 ";
-                  };
-                };
-                "~muted" = {
-                  string = {
-                    deco = values.combination.utils;
-                    text = "  {volume}% ";
-                  };
-                };
-              };
-            };
-          };
-        }
-        {
-          script = {
-            path = scripts.cpu_script;
-            content.string = {
-              deco = values.combination.resources;
-              text = "  {cpu}% ";
-            };
-          };
-        }
-        {
-          script = {
-            path = scripts.memory_script;
-            content.map.conditions = {
-              swapstate = {
-                string = {
-                  deco = values.combination.resources;
-                  text = "  {memperc}%({swapperc}%) ";
-                };
-              };
-              "~swapstate" = {
-                string = {
-                  deco = values.combination.resources;
-                  text = "  {memperc}% ";
-                };
-              };
-            };
-          };
-        }
-        {
-          script = {
-            path = scripts.disk_script;
-            content.string = {
-              deco = values.combination.resources;
-              text = " 󰋊 {diskspace}({diskperc})";
-            };
-          };
-        }
-      ]
-      ++ lib.optionals laptop [
-        {
-          backlight = {
-            name = laptopBacklightName;
-            content.string = {
-              text = "  {percent}% ";
-              deco = values.combination.utils;
-            };
-          };
-        }
-        {
-          battery = {
-            name = "BAT0";
-            poll-interval = 300;
-            content.list.items = [
-              {
-                ramp = {
-                  tag = "capacity";
-                  items = let
-                    stack = [
-                      values.backgroundBlock.normal
-                      values.underline.battery
-                    ];
-                  in [
-                    {
-                      string = {
-                        text = "  {capacity}%({estimate}) ";
-                        deco =
-                          values.backgroundBlock.urgent;
-                      };
-                    }
-                    {
-                      string = {
-                        text = "  {capacity}%({estimate}) ";
-                        deco.stack = stack;
-                      };
-                    }
-                    {
-                      string = {
-                        text = "  {capacity}%({estimate}) ";
-                        deco.stack = stack;
-                      };
-                    }
-                    {
-                      string = {
-                        text = "  {capacity}%({estimate}) ";
-                        deco.stack = stack;
-                      };
-                    }
-                    {
-                      string = {
-                        text = "  {capacity}%({estimate}) ";
-                        deco.stack = stack;
-                      };
-                    }
-                  ];
-                };
-              }
-            ];
-          };
-        }
-      ];
-  };
-}
diff --git a/modules/by-name/yt/yt/config.toml b/modules/by-name/yt/yt/config.toml
deleted file mode 100644
index aecb74ba..00000000
--- a/modules/by-name/yt/yt/config.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[download]
-max_cache_size = "5 GiB"
diff --git a/modules/by-name/yt/yt/external_commands_script.sh b/modules/by-name/yt/yt/external_commands_script.sh
new file mode 100755
index 00000000..2e59e94a
--- /dev/null
+++ b/modules/by-name/yt/yt/external_commands_script.sh
@@ -0,0 +1,9 @@
+#! /usr/bin/env sh
+
+riverctl focus-output next
+
+alacritty --title "floating please" --command "$@"
+
+riverctl focus-output next
+
+# vim: ft=sh
diff --git a/modules/by-name/yt/yt/input.conf b/modules/by-name/yt/yt/input.conf
deleted file mode 100644
index 68dad824..00000000
--- a/modules/by-name/yt/yt/input.conf
+++ /dev/null
@@ -1,14 +0,0 @@
-c script-message yt-comments-external
-C script-message yt-comments-local
-
-d script-message yt-description-external
-D script-message yt-description-local
-
-WHEEL_LEFT playlist-prev
-WHEEL_RIGHT playlist-next
-
-q script-message yt-mark-watched
-Q script-message yt-mark-picked
-r script-message yt-check-new-videos
-
-P quit
diff --git a/modules/by-name/yt/yt/input.conf.license b/modules/by-name/yt/yt/input.conf.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/yt/yt/input.conf.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/yt/yt/module.nix b/modules/by-name/yt/yt/module.nix
index 4e7e90fe..81bacf44 100644
--- a/modules/by-name/yt/yt/module.nix
+++ b/modules/by-name/yt/yt/module.nix
@@ -10,9 +10,102 @@
 {
   config,
   lib,
+  pkgs,
   ...
 }: let
   cfg = config.soispha.programs.yt;
+
+  mkConfig = (pkgs.formats.toml {}).generate;
+
+  mpvInputConfig = {
+    "c" = "script-message yt-comments-external";
+    "C" = "script-message yt-comments-local";
+
+    "d" = "script-message yt-description-external";
+    "D" = "script-message yt-description-local";
+
+    "t" = "script-message yt-thumbnail-external";
+    "I" = "script-message yt-info-external";
+
+    "WHEEL_LEFT" = "playlist-prev";
+    "WHEEL_RIGHT" = "playlist-next";
+
+    "q" = "script-message yt-mark-watched";
+    "Q" = "script-message yt-mark-picked";
+    "r" = "script-message yt-check-new-videos";
+
+    "P" = "quit";
+  };
+
+  mpvConf = {
+    "volume" = 75;
+  };
+
+  ytConfig = {
+    download = {
+      max_cache_size = "5 GiB";
+    };
+
+    commands = {
+      image_show = [
+        (lib.getExe
+          (pkgs.writeShellApplication {
+            name = "show_thumbnail";
+            text = ''
+              imv -w "floating please" "$1"
+            '';
+            runtimeInputs = [
+              pkgs.imv
+            ];
+
+            inheritPath = false;
+          }))
+      ];
+
+      external_spawn = [
+        (lib.getExe
+          (pkgs.writeShellApplication {
+            name = "start_external_command";
+            text = builtins.readFile ./external_commands_script.sh;
+            runtimeInputs = [
+              pkgs.river-classic
+              pkgs.alacritty
+              pkgs.less
+            ];
+
+            inheritPath = false;
+          }))
+      ];
+
+      url_opener = ["qutebrowser-timesinks.youtube"];
+    };
+  };
+
+  inherit (lib) generators;
+  inherit (builtins) typeOf stringLength;
+
+  renderOption = option:
+    rec {
+      int = toString option;
+      float = int;
+      bool = lib.hm.booleans.yesNo option;
+      string = option;
+    }
+    .${
+      typeOf option
+    };
+
+  renderOptionValue = value: let
+    rendered = renderOption value;
+    length = toString (stringLength rendered);
+  in "%${length}%${rendered}";
+
+  renderOptions = generators.toKeyValue {
+    mkKeyValue = generators.mkKeyValueDefault {mkValueString = renderOptionValue;} "=";
+    listsAsDuplicateKeys = true;
+  };
+
+  renderBindings = bindings: lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: "${name} ${value}") bindings);
 in {
   options.soispha.programs.yt = {
     enable = lib.mkEnableOption "the yt cli client";
@@ -21,9 +114,9 @@ in {
   config = {
     home-manager.users.soispha = lib.mkIf cfg.enable {
       xdg.configFile = {
-        "yt/mpv.conf".source = ./mpv.conf;
-        "yt/mpv.input.conf".source = ./input.conf;
-        "yt/config.toml".source = ./config.toml;
+        "yt/mpv.conf".text = renderOptions mpvConf;
+        "yt/mpv.input.conf".text = renderBindings mpvInputConfig;
+        "yt/config.toml".source = mkConfig "config.toml" ytConfig;
       };
     };
   };
diff --git a/modules/by-name/yt/yt/mpv.conf b/modules/by-name/yt/yt/mpv.conf
deleted file mode 100644
index 52a40823..00000000
--- a/modules/by-name/yt/yt/mpv.conf
+++ /dev/null
@@ -1 +0,0 @@
-volume=75
diff --git a/modules/by-name/yt/yt/mpv.conf.license b/modules/by-name/yt/yt/mpv.conf.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/by-name/yt/yt/mpv.conf.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/by-name/zs/zsh/config/command_not_found/command_not_found_insult.sh b/modules/by-name/zs/zsh/config/command_not_found/command_not_found_insult.sh
deleted file mode 100644
index a5d71939..00000000
--- a/modules/by-name/zs/zsh/config/command_not_found/command_not_found_insult.sh
+++ /dev/null
@@ -1,309 +0,0 @@
-#! /usr/bin/env bash
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-print_message() {
-
-    local messages
-    local message
-
-    ### STANDARD INSULTS ###
-    declare -a _array1=(
-        "(╯°□°)╯︵ ┻━┻"
-        "¯\_(ツ)_/¯"
-        "ACHTUNG! ALLES TURISTEN UND NONTEKNISCHEN LOOKENPEEPERS! DAS KOMPUTERMASCHINE IST NICHT FÜR DER GEFINGERPOKEN UND MITTENGRABEN! ODERWISE IST EASY TO SCHNAPPEN DER SPRINGENWERK, BLOWENFUSEN UND POPPENCORKEN MIT SPITZENSPARKEN. IST NICHT FÜR GEWERKEN BEI DUMMKOPFEN. DER RUBBERNECKEN SIGHTSEEREN KEEPEN DAS COTTONPICKEN HÄNDER IN DAS POCKETS MUSS. ZO RELAXEN UND WATSCHEN DER BLINKENLICHTEN."
-        "And the Darwin Award goes to.... ${USER}!"
-        "Allowing you to survive childbirth was medical malpractice."
-        "Are you always this stupid or are you making a special effort today?!"
-        "Are you even trying?!"
-        "Bad."
-        "Boooo!"
-        "Brains aren't everything. In your case they're nothing."
-        "Commands, random gibberish, who cares!"
-        "Come on! You can do it!"
-        "Don't you have anything better to do?!"
-        "Don't you know anything?"
-        "Dropped on your head as a baby, eh?"
-        "error code: 1D10T"
-        "Even your mom loves you only as a friend."
-        "ERROR_INCOMPETENT_USER"
-        "Fake it till you make it!"
-        "Go outside."
-        "Haha, n00b!"
-        "How many times do I have to flush before you go away?"
-        "I am _seriously_ considering 'rm -rf /'-ing myself..."
-        "I don't know what makes you so stupid, but it really works."
-        "I was going to give you a nasty look, but I see you already have one."
-        "If beauty fades then you have nothing to worry about."
-        "If brains were gasoline you wouldn’t have enough to propel a flea’s motorcycle around a doughnut."
-        "If ignorance is bliss, you must be the happiest person on earth."
-        "If shit was music, you'd be an orchestra."
-        "If what you don't know can't hurt you, you're invulnerable."
-        "Incompetence is also a form of competence"
-        "I’d slap you, but that’d be animal abuse."
-        "I’ve heard of being hit with the ugly stick, but you must have been beaten senseless with it."
-        "Keep trying, someday you'll do something intelligent!"
-        "Let’s play horse. I’ll be the front end. And you be yourself."
-        "Life is good, you should get one."
-        "lol"
-        "lol... plz"
-        "My keyboard is not a touch screen!"
-        "My uptime is longer than your relationships."
-        "Nice try."
-        "n00b alert!"
-        "Pathetic"
-        "Perhaps computers are not for you..."
-        "Perhaps you should leave the command line alone..."
-        "Please step away from the keyboard!"
-        "plz uninstall"
-        "Pro tip: type a valid command!"
-        "Rose are red. Violets are blue. I have five fingers. The middle one's for you."
-        "RTFM!"
-        "Sorry what? I don’t understand idiot language."
-        "The degree of your stupidity is enough to boil water."
-        "The worst one today!"
-        "This is not a search engine."
-        "This is not Windows"
-        "This is why nobody likes you."
-        "This is why you get to see your children only once a month."
-        "Try using your brain the next time!"
-        "Two wrongs don't make a right, take your parents as an example."
-        "Typing incorrect commands, eh?"
-        "u suk"
-        "What if... you type an actual command the next time!"
-        "What if I told you... it is possible to type valid commands."
-        "What is this...? Amateur hour!?"
-        "Why are you so stupid?!"
-        "Why are you doing this to me?!"
-        "Why did the chicken cross the road? To get the hell away from you."
-        "Wow! That was impressively wrong!"
-        "Y u no speak computer???"
-        "You are not as bad as people say, you are much, much worse."
-        "You are not useless since you can still be used as a bad example."
-        "You must have been born on a highway because that's where most accidents happen."
-        "Your application for reduced salary has been sent!"
-        "Your mom had a severe case of diarrhea when you were born."
-        "You're proof that god has a sense of humor."
-        "You’re so dumb your first words were DUH."
-        "You're so fat, people jog around you for exercise."
-        "You’re the reason Santa says ho, ho, ho, on Christmas!"
-    )
-    ### SHAKESPEARE INSULTS ###
-    declare -a array2=(
-        "A most notable coward, an infinite and endless liar, an hourly promise breaker, the owner of no one good quality."
-        "Away, you starvelling, you elf-skin, you dried neat's-tongue, bull's-pizzle, you stock-fish!"
-        "Away, you three-inch fool! "
-        "Come, come, you froward and unable worms!"
-        "Go, prick thy face, and over-red thy fear, Thou lily-liver’d boy."
-        "His wit's as thick as a Tewkesbury mustard."
-        "I am pigeon-liver'd and lack gall."
-        "I am sick when I do look on thee "
-        "I must tell you friendly in your ear, sell when you can, you are not for all markets."
-        "If thou wilt needs marry, marry a fool; for wise men know well enough what monsters you make of them."
-        "I'll beat thee, but I would infect my hands."
-        "I scorn you, scurvy companion. "
-        "Methink'st thou art a general offence and every man should beat thee."
-        "More of your conversation would infect my brain."
-        "My wife's a hobby horse!"
-        "Peace, ye fat guts!"
-        "Poisonous bunch-backed toad! "
-        "The rankest compound of villainous smell that ever offended nostril"
-        "The tartness of his face sours ripe grapes."
-        "There's no more faith in thee than in a stewed prune."
-        "Thine forward voice, now, is to speak well of thine friend; thine backward voice is to utter foul speeches and to detract."
-        "That trunk of humours, that bolting-hutch of beastliness, that swollen parcel of dropsies, that huge bombard of sack, that stuffed cloak-bag of guts, that roasted Manningtree ox with pudding in his belly, that reverend vice, that grey Iniquity, that father ruffian, that vanity in years?"
-        "Thine face is not worth sunburning."
-        "This woman's an easy glove, my lord, she goes off and on at pleasure."
-        "Thou art a boil, a plague sore."
-        "Was the Duke a flesh-monger, a fool and a coward?"
-        "Thou art as fat as butter."
-        "Here is the babe, as loathsome as a toad."
-        "Like the toad; ugly and venomous."
-        "Thou art unfit for any place but hell."
-        "Thou cream faced loon"
-        "Thou clay-brained guts, thou knotty-pated fool, thou whoreson obscene greasy tallow-catch!"
-        "Thou damned and luxurious mountain goat."
-        "Thou elvish-mark'd, abortive, rooting hog!"
-        "Thou leathern-jerkin, crystal-button, knot-pated, agatering, puke-stocking, caddis-garter, smooth-tongue, Spanish pouch!"
-        "Thou lump of foul deformity"
-        "That poisonous bunch-back'd toad!"
-        "Thou sodden-witted lord! Thou hast no more brain than I have in mine elbows "
-        "Thou subtle, perjur'd, false, disloyal man!"
-        "Thou whoreson zed , thou unnecessary letter!"
-        "Thy sin’s not accidental, but a trade."
-        "Thy tongue outvenoms all the worms of Nile."
-        "Would thou wert clean enough to spit upon"
-        "Would thou wouldst burst!"
-        "You poor, base, rascally, cheating lack-linen mate! "
-        "You are as a candle, the better burnt out."
-        "You scullion! You rampallian! You fustilarian! I’ll tickle your catastrophe!"
-        "You starvelling, you eel-skin, you dried neat's-tongue, you bull's-pizzle, you stock-fish-O for breath to utter what is like thee!-you tailor's-yard, you sheath, you bow-case, you vile standing tuck!"
-        "Your brain is as dry as the remainder biscuit after voyage."
-        "Virginity breeds mites, much like a cheese."
-        "Villain, I have done thy mother"
-    )
-    ### MARTIN LUTHER INSULTS ###
-    declare -a array3=(
-        "You live like simple cattle or irrational pigs and, despite the fact that the gospel has returned, have mastered the fine art of misusing all your freedom."
-        "You shameful gluttons and servants of your bellies are better suited to be swineherds and keepers of dogs."
-        "You deserve not only to be given no food to eat, but also to have the dogs set upon you and to be pelted with horse manure."
-        "Oh, what mad senseless fools you are!"
-        "For this you deserve to have God deprive you of his Word and blessing and once again allow preachers of lies to arise who lead you to the devil - and wring sweat and blood out of you besides."
-        "All your holiness is only stench and filth, and it merits nothing but wrath and damnation."
-        "May your grain spoil in the barn, your beer in the cellar, your cattle perish in the stall. Yes, your entire hoard ought to be consumed by rust so that you will never enjoy it."
-        "You relish and delight in the chance to stir up someone else's dirt like pigs that roll in manure and root around in it with their snouts."
-        "Your sin smells to high heaven."
-        "Your words are so foolishly and ignorantly composed that I cannot believe you understand them."
-        "You are the most insane heretics and ingrafters of heretical perversity."
-        "What you say is a blasphemy that has made you worthy of a thousand deaths."
-        "Behold, indeed, this little golden work of a golden teacher! It is a work most worthy of golden letters, and lest there be something about it which is not golden, it must be handed down by golden disciples, namely, by those about whom it is said, 'The idols of the nations are silver and gold. They have eyes, but they see not.'"
-        "You are worthy only to be mocked by the words of error."
-        "It is presumptuous for people who are as ignorant as you are not to take up the work of a herdsman."
-        "What bilgewater of heresies has ever been spoken so heretically as what you have said?"
-        "What do you mean when you say this? Are you dreaming in the throes of a fever or are you laboring under a madness?"
-        "Your astute minds have been completely turned into stinking mushrooms."
-        "You are the prostitute of heretics!"
-        "I am tired of the pestilent voice of your sirens."
-        "You are a bungling magpie, croaking loudly."
-        "You forgot to purge yourself with hellabore while you were preparing to fabricate this lie."
-        "You are more corrupt than any Babylon or Sodom ever was, and, as far as I can see, are characterized by a completely depraved, hopeless, and notorious godlessness."
-        "Your home, once the holiest of all, has become the most licentious den of thieves, the most shameless of all brothels, the kingdom of sin, death, and hell. It is so bad that even Antichrist himself, if he should come, could think of nothing to add to its wickedness."
-        "What devilish unchristian thing would you not undertake?"
-        "You are an extraordinary creature, being neither God nor man. Perhaps you are the devil himself."
-        "Even if the Antichrist appears, what greater evil can he do than what you have done and do daily?"
-        "It may be that you want to build yourself a heaven of your own, like those jugglers build themselves out of linen cloth at the Shrove Tuesday carnival. Is it not disgusting that we have to hear such foolish and childish things from you?"
-        "In our country, fruit grows on trees and from trees, and meditation upon sin grows from contrition. But in your land, trees may grow on fruits, contrition from sins, people walk on their ears, and everything is upside down."
-        "O you wolf in Christendom!"
-        "You know less than does a log on the ground."
-        "I think that all the devils have at once entered into you."
-        "You are worse than all the devils. What you have done, no devil has ever done. Your end is near, you son of perdition and Antichrist! Stop now, you are going to far!"
-        "You are the true, chief, and final Antichrist."
-        "How far will you go, O devilish pride?"
-        "All Christians should be on guard against your antichristian poison."
-        "I think you received these ideas in your pipe dreams."
-        "You are in all you do the very opposite of Christ as befits a true Antichrist."
-        "You are a person of sin and the child of perdition, leading all the world with you to the devil, using your lying and deceitful ways."
-        "You are not a pious fraud, but an infernal, diabolical, antichristian fraud."
-        "You are the Roman Nimrod and a teacher of sin."
-        "It is the old dragon from the abyss of hell who is standing before me!"
-        "You hold fast to human dreams and the doctrines of devils."
-        "If you who are assembled in a council are so frivolous and irresponsible as to waste time and money on unnecessary questions, when it is the business of a council to deal only with the important and necessary matters, we should not only refuse to obey you, but consider you insane or criminals."
-        "Even Lucifer was not guilty of so great a sacrilege in heaven, for he only presumed to be God's equal. God help us!"
-        "You condemned the holy gospel and replaced it with the teaching of the dragon from hell."
-        "Your words are un-Christian, antichristian, and spoken by the inspiration of the evil spirit."
-        "What happened to the house built on sand in Matthew 7 will also happen to you."
-        "Must we believe your nightmares?"
-        "Look how this great heretic speaks brazenly and sacrilegiously."
-        "You run against God with the horns of your pride up in the air and thus plunge into the abyss of hell. Woe unto you, Antichrist!"
-        "You are the devil's most dangerous tool!"
-        "It seems I must have liars and villains for opponents. I am not worthy in the sight of God that a godly and honorable person should discuss these matters with me in a Christian way. This is my greatest lament."
-        "May the Lord Jesus protect me and all devout souls from your contagion and your company!"
-        "This venom - the mere smell of which kills a man!"
-        "You are a Baal-zebub - that is, a man of flies."
-        "You are full of poisonous refuse and insane foolishness."
-        "You are ignorant, stupid, godless blasphemers."
-        "You moderate enforcer and eulogizer of moderation. You are one of those bloody and deceitful people who affect modesty in words and appearance, but who meanwhile breathe out threats and blood."
-        "We leave you to your own devices, for nothing properly suits you except hypocrisy, flattery, and lies."
-        "In lying fashion you ignore what even children know."
-        "The reward of such flattery is what your crass stupidity deserves. Therefore, we shall turn from you, a sevenfold stupid and blasphemous wise person."
-        "People of your sort are hirelings, dumb dogs unable to bark, who see the wolf coming and flee or, rather, join up with the wolf."
-        "You are a wolf and apostle of Satan."
-        "You are the ultimate scourges of the world, the Antichrist together with your sophists and bishops."
-        "You cowardly slave, you corrupt sycophant, with your sickening advice!"
-        "You are idiots and swine."
-        "Every letter of yours breathes Moabitish pride. So much can a single bull inflate a single bubble that you practically make distinguished asses into gods."
-        "You sophistic worms, grasshoppers, locusts, frogs and lice!"
-        'You completely close your mind and do nothing but shout, "Anathema, anathema, anathema!" so that by your own voice you are judged mad.'
-        "Let this generation of vipers prepare itself for unquenchable fire!"
-        "You rush forward as an ass under the pelt of a lion."
-        "In appearance and words you simulate modesty, but you are so swollen with haughtiness, arrogance, pride, malice, villainy, rashness, superciliousness, ignorance, and stupidity that there is nothing to surpass you."
-        "Blind moles!"
-        "We despise your whorish impudence."
-    )
-    ### EDIT THIS LINE IF YOU ONLY WANT TO USE CERTAIN INSULT LISTS ###
-    messages=(
-        # "${array1[@]}" ## normal ones
-        "${array2[@]}" ## Shakespeare
-        "${array3[@]}" ## Luther
-    )
-
-    # If CMD_NOT_FOUND_MSGS array is populated use those messages instead of the defaults
-    [[ -n ${CMD_NOT_FOUND_MSGS} ]] && messages=("${CMD_NOT_FOUND_MSGS[@]}")
-
-    # If CMD_NOT_FOUND_MSGS_APPEND array is populated append those to the existing messages
-    [[ -n ${CMD_NOT_FOUND_MSGS_APPEND} ]] && messages+=("${CMD_NOT_FOUND_MSGS_APPEND[@]}")
-
-    # Seed RANDOM with an integer of some length
-    RANDOM=$(od -vAn -N4 -tu </dev/urandom)
-
-    # Print a randomly selected message, but only about half the time to annoy the user a
-    # little bit less.
-    if [[ $((RANDOM % 2)) -lt 1 ]]; then
-        message=${messages[RANDOM % ${#messages[@]}]}
-        printf "\n  %s%s%s\n\n" "$(tput bold)$(tput setaf 1)" "$message" "$(tput sgr0)" >&2
-    fi
-}
-
-function_exists() {
-    # Zsh returns 0 even on non existing functions with -F so use -f
-    declare -f "$1" >/dev/null
-    return $?
-}
-
-#
-# The idea below is to copy any existing handlers to another function
-# name and insert the message in front of the old handler in the
-# new handler. By default, neither bash or zsh has has a handler function
-# defined, so the default behaviour is replicated.
-#
-# Also, ensure the handler is only copied once. If we do not ensure this
-# the handler would add itself recursively if this file happens to be
-# sourced multiple times in the same shell, resulting in a neverending
-# stream of messages.
-#
-
-#
-# Zsh
-#
-if function_exists command_not_found_handler; then
-    if ! function_exists orig_command_not_found_handler; then
-        eval "orig_$(declare -f command_not_found_handler)"
-    fi
-else
-    orig_command_not_found_handler() {
-        printf "zsh: command not found: %s\n" "$1" >&2
-        return 127
-    }
-fi
-
-command_not_found_handler() {
-    print_message
-    orig_command_not_found_handler "$@"
-}
-
-#
-# Bash
-#
-if function_exists command_not_found_handle; then
-    if ! function_exists orig_command_not_found_handle; then
-        eval "orig_$(declare -f command_not_found_handle)"
-    fi
-else
-    orig_command_not_found_handle() {
-        printf "%s: %s: command not found\n" "$0" "$1" >&2
-        return 127
-    }
-fi
-
-command_not_found_handle() {
-    print_message
-    orig_command_not_found_handle "$@"
-}
diff --git a/modules/by-name/zs/zsh/module.nix b/modules/by-name/zs/zsh/module.nix
index fdd9edaf..fee2eae3 100644
--- a/modules/by-name/zs/zsh/module.nix
+++ b/modules/by-name/zs/zsh/module.nix
@@ -10,14 +10,11 @@
 {
   config,
   lib,
-  shell_library,
-  system,
-  pkgs,
   ...
 }: let
   cfg = config.soispha.programs.zsh;
 
-  zDotDir = ".config/zsh";
+  zDotDir = "${config.home-manager.users.soispha.xdg.configHome}/zsh";
 
   sourceFile = path: "source ${path}\n";
 
@@ -46,7 +43,7 @@ in {
 
   config = lib.mkIf cfg.enable {
     environment.variables = {
-      ZDOTDIR = "${config.home-manager.users.soispha.home.homeDirectory}/${zDotDir}";
+      ZDOTDIR = zDotDir;
     };
 
     home-manager.users.soispha = {
@@ -67,8 +64,6 @@ in {
 
         autocd = true;
 
-        # Must be relative to the users home directory (for whatever reason)
-        # Thus no `${homeConfig.xdg.configHome}`
         dotDir = zDotDir;
 
         # TODO: Remove the whole history and replace it completely with `atuin` <2024-10-21>
@@ -106,10 +101,7 @@ in {
 
         initContent = let
           start = lib.modules.mkBefore (
-            # NOTE: This must be before the insult, as we otherwise override the previous handler <2024-02-28>
             sourceFile ./config/zsh-init.zsh
-            + sourceFile ./config/command_not_found/command_not_found.sh
-            + sourceFile ./config/command_not_found/command_not_found_insult.sh
             + sourceFile ./config/custom_cursor.zsh
             + sourceFile ./config/edit_command_line.zsh
             + sourceFile ./plugins/zsh-history-substring-search.zsh
@@ -124,9 +116,6 @@ in {
             + sourceFile ./config/keymaps/viopp.zsh
             + sourceFile ./config/keymaps/visual.zsh
             + sourceFile ./config/keymaps_end.zsh
-            + ''
-              SHELL_LIBRARY_VERSION="2.1.2" source ${shell_library.rawLib.${system}}
-            ''
           );
         in
           lib.modules.mkMerge
@@ -142,11 +131,6 @@ in {
           HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_FOUND = "bg=cyan,fg=white";
           HISTORY_SUBSTRING_SEARCH_HIGHLIGHT_NOT_FOUND = "fg=red,underline,standout,bold";
         };
-
-        shellAliases = {
-          ll = ". ${lib.getExe pkgs.ll}";
-          lm = ". ${lib.getExe pkgs.lm}";
-        };
       };
     };
   };
diff --git a/modules/common/default.nix b/modules/common/default.nix
index 74198b43..f9831351 100644
--- a/modules/common/default.nix
+++ b/modules/common/default.nix
@@ -13,9 +13,21 @@
   config,
   pkgs,
   lib,
+  # Needed for nixos-shell
+  libraries,
+  modules,
+  openPRsNixpkgs,
+  packageSets,
+  system,
+  self,
+  externalDependencies,
+  externalBinaries,
   ...
 }: {
+  # TODO(@bpeetz): Move this file to default options in their respective modules. <2025-05-31>
+
   soispha = {
+    age.enable = true;
     boot.enable = true;
     cleanup.enable = true;
     documentation.enable = true;
@@ -25,17 +37,60 @@
       enableEmoji = true;
     };
 
+    hardware = {
+      enable = lib.mkDefault true;
+    };
     home-manager.enable = true;
     impermanence = {
       enable = true;
 
       directories = [
         "/etc/nixos"
-        "/var/log"
         "/var/lib/systemd"
-        "/var/lib/nixos"
       ];
     };
+
+    nixos-shell = {
+      enable = lib.mkDefault true;
+      configuration = {
+        specialArgs = {
+          inherit
+            libraries
+            modules
+            ;
+        };
+        value = lib.mkMerge [
+          {
+            _module.args = {
+              inherit
+                # extra package sources
+                openPRsNixpkgs
+                packageSets
+                # extra information
+                system
+                # nix registry
+                self
+                externalDependencies
+                # bins
+                # TODO: Integrate these into `pkgs/by-name` <2024-05-22>
+                externalBinaries
+                ;
+            };
+          }
+
+          {
+            require = [
+              ./nixos_shell_configuration.nix
+
+              ../../modules
+              ../../modules/common
+            ];
+          }
+        ];
+      };
+      mounts = {};
+    };
+
     polkit.enable = true;
     power.enable = true;
     xdg.enable = true;
@@ -46,12 +101,16 @@
         user = "soispha";
       };
       backup = {
-        enable = true;
-        user = "u459143-sub1";
-        privateSshKey = ./secrets/backup/privateSshKey.age;
-        privatePassword = ./secrets/backup/privatePassword.age;
+        storagebox = {
+          enable = lib.mkDefault true;
+          user = "u459143-sub1";
+        };
+        local = {
+          enable = lib.mkDefault true;
+        };
       };
       fwupd.enable = true;
+      mako.enable = true;
       mpd = {
         enable = true;
         directories = let
@@ -75,7 +134,7 @@
       water-reminder.enable = true;
       systemDiff.enable = true;
       unison = {
-        enable = true;
+        enable = lib.mkDefault true;
 
         foreign.userName = "soispha";
         dataDir = "${config.home-manager.users.soispha.xdg.dataHome}/unison";
@@ -88,16 +147,20 @@
               config.home-manager.users.soispha.home.file);
         in
           [
+            # TODO(@bpeetz): Move these to their respective modules <2025-05-09>
             # Already synchronized by TaskChampion sync server
             "~/.local/share/task"
             # Already synchronized by atuin sync server
             "~/.local/share/atuin"
+            # Already synchronized by mbsync
+            "~/.local/share/maildir"
 
             # Should not be synchronized
             "~/.local/share/unison"
 
             # These are just to big to be synchronized (# TODO: Work around that <2024-08-31> )
-            "~/media/music"
+            "~/media/music/beets.old"
+            "~/media/music/deerix"
             "~/.local/share/Steam"
           ]
           ++ homeManagerSymlinks;
@@ -108,21 +171,29 @@
           "~/.local/share"
           "~/.local/.Trash-1000"
 
-          "~/.mozilla/firefox"
-
           "~/media"
-          "~/school"
+          "~/documents"
           "~/repos"
         ];
       };
     };
 
     programs = {
+      i3bar-river.enable = true;
+      i3status-rust.enable = true;
+
+      qutebrowser = {
+        enable = true;
+      };
+
       nvim = {
         enable = true;
         shell = pkgs.zsh;
       };
-      atuin.enable = true;
+      atuin = {
+        enable = true;
+        enableAge = lib.mkDefault true;
+      };
       cargo.enable = true;
       direnv.enable = true;
       git.enable = true;
@@ -131,7 +202,7 @@
       lf.enable = true;
       gpg.enable = true;
       river = {
-        enable = true;
+        enable = lib.mkDefault true;
         init = {
           rules = [
             {
@@ -165,12 +236,12 @@
               title = "*";
               action = "ssd";
             }
-            # This remove the focus border around Firefox (which is useful because the Firefox is nearly always in its own tag.)
-            {
-              app-id = "firefox";
-              title = "*";
-              action = "csd";
-            }
+            # # This remove the focus border around Firefox (which is useful because the Firefox is nearly always in its own tag.)
+            # {
+            #   app-id = "firefox";
+            #   title = "*";
+            #   action = "csd";
+            # }
           ];
           generalSettings = {
             # background
@@ -193,37 +264,35 @@
             pointer-12951-6505-ZSA_Technology_Labs_Moonlander_Mark_I = [["pointer-accel" "0"] ["accel-profile" "none"]];
           };
           backgroundStart = [
-            pkgs.gammastep
-            pkgs.yambar
+            # TODO(@bpeetz): Move these to systemd units/their own modules <2025-05-18>
 
-            pkgs.mako
             ["${lib.getExe pkgs.swaybg}" "--image" "${./abstract-nord.png}"]
             pkgs.swayidle
             pkgs.alacritty
           ];
         };
       };
-      firefox.enable = true;
       mpv.enable = true;
-      steam.enable = true;
+      steam.enable = false;
       ssh.enable = true;
       swaylock.enable = true;
       timewarrior.enable = true;
       taskwarrior = {
         enable = true;
+        enableAge = lib.mkDefault true;
+
         hooks = import ./hooks {inherit pkgs lib config;};
       };
       tskm = {
         enable = true;
         projects = builtins.fromJSON (builtins.readFile ./projects.json);
       };
-      yambar.enable = true;
+      nix-index.enable = true;
       yt.enable = true;
       zathura.enable = true;
       zsh.enable = true;
     };
 
-    sound.enable = true;
     version.enable = true;
   };
 }
diff --git a/modules/common/nixos_shell_configuration.nix b/modules/common/nixos_shell_configuration.nix
new file mode 100644
index 00000000..1bec0145
--- /dev/null
+++ b/modules/common/nixos_shell_configuration.nix
@@ -0,0 +1,66 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{...}: {
+  soispha = {
+    networking = {
+      enable = true;
+      hostName = "lahmu";
+      mode = "systemd-networkd";
+    };
+
+    nixos-shell.enable = false;
+
+    nixpkgs = {
+      enable = true;
+      systemName = "x86_64-linux";
+    };
+
+    services = {
+      unison.enable = false;
+      backup = {
+        storagebox.enable = false;
+        local.enable = false;
+      };
+    };
+
+    programs = {
+      river.enable = false;
+
+      # We don't have access to the age secrets.
+      atuin.enableAge = false;
+      taskwarrior.enableAge = false;
+    };
+
+    locale = {
+      enable = true;
+      keyMap = "us";
+    };
+
+    users = {
+      enable = true;
+      enableDeprecatedPlugdev = true;
+
+      # Make logging in impossible.
+      # (This also removes root a obvious access-point from the virtual machine)
+      hashedPassword = "";
+    };
+  };
+
+  soispha = {
+    hardware = {
+      enable = false;
+    };
+
+    disks.enable = false;
+  };
+
+  # We run without state
+  # system.stateVersion = null;
+}
diff --git a/modules/common/projects.json b/modules/common/projects.json
index 48a10f03..e8e9bc39 100644
--- a/modules/common/projects.json
+++ b/modules/common/projects.json
@@ -1,7 +1,4 @@
 {
-  "3d-printer": {
-    "prefix": "hardware"
-  },
   "aoc": {
     "prefix": "programming/advent_of_code"
   },
@@ -15,19 +12,7 @@
       "pc": {}
     }
   },
-  "camera": {
-    "prefix": "programming/zig"
-  },
-  "hardware": {
-    "prefix": "research"
-  },
-  "input": {
-    "prefix": "research",
-    "subprojects": {
-      "dotfiles": {},
-      "read-things": {}
-    }
-  },
+  "esc": {},
   "latex": {
     "prefix": "programming/latex"
   },
@@ -36,45 +21,10 @@
       "bank": {},
       "google": {},
       "health": {},
+      "job": {},
       "sweden": {}
     }
   },
-  "possible-projects": {
-    "prefix": "research"
-  },
-  "presentation": {
-    "prefix": "research"
-  },
-  "school": {
-    "prefix": "research",
-    "subprojects": {
-      "biologie": {},
-      "chemie": {
-        "subprojects": {
-          "facharbeit": {}
-        }
-      },
-      "deutsch": {},
-      "english": {},
-      "extern": {
-        "subprojects": {
-          "bwinf": {},
-          "dsa": {}
-        }
-      },
-      "geographie": {},
-      "geschichte": {},
-      "infomatik": {},
-      "klausuren": {},
-      "latein": {},
-      "mathematik": {},
-      "musik": {},
-      "philosophie": {},
-      "physik": {},
-      "sozialkunde": {},
-      "sport": {}
-    }
-  },
   "server": {
     "prefix": "config",
     "subprojects": {
@@ -86,15 +36,8 @@
       "sudo-less": {}
     }
   },
-  "serverphone": {
-    "prefix": "programming/rust"
-  },
   "smartphone": {
-    "prefix": "hardware",
-    "subprojects": {
-      "airdrop": {},
-      "airplay": {}
-    }
+    "prefix": "hardware"
   },
   "system": {
     "prefix": "config",
@@ -106,6 +49,7 @@
       "gpg": {},
       "keyboard": {},
       "laptop": {},
+      "music": {},
       "nvim": {},
       "rss": {},
       "shell": {},
@@ -121,12 +65,5 @@
       "netflix": {},
       "youtube": {}
     }
-  },
-  "trinitrix": {
-    "prefix": "programming/rust",
-    "subprojects": {
-      "documentation": {},
-      "testing": {}
-    }
   }
 }
diff --git a/modules/default.nix b/modules/default.nix
index 541a3663..f83cf683 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -9,13 +9,12 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 # NOTE: This file **must** not depend on `pkgs`. This is because `pkgs` is defined in a
 # module imported by it, and thus would require infinite recursion.  <2024-10-18>
-{nixLib, ...}: let
+{libraries, ...}: let
   files =
     builtins.attrValues
-    (nixLib.mkByName {
+    (libraries.extra.mkByName {
       baseDirectory = ./by-name;
       fileName = "module.nix";
-      finalizeFunction = name: value: value;
     });
 in {
   imports = files;
diff --git a/modules/home.legacy/conf/alacritty/default.nix b/modules/home.legacy/conf/alacritty/default.nix
deleted file mode 100644
index 493c4114..00000000
--- a/modules/home.legacy/conf/alacritty/default.nix
+++ /dev/null
@@ -1,39 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{lib, ...}: let
-  config_file = ''
-    ${lib.strings.fileContents ./toml/general.toml}
-    ${lib.strings.fileContents ./toml/bell.toml}
-    ${lib.strings.fileContents ./toml/colorscheme.toml}
-    ${lib.strings.fileContents ./toml/cursor.toml}
-    ${lib.strings.fileContents ./toml/env.toml}
-    ${lib.strings.fileContents ./toml/font.toml}
-    ${lib.strings.fileContents ./toml/hints.toml}
-    ${lib.strings.fileContents ./toml/keyboard_bindings.toml}
-    ${lib.strings.fileContents ./toml/mouse.toml}
-    ${lib.strings.fileContents ./toml/mouse_bindings.toml}
-    ${lib.strings.fileContents ./toml/scrolling.toml}
-    ${lib.strings.fileContents ./toml/selection.toml}
-    ${lib.strings.fileContents ./toml/window.toml}
-  '';
-in {
-  home.sessionVariables = {
-    # This is **not** the TERM variable but a special one to signify my favorite terminal.
-    TERMINAL = "alacritty";
-
-    # These two here should be set by alacritty at start-up
-    # TERM = "alacritty";
-    # COLORTERM = "truecolor";
-  };
-  programs.alacritty = {
-    enable = true;
-  };
-  xdg.configFile."alacritty/alacritty.toml".text = config_file;
-}
diff --git a/modules/home.legacy/conf/alacritty/toml/bell.toml b/modules/home.legacy/conf/alacritty/toml/bell.toml
deleted file mode 100644
index 821306cc..00000000
--- a/modules/home.legacy/conf/alacritty/toml/bell.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Bell
-#
-# The bell is rung every time the BEL control character is received.
-[bell]
-# Duration of the visual bell flash in milliseconds. A `duration` of `0` will
-# disable the visual bell animation.
-duration = 0
diff --git a/modules/home.legacy/conf/alacritty/toml/env.toml b/modules/home.legacy/conf/alacritty/toml/env.toml
deleted file mode 100644
index 307f1f1d..00000000
--- a/modules/home.legacy/conf/alacritty/toml/env.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[env]
-TERM = "alacritty"
-COLORTERM = "truecolor"
diff --git a/modules/home.legacy/conf/alacritty/toml/font.toml b/modules/home.legacy/conf/alacritty/toml/font.toml
deleted file mode 100644
index fd8b0b94..00000000
--- a/modules/home.legacy/conf/alacritty/toml/font.toml
+++ /dev/null
@@ -1,25 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[font]
-builtin_box_drawing = true
-size = 12.0
-
-[font.glyph_offset]
-x = -1
-y = -1
-
-[font.normal]
-family = "SauceCodePro Nerd Font Mono"
-style = "Regular"
-
-[font.offset]
-x = -1
-y = -1
diff --git a/modules/home.legacy/conf/alacritty/toml/general.toml b/modules/home.legacy/conf/alacritty/toml/general.toml
deleted file mode 100644
index 588d8ea0..00000000
--- a/modules/home.legacy/conf/alacritty/toml/general.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Configuration for Alacritty, the GPU enhanced terminal emulator.
-
-[general]
-# Live config reload (changes require restart)
-live_config_reload = true
-
-# Startup directory
-#
-# Directory the shell is started in. If this is unset, or `None`, the working
-# directory of the parent process will be used.
-#working_directory: None
-
-# Offer IPC using `alacritty msg` (unix only)
-ipc_socket = true
diff --git a/modules/home.legacy/conf/alacritty/toml/hints.toml b/modules/home.legacy/conf/alacritty/toml/hints.toml
deleted file mode 100644
index da18dc59..00000000
--- a/modules/home.legacy/conf/alacritty/toml/hints.toml
+++ /dev/null
@@ -1,35 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[hints]
-alphabet = "jfkdls;ahgurieowpq"
-
-[[hints.enabled]]
-command = "xdg-open"                                                                                                                                      # On Linux/BSD
-hyperlinks = true
-post_processing = true
-persist = false
-mouse.enabled = true
-binding = { key = "U", mods = "Control|Shift" }
-regex = "(ipfs:|ipns:|magnet:|mailto:|gemini://|gopher://|https://|http://|news:|file:|git://|ssh:|ftp://)[^\u0000-\u001F\u007F-\u009F<>\"\\s{-}\\^⟨⟩`]+"
-
-
-[[hints.enabled]]
-action = "Paste"
-post_processing = false
-binding = { key = "T", mods = "Control|Shift" }
-regex = '''([^ '"`=:\[\(]*/)([^/: '"`\)\]]*)'''
-
-
-[[hints.enabled]]
-action = "Paste"
-post_processing = false
-binding = { key = "H", mods = "Control|Shift" }
-regex = '([a-z0-9]{7,40})\s'
diff --git a/modules/home.legacy/conf/alacritty/toml/keyboard_bindings.toml b/modules/home.legacy/conf/alacritty/toml/keyboard_bindings.toml
deleted file mode 100644
index f2a6eb55..00000000
--- a/modules/home.legacy/conf/alacritty/toml/keyboard_bindings.toml
+++ /dev/null
@@ -1,307 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[[keyboard.bindings]]
-action = "Paste"
-key = "P"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "Paste"
-key = "Insert"
-mods = "Shift"
-
-[[keyboard.bindings]]
-chars = "gc"
-key = "Slash"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "Copy"
-key = "Y"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ResetFontSize"
-key = "Key0"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "IncreaseFontSize"
-key = "Equals"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "IncreaseFontSize"
-key = "Plus"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "DecreaseFontSize"
-key = "Minus"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ToggleViMode"
-key = "Space"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ScrollToBottom"
-key = "Space"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ScrollToBottom"
-key = "I"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "ToggleViMode"
-key = "I"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "ScrollToBottom"
-key = "C"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ToggleViMode"
-key = "C"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ClearSelection"
-key = "Escape"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "ScrollLineUp"
-key = "Y"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ScrollLineDown"
-key = "E"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ScrollToTop"
-key = "G"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "ScrollToBottom"
-key = "G"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "ScrollPageUp"
-key = "B"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ScrollPageDown"
-key = "F"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ScrollHalfPageUp"
-key = "U"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ScrollHalfPageDown"
-key = "D"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "Copy"
-key = "Y"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "ClearSelection"
-key = "Y"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "ToggleNormalSelection"
-key = "V"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "ToggleLineSelection"
-key = "V"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "ToggleBlockSelection"
-key = "V"
-mode = "Vi"
-mods = "Control"
-
-[[keyboard.bindings]]
-action = "ToggleSemanticSelection"
-key = "V"
-mode = "Vi"
-mods = "Alt"
-
-[[keyboard.bindings]]
-action = "Open"
-key = "Return"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Up"
-key = "K"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Down"
-key = "J"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Left"
-key = "H"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Right"
-key = "L"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Up"
-key = "Up"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Down"
-key = "Down"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Left"
-key = "Left"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Right"
-key = "Right"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "First"
-key = "Key0"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "Last"
-key = "Key4"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "FirstOccupied"
-key = "Key6"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "High"
-key = "H"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "Middle"
-key = "M"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "Low"
-key = "L"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "SemanticLeft"
-key = "B"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "SemanticRight"
-key = "W"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "SemanticRightEnd"
-key = "E"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "WordLeft"
-key = "B"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "WordRight"
-key = "W"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "WordRightEnd"
-key = "E"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "Bracket"
-key = "Key5"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "SearchForward"
-key = "Slash"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "SearchBackward"
-key = "Slash"
-mode = "Vi"
-mods = "Shift"
-
-[[keyboard.bindings]]
-action = "SearchNext"
-key = "N"
-mode = "Vi"
-
-[[keyboard.bindings]]
-action = "SearchPrevious"
-key = "N"
-mode = "Vi"
-mods = "Shift"
diff --git a/modules/home.legacy/conf/alacritty/toml/mouse.toml b/modules/home.legacy/conf/alacritty/toml/mouse.toml
deleted file mode 100644
index cbc9cd32..00000000
--- a/modules/home.legacy/conf/alacritty/toml/mouse.toml
+++ /dev/null
@@ -1,12 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[mouse]
-hide_when_typing = false
diff --git a/modules/home.legacy/conf/alacritty/toml/mouse_bindings.toml b/modules/home.legacy/conf/alacritty/toml/mouse_bindings.toml
deleted file mode 100644
index e566a452..00000000
--- a/modules/home.legacy/conf/alacritty/toml/mouse_bindings.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[[mouse.bindings]]
-action = "Copy"
-mouse = "Middle"
diff --git a/modules/home.legacy/conf/alacritty/toml/scrolling.toml b/modules/home.legacy/conf/alacritty/toml/scrolling.toml
deleted file mode 100644
index 09240872..00000000
--- a/modules/home.legacy/conf/alacritty/toml/scrolling.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[scrolling]
-history = 10000
-multiplier = 3
diff --git a/modules/home.legacy/conf/alacritty/toml/selection.toml b/modules/home.legacy/conf/alacritty/toml/selection.toml
deleted file mode 100644
index ebc8c849..00000000
--- a/modules/home.legacy/conf/alacritty/toml/selection.toml
+++ /dev/null
@@ -1,13 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[selection]
-save_to_clipboard = false
-semantic_escape_chars = ",│`|:\"' ()[]{}<>\t"
diff --git a/modules/home.legacy/conf/alacritty/toml/window.toml b/modules/home.legacy/conf/alacritty/toml/window.toml
deleted file mode 100644
index edc9cf6e..00000000
--- a/modules/home.legacy/conf/alacritty/toml/window.toml
+++ /dev/null
@@ -1,28 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[window]
-decorations = "none"
-decorations_theme_variant = "None"
-dynamic_title = true
-opacity = 0.9
-startup_mode = "Windowed"
-title = "Alacritty"
-[window.class]
-general = "Alacritty"
-instance = "Alacritty"
-
-[window.dimensions]
-columns = 0
-lines = 0
-
-[window.padding]
-x = 5
-y = 5
diff --git a/modules/home.legacy/conf/alacritty/yaml/base.yml b/modules/home.legacy/conf/alacritty/yaml/base.yml
deleted file mode 100644
index 637d0d2e..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/base.yml
+++ /dev/null
@@ -1,27 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
----
-# Configuration for Alacritty, the GPU enhanced terminal emulator.
-
-# If `true`, bold text is drawn using the bright color variants.
-#draw_bold_text_with_bright_colors: true # TODO:
-
-# Live config reload (changes require restart)
-live_config_reload: true
-
-# Startup directory
-#
-# Directory the shell is started in. If this is unset, or `None`, the working
-# directory of the parent process will be used.
-#working_directory: None
-
-# Offer IPC using `alacritty msg` (unix only)
-ipc_socket: true
diff --git a/modules/home.legacy/conf/alacritty/yaml/bell.yml b/modules/home.legacy/conf/alacritty/yaml/bell.yml
deleted file mode 100644
index 4331a121..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/bell.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Bell
-#
-# The bell is rung every time the BEL control character is received.
-bell:
-  # Visual Bell Animation
-  #
-  # Animation effect for flashing the screen when the visual bell is rung.
-  #
-  # Values for `animation`:
-  #   - Ease
-  #   - EaseOut
-  #   - EaseOutSine
-  #   - EaseOutQuad
-  #   - EaseOutCubic
-  #   - EaseOutQuart
-  #   - EaseOutQuint
-  #   - EaseOutExpo
-  #   - EaseOutCirc
-  #   - Linear
-  #animation: EaseOutExpo
-
-  # Duration of the visual bell flash in milliseconds. A `duration` of `0` will
-  # disable the visual bell animation.
-  duration: 0
-
-  # Visual bell animation color.
-  #color: '#ffffff'
-
-  # Bell Command
-  #
-  # This program is executed whenever the bell is rung.
-  #
-  # When set to `command: None`, no command will be executed.
-  #
-  # Example:
-  #   command:
-  #     program: notify-send
-  #     args: ["Hello, World!"]
-  #
-  # command:
-  #   program: notify-send
-  #   args: ["The bell in alacritty was rung!"]
diff --git a/modules/home.legacy/conf/alacritty/yaml/colors.yml b/modules/home.legacy/conf/alacritty/yaml/colors.yml
deleted file mode 100644
index 05d2e0e6..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/colors.yml
+++ /dev/null
@@ -1,157 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Colors (Tomorrow Night)
-colors:
-  # Default colors
-  primary:
-    background: '#191919'
-    foreground: '#d8dee9'
-
-    # Bright and dim foreground colors
-    #
-    # The dimmed foreground color is calculated automatically if it is not
-    # present. If the bright foreground color is not set, or
-    # `draw_bold_text_with_bright_colors` is `false`, the normal foreground
-    # color will be used.
-    #dim_foreground: '#828482'
-    #bright_foreground: '#eaeaea'
-
-  # Cursor colors
-  #
-  # Colors which should be used to draw the terminal cursor.
-  #
-  # Allowed values are CellForeground/CellBackground, which reference the
-  # affected cell, or hexadecimal colors like #ff00ff.
-  cursor:
-    text: '#191919'
-    cursor: '#d8dee9'
-
-  # Vi mode cursor colors
-  #
-  # Colors for the cursor when the vi mode is active.
-  #
-  # Allowed values are CellForeground/CellBackground, which reference the
-  # affected cell, or hexadecimal colors like #ff00ff.
-  vi_mode_cursor:
-    text: CellBackground
-    cursor: CellForeground
-
-  # Search colors
-  #
-  # Colors used for the search bar and match highlighting.
-  search:
-    # Allowed values are CellForeground/CellBackground, which reference the
-    # affected cell, or hexadecimal colors like #ff00ff.
-    matches:
-      foreground: '#000000'
-      background: '#ffffff'
-    focused_match:
-      foreground: '#ffffff'
-      background: '#000000'
-
-  # Keyboard hints
-  hints:
-    # First character in the hint label
-    #
-    # Allowed values are CellForeground/CellBackground, which reference the
-    # affected cell, or hexadecimal colors like #ff00ff.
-    start:
-      foreground: '#1d1f21'
-      background: '#e9ff5e'
-
-    # All characters after the first one in the hint label
-    #
-    # Allowed values are CellForeground/CellBackground, which reference the
-    # affected cell, or hexadecimal colors like #ff00ff.
-    end:
-      foreground: '#e9ff5e'
-      background: '#1d1f21'
-
-  # Line indicator
-  #
-  # Color used for the indicator displaying the position in history during
-  # search and vi mode.
-  #
-  # By default, these will use the opposing primary color.
-  #line_indicator:
-  #  foreground: None
-  #  background: None
-
-  # Footer bar
-  #
-  # Color used for the footer bar on the bottom, used by search regex input,
-  # hyperlink URI preview, etc.
-  #
-  footer_bar:
-    background: '#c5c8c6'
-    foreground: '#1d1f21'
-
-  # Selection colors
-  #
-  # Colors which should be used to draw the selection area.
-  #
-  # Allowed values are CellForeground/CellBackground, which reference the
-  # affected cell, or hexadecimal colors like #ff00ff.
-  selection:
-    text: '#191919'
-    background: '#d8dee9'
-
-  # Normal colors
-  normal:
-    black: '#191919'
-    red: '#b02626'
-    green: '#40a62f'
-    yellow: '#f2e635'
-    blue: '#314ad0'
-    magenta: '#b30ad0'
-    cyan: '#32d0fc'
-    white: '#acadb1'
-
-  # Bright colors
-  bright:
-    black: '#36393d'
-    red: '#ce2727'
-    green: '#47c930'
-    yellow: '#fff138'
-    blue: '#2e4bea'
-    magenta: '#cc15ed'
-    cyan: '#54d9ff'
-    white: '#dbdbdb'
-
-  # Dim colors
-  #
-  # If the dim colors are not set, they will be calculated automatically based
-  # on the `normal` colors.
-  dim:
-    black: '#676f78'
-    red: '#b55454'
-    green: '#78a670'
-    yellow: '#faf380'
-    blue: '#707fd0'
-    magenta: '#c583d0'
-    cyan: '#8adaf1'
-    white: '#e0e3e7'
-  # Indexed Colors
-  #
-  # The indexed colors include all colors from 16 to 256.
-  # When these are not set, they're filled with sensible defaults.
-  #
-  # Example:
-  #   `- { index: 16, color: '#ff00ff' }`
-  #
-  #indexed_colors: []
-
-  # Transparent cell backgrounds
-  #
-  # Whether or not `window.opacity` applies to all cell backgrounds or only to
-  # the default background. When set to `true` all cells will be transparent
-  # regardless of their background color.
-  #transparent_background_colors: false # TODO:
diff --git a/modules/home.legacy/conf/alacritty/yaml/colorscheme.yml b/modules/home.legacy/conf/alacritty/yaml/colorscheme.yml
deleted file mode 100644
index 0b07fe80..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/colorscheme.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Nightfox Alacritty Colors
-# Style: carbonfox
-# Upstream: https://github.com/edeneast/nightfox.nvim/raw/main/extra/carbonfox/nightfox_alacritty.yml
-colors:
-  # Default colors
-  primary:
-    background: '0x161616'
-    foreground: '0xf2f4f8'
-  # Normal colors
-  normal:
-    black:   '0x282828'
-    red:     '0xee5396'
-    green:   '0x25be6a'
-    yellow:  '0x08bdba'
-    blue:    '0x78a9ff'
-    magenta: '0xbe95ff'
-    cyan:    '0x33b1ff'
-    white:   '0xdfdfe0'
-  # Bright colors
-  bright:
-    black:   '0x484848'
-    red:     '0xf16da6'
-    green:   '0x46c880'
-    yellow:  '0x2dc7c4'
-    blue:    '0x8cb6ff'
-    magenta: '0xc8a5ff'
-    cyan:    '0x52bdff'
-    white:   '0xe4e4e5'
-  indexed_colors:
-    - { index: 16, color: '0x3ddbd9' }
-    - { index: 17, color: '0xff7eb6' }
diff --git a/modules/home.legacy/conf/alacritty/yaml/cursor.yml b/modules/home.legacy/conf/alacritty/yaml/cursor.yml
deleted file mode 100644
index 5a3946f2..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/cursor.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-cursor:
-  # Cursor style
-  style:
-    # Cursor shape
-    #
-    # Values for `shape`:
-    #   - ▇ Block
-    #   - _ Underline
-    #   - | Beam
-    shape: Beam
-
-    # Cursor blinking state
-    #
-    # Values for `blinking`:
-    #   - Never: Prevent the cursor from ever blinking
-    #   - Off: Disable blinking by default
-    #   - On: Enable blinking by default
-    #   - Always: Force the cursor to always blink
-    blinking: On
-
-  # Vi mode cursor style
-  #
-  # If the vi mode cursor style is `None` or not specified, it will fall back to
-  # the style of the active value of the normal cursor.
-  #
-  # See `cursor.style` for available options.
-  vi_mode_style: None
-
-  # Cursor blinking interval in milliseconds.
-  blink_interval: 750
-
-  # Time after which cursor stops blinking, in seconds.
-  #
-  # Specifying '0' will disable timeout for blinking.
-  blink_timeout: 5
-
-  # If this is `true`, the cursor will be rendered as a hollow box when the
-  # window is not focused.
-  unfocused_hollow: true
-
-  # Thickness of the cursor relative to the cell width as floating point number
-  # from `0.0` to `1.0`.
-  thickness: 0.15
diff --git a/modules/home.legacy/conf/alacritty/yaml/debug.yml b/modules/home.legacy/conf/alacritty/yaml/debug.yml
deleted file mode 100644
index e876d801..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/debug.yml
+++ /dev/null
@@ -1,39 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-#debug:
-  # Display the time it takes to redraw each frame.
-  #render_timer: false
-
-  # Keep the log file after quitting Alacritty.
-  #persistent_logging: false
-
-  # Log level
-  #
-  # Values for `log_level`:
-  #   - Off
-  #   - Error
-  #   - Warn
-  #   - Info
-  #   - Debug
-  #   - Trace
-  #log_level: Warn
-
-  # Renderer override.
-  #   - glsl3
-  #   - gles2
-  #   - gles2_pure
-  #renderer: None
-
-  # Print all received window events.
-  #print_events: false
-
-  # Highlight window damage information.
-  #highlight_damage: false
diff --git a/modules/home.legacy/conf/alacritty/yaml/env.yml b/modules/home.legacy/conf/alacritty/yaml/env.yml
deleted file mode 100644
index 585416a1..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/env.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Any items in the `env` entry below will be added as
-# environment variables. Some entries may override variables
-# set by alacritty itself.
-env:
-  # TERM variable
-  #
-  # This value is used to set the `$TERM` environment variable for
-  # each instance of Alacritty. If it is not present, alacritty will
-  # check the local terminfo database and use `alacritty` if it is
-  # available, otherwise `xterm-256color` is used.
-  TERM: alacritty
diff --git a/modules/home.legacy/conf/alacritty/yaml/font.yml b/modules/home.legacy/conf/alacritty/yaml/font.yml
deleted file mode 100644
index a711f231..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/font.yml
+++ /dev/null
@@ -1,83 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Font configuration
-font:
-  # Normal (roman) font face
-  normal:
-    # Font family
-    #
-    # Default:
-    #   - (macOS) Menlo
-    #   - (Linux/BSD) monospace
-    #   - (Windows) Consolas
-    # family: Source Code Pro
-    # family: SauceCodePro Nerd Font
-    family: SauceCodePro Nerd Font Mono
-
-    # The `style` can be specified to pick a specific face.
-    style: Regular
-
-  # Bold font face
-  #bold:
-    # Font family
-    #
-    # If the bold family is not specified, it will fall back to the
-    # value specified for the normal font.
-    # family: Source Code Pro
-
-    # The `style` can be specified to pick a specific face.
-    #style: Bold
-
-  # Italic font face
-  #italic:
-    # Font family
-    #
-    # If the italic family is not specified, it will fall back to the
-    # value specified for the normal font.
-    # family: Source Code Pro
-
-    # The `style` can be specified to pick a specific face.
-    #style: Italic
-
-  # Bold italic font face
-  #bold_italic:
-    # Font family
-    #
-    # If the bold italic family is not specified, it will fall back to the
-    # value specified for the normal font.
-    # family: Source Code Pro
-
-    # The `style` can be specified to pick a specific face.
-    #style: Bold Italic
-
-  # Point size
-  size: 12.0
-
-  # Offset is the extra space around each character. `offset.y` can be thought
-  # of as modifying the line spacing, and `offset.x` as modifying the letter
-  # spacing.
-  offset:
-    x: -1
-    y: -1
-
-  # Glyph offset determines the locations of the glyphs within their cells with
-  # the default being at the bottom. Increasing `x` moves the glyph to the
-  # right, increasing `y` moves the glyph upward.
-  glyph_offset:
-    x: -1
-    y: -1
-
-  # Use built-in font for box drawing characters.
-  #
-  # If `true`, Alacritty will use a custom built-in font for box drawing
-  # characters (Unicode points 2500 - 259f).
-  #
-  builtin_box_drawing: true # TODO:
diff --git a/modules/home.legacy/conf/alacritty/yaml/hints.yml b/modules/home.legacy/conf/alacritty/yaml/hints.yml
deleted file mode 100644
index b9d75378..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/hints.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Hints
-#
-# Terminal hints can be used to find text or hyperlink in the visible part of
-# the terminal and pipe it to other applications.
-hints:
-  # Keys used for the hint labels.
-  alphabet: "jfkdls;ahgurieowpq"
-
-  # List with all available hints
-  #
-  # Each hint must have any of `regex` or `hyperlinks` field and either an
-  # `action` or a `command` field. The fields `mouse`, `binding` and
-  # `post_processing` are optional.
-  #
-  # The `hyperlinks` option will cause OSC 8 escape sequence hyperlinks to be
-  # highlighted.
-  #
-  # The fields `command`, `binding.key`, `binding.mods`, `binding.mode` and
-  # `mouse.mods` accept the same values as they do in the `key_bindings` section.
-  #
-  # The `mouse.enabled` field controls if the hint should be underlined while
-  # the mouse with all `mouse.mods` keys held or the vi mode cursor is above it.
-  #
-  # If the `post_processing` field is set to `true`, heuristics will be used to
-  # shorten the match if there are characters likely not to be part of the hint
-  # (e.g. a trailing `.`). This is most useful for URIs and applies only to
-  # `regex` matches.
-  #
-  # Values for `action`:
-  #   - Copy
-  #       Copy the hint's text to the clipboard.
-  #   - Paste
-  #       Paste the hint's text to the terminal or search.
-  #   - Select
-  #       Select the hint's text.
-  #   - MoveViModeCursor
-  #       Move the vi mode cursor to the beginning of the hint.
-  enabled:
-    - regex: "(ipfs:|ipns:|magnet:|mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
-             [^\u0000-\u001F\u007F-\u009F<>\"\\s{-}\\^⟨⟩`]+"
-      hyperlinks: true
-      command: xdg-open
-      post_processing: true
-      mouse:
-        enabled: true
-        mods: None
-      binding:
-        key: U
-        mods: Control|Shift
-
-    - regex: "([^ '\"`=:\\[\\(]*/)([^/: '\"`\\)\\]]*)"
-      action: Paste
-      post_procesing: false
-      binding:
-        key: T
-        mods: Control|Shift
-
-    - regex: "([a-z0-9]{7})\\s"
-      action: Paste
-      post_procesing: false
-      binding:
-        key: H
-        mods: Control|Shift
-
-    # multi regex for different purposes:
-    # 2. UUIDs
-    # 3. hex (for example signatures)
-    # 4. IP addresses
-#    - regex: "([[:alnum:]_$%&+=/@-]+)\
-#|([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\
-#|([0-9a-f]{12,128})\
-#|([[:digit:]]{1,3}.[[:digit:]]{1,3}.[[:digit:]]{1,3}.[[:digit:]]{1,3})"
-#      action: Copy
-#      post_processing: false
-#      binding:
-#        key: U
-#        mods: Control|Shift
diff --git a/modules/home.legacy/conf/alacritty/yaml/key_bindings.yml b/modules/home.legacy/conf/alacritty/yaml/key_bindings.yml
deleted file mode 100644
index 6bf31719..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/key_bindings.yml
+++ /dev/null
@@ -1,392 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Key bindings
-#
-# Key bindings are specified as a list of objects. For example, this is the
-# default paste binding:
-#
-# `- { key: V, mods: Control|Shift, action: Paste }`
-#
-# Each key binding will specify a:
-#
-# - `key`: Identifier of the key pressed
-#
-#    - A-Z
-#    - F1-F24
-#    - Key0-Key9
-#
-#    A full list with available key codes can be found here:
-#    https://docs.rs/winit/*/winit/event/enum.VirtualKeyCode.html#variants
-#
-#    Instead of using the name of the keys, the `key` field also supports using
-#    the scancode of the desired key. Scancodes have to be specified as a
-#    decimal number. This command will allow you to display the hex scancodes
-#    for certain keys:
-#
-#       `showkey --scancodes`.
-#
-# Then exactly one of:
-#
-# - `chars`: Send a byte sequence to the running application
-#
-#    The `chars` field writes the specified string to the terminal. This makes
-#    it possible to pass escape sequences. To find escape codes for bindings
-#    like `PageUp` (`"\x1b[5~"`), you can run the command `showkey -a` outside
-#    of tmux. Note that applications use terminfo to map escape sequences back
-#    to keys. It is therefore required to update the terminfo when changing an
-#    escape sequence.
-#
-# - `action`: Execute a predefined action
-#
-#   - ToggleViMode
-#   - SearchForward
-#       Start searching toward the right of the search origin.
-#   - SearchBackward
-#       Start searching toward the left of the search origin.
-#   - Copy
-#   - Paste
-#   - IncreaseFontSize
-#   - DecreaseFontSize
-#   - ResetFontSize
-#   - ScrollPageUp
-#   - ScrollPageDown
-#   - ScrollHalfPageUp
-#   - ScrollHalfPageDown
-#   - ScrollLineUp
-#   - ScrollLineDown
-#   - ScrollToTop
-#   - ScrollToBottom
-#   - ClearHistory
-#       Remove the terminal's scrollback history.
-#   - Hide
-#       Hide the Alacritty window.
-#   - Minimize
-#       Minimize the Alacritty window.
-#   - Quit
-#       Quit Alacritty.
-#   - ToggleFullscreen
-#   - ToggleMaximized
-#   - SpawnNewInstance
-#       Spawn a new instance of Alacritty.
-#   - CreateNewWindow
-#       Create a new Alacritty window from the current process.
-#   - ClearLogNotice
-#       Clear Alacritty's UI warning and error notice.
-#   - ClearSelection
-#       Remove the active selection.
-#   - ReceiveChar
-#   - None
-#
-# - Vi mode exclusive actions:
-#
-#   - Open
-#       Perform the action of the first matching hint under the vi mode cursor
-#       with `mouse.enabled` set to `true`.
-#   - ToggleNormalSelection
-#   - ToggleLineSelection
-#   - ToggleBlockSelection
-#   - ToggleSemanticSelection
-#       Toggle semantic selection based on `selection.semantic_escape_chars`.
-#   - CenterAroundViCursor
-#       Center view around vi mode cursor
-#
-# - Vi mode exclusive cursor motion actions:
-#
-#   - Up
-#       One line up.
-#   - Down
-#       One line down.
-#   - Left
-#       One character left.
-#   - Right
-#       One character right.
-#   - First
-#       First column, or beginning of the line when already at the first column.
-#   - Last
-#       Last column, or beginning of the line when already at the last column.
-#   - FirstOccupied
-#       First non-empty cell in this terminal row, or first non-empty cell of
-#       the line when already at the first cell of the row.
-#   - High
-#       Top of the screen.
-#   - Middle
-#       Center of the screen.
-#   - Low
-#       Bottom of the screen.
-#   - SemanticLeft
-#       Start of the previous semantically separated word.
-#   - SemanticRight
-#       Start of the next semantically separated word.
-#   - SemanticLeftEnd
-#       End of the previous semantically separated word.
-#   - SemanticRightEnd
-#       End of the next semantically separated word.
-#   - WordLeft
-#       Start of the previous whitespace separated word.
-#   - WordRight
-#       Start of the next whitespace separated word.
-#   - WordLeftEnd
-#       End of the previous whitespace separated word.
-#   - WordRightEnd
-#       End of the next whitespace separated word.
-#   - Bracket
-#       Character matching the bracket at the cursor's location.
-#   - SearchNext
-#       Beginning of the next match.
-#   - SearchPrevious
-#       Beginning of the previous match.
-#   - SearchStart
-#       Start of the match to the left of the vi mode cursor.
-#   - SearchEnd
-#       End of the match to the right of the vi mode cursor.
-#
-# - Search mode exclusive actions:
-#   - SearchFocusNext
-#       Move the focus to the next search match.
-#   - SearchFocusPrevious
-#       Move the focus to the previous search match.
-#   - SearchConfirm
-#   - SearchCancel
-#   - SearchClear
-#       Reset the search regex.
-#   - SearchDeleteWord
-#       Delete the last word in the search regex.
-#   - SearchHistoryPrevious
-#       Go to the previous regex in the search history.
-#   - SearchHistoryNext
-#       Go to the next regex in the search history.
-#
-# - macOS exclusive actions:
-#   - ToggleSimpleFullscreen
-#       Enter fullscreen without occupying another space.
-#
-# - Linux/BSD exclusive actions:
-#
-#   - CopySelection
-#       Copy from the selection buffer.
-#   - PasteSelection
-#       Paste from the selection buffer.
-#
-# - `command`: Fork and execute a specified command plus arguments
-#
-#    The `command` field must be a map containing a `program` string and an
-#    `args` array of command line parameter strings. For example:
-#       `{ program: "alacritty", args: ["-e", "vttest"] }`
-#
-# And optionally:
-#
-# - `mods`: Key modifiers to filter binding actions
-#
-#    - Command
-#    - Control
-#    - Option
-#    - Super
-#    - Shift
-#    - Alt
-#
-#    Multiple `mods` can be combined using `|` like this:
-#       `mods: Control|Shift`.
-#    Whitespace and capitalization are relevant and must match the example.
-#
-# - `mode`: Indicate a binding for only specific terminal reported modes
-#
-#    This is mainly used to send applications the correct escape sequences
-#    when in different modes.
-#
-#    - AppCursor
-#    - AppKeypad
-#    - Search
-#    - Alt
-#    - Vi
-#
-#    A `~` operator can be used before a mode to apply the binding whenever
-#    the mode is *not* active, e.g. `~Alt`.
-#
-# Bindings are always filled by default, but will be replaced when a new
-# binding with the same triggers is defined. To unset a default binding, it can
-# be mapped to the `ReceiveChar` action. Alternatively, you can use `None` for
-# a no-op if you do not wish to receive input characters for that binding.
-#
-# If the same trigger is assigned to multiple actions, all of them are executed
-# in the order they were defined in.
-key_bindings:
-#
-#
-  - { key: P, mods: Control, action: Paste }
-  - { key: Insert, mods: Shift, action: Paste }
-  - { key: Slash, mods: Control, chars: "gc" }
-  - { key: Y, mods: Control, action: Copy }
-  - { key: Key0, mods: Control, action: ResetFontSize }
-  - { key: Equals, mods: Control, action: IncreaseFontSize }
-  - { key: Plus, mods: Control, action: IncreaseFontSize }
-  - { key: Minus, mods: Control, action: DecreaseFontSize }
-
-  # Vi Mode
-  - { key: Space, mods: Control, action: ToggleViMode }
-  - { key: Space, mods: Control, mode: Vi, action: ScrollToBottom }
-  - { key: I, mode: Vi, action: ScrollToBottom }
-  - { key: I, mode: Vi, action: ToggleViMode }
-  - { key: C, mods: Control, mode: Vi, action: ScrollToBottom }
-  - { key: C, mods: Control, mode: Vi, action: ToggleViMode }
-  - { key: Escape, mode: Vi, action: ClearSelection }
-  - { key: Y, mods: Control, mode: Vi, action: ScrollLineUp }
-  - { key: E, mods: Control, mode: Vi, action: ScrollLineDown }
-  - { key: G, mode: Vi, action: ScrollToTop }
-  - { key: G, mods: Shift, mode: Vi, action: ScrollToBottom }
-  - { key: B, mods: Control, mode: Vi, action: ScrollPageUp }
-  - { key: F, mods: Control, mode: Vi, action: ScrollPageDown }
-  - { key: U, mods: Control, mode: Vi, action: ScrollHalfPageUp }
-  - { key: D, mods: Control, mode: Vi, action: ScrollHalfPageDown }
-  - { key: Y, mode: Vi, action: Copy }
-  - { key: Y, mode: Vi, action: ClearSelection }
-  - { key: V, mode: Vi, action: ToggleNormalSelection }
-  - { key: V, mods: Shift, mode: Vi, action: ToggleLineSelection }
-  - { key: V, mods: Control, mode: Vi, action: ToggleBlockSelection }
-  - { key: V, mods: Alt, mode: Vi, action: ToggleSemanticSelection }
-  - { key: Return, mode: Vi, action: Open }
-  - { key: K, mode: Vi, action: Up }
-  - { key: J, mode: Vi, action: Down }
-  - { key: H, mode: Vi, action: Left }
-  - { key: L, mode: Vi, action: Right }
-  - { key: Up, mode: Vi, action: Up }
-  - { key: Down, mode: Vi, action: Down }
-  - { key: Left, mode: Vi, action: Left }
-  - { key: Right, mode: Vi, action: Right }
-  - { key: Key0, mode: Vi, action: First }
-  - { key: Key4, mode: Vi, action: Last }
-  - { key: Key6, mods: Shift, mode: Vi, action: FirstOccupied }
-  - { key: H, mods: Shift, mode: Vi, action: High }
-  - { key: M, mods: Shift, mode: Vi, action: Middle }
-  - { key: L, mods: Shift, mode: Vi, action: Low }
-  - { key: B, mode: Vi, action: SemanticLeft }
-  - { key: W, mode: Vi, action: SemanticRight }
-  - { key: E, mode: Vi, action: SemanticRightEnd }
-  - { key: B, mods: Shift, mode: Vi, action: WordLeft }
-  - { key: W, mods: Shift, mode: Vi, action: WordRight }
-  - { key: E, mods: Shift, mode: Vi, action: WordRightEnd }
-  - { key: Key5, mods: Shift, mode: Vi, action: Bracket }
-  - { key: Slash, mode: Vi, action: SearchForward }
-  - { key: Slash, mods: Shift, mode: Vi, action: SearchBackward }
-  - { key: N, mode: Vi, action: SearchNext }
-  - { key: N, mods: Shift, mode: Vi, action: SearchPrevious }
-#
-#
-#
-  #- { key: Paste,                                       action: Paste          }
-  #- { key: Copy,                                        action: Copy           }
-  #- { key: L,         mods: Control,                    action: ClearLogNotice }
-  #- { key: L,         mods: Control, mode: ~Vi|~Search, chars: "\x0c"          }
-  #- { key: PageUp,    mods: Shift,   mode: ~Alt,        action: ScrollPageUp   }
-  #- { key: PageDown,  mods: Shift,   mode: ~Alt,        action: ScrollPageDown }
-  #- { key: Home,      mods: Shift,   mode: ~Alt,        action: ScrollToTop    }
-  #- { key: End,       mods: Shift,   mode: ~Alt,        action: ScrollToBottom }
-
-  # Vi Mode
-  #- { key: Space,  mods: Shift|Control, mode: ~Search,    action: ToggleViMode            }
-  #- { key: Space,  mods: Shift|Control, mode: Vi|~Search, action: ScrollToBottom          }
-  #- { key: Escape,                      mode: Vi|~Search, action: ClearSelection          }
-  #- { key: I,                           mode: Vi|~Search, action: ToggleViMode            }
-  #- { key: I,                           mode: Vi|~Search, action: ScrollToBottom          }
-  #- { key: C,      mods: Control,       mode: Vi|~Search, action: ToggleViMode            }
-  #- { key: Y,      mods: Control,       mode: Vi|~Search, action: ScrollLineUp            }
-  #- { key: E,      mods: Control,       mode: Vi|~Search, action: ScrollLineDown          }
-  #- { key: G,                           mode: Vi|~Search, action: ScrollToTop             }
-  #- { key: G,      mods: Shift,         mode: Vi|~Search, action: ScrollToBottom          }
-  #- { key: B,      mods: Control,       mode: Vi|~Search, action: ScrollPageUp            }
-  #- { key: F,      mods: Control,       mode: Vi|~Search, action: ScrollPageDown          }
-  #- { key: U,      mods: Control,       mode: Vi|~Search, action: ScrollHalfPageUp        }
-  #- { key: D,      mods: Control,       mode: Vi|~Search, action: ScrollHalfPageDown      }
-  #- { key: Y,                           mode: Vi|~Search, action: Copy                    }
-  #- { key: Y,                           mode: Vi|~Search, action: ClearSelection          }
-  #- { key: Copy,                        mode: Vi|~Search, action: ClearSelection          }
-  #- { key: V,                           mode: Vi|~Search, action: ToggleNormalSelection   }
-  #- { key: V,      mods: Shift,         mode: Vi|~Search, action: ToggleLineSelection     }
-  #- { key: V,      mods: Control,       mode: Vi|~Search, action: ToggleBlockSelection    }
-  #- { key: V,      mods: Alt,           mode: Vi|~Search, action: ToggleSemanticSelection }
-  #- { key: Return,                      mode: Vi|~Search, action: Open                    }
-  #- { key: Z,                           mode: Vi|~Search, action: CenterAroundViCursor    }
-  #- { key: K,                           mode: Vi|~Search, action: Up                      }
-  #- { key: J,                           mode: Vi|~Search, action: Down                    }
-  #- { key: H,                           mode: Vi|~Search, action: Left                    }
-  #- { key: L,                           mode: Vi|~Search, action: Right                   }
-  #- { key: Up,                          mode: Vi|~Search, action: Up                      }
-  #- { key: Down,                        mode: Vi|~Search, action: Down                    }
-  #- { key: Left,                        mode: Vi|~Search, action: Left                    }
-  #- { key: Right,                       mode: Vi|~Search, action: Right                   }
-  #- { key: Key0,                        mode: Vi|~Search, action: First                   }
-  #- { key: Key4,   mods: Shift,         mode: Vi|~Search, action: Last                    }
-  #- { key: Key6,   mods: Shift,         mode: Vi|~Search, action: FirstOccupied           }
-  #- { key: H,      mods: Shift,         mode: Vi|~Search, action: High                    }
-  #- { key: M,      mods: Shift,         mode: Vi|~Search, action: Middle                  }
-  #- { key: L,      mods: Shift,         mode: Vi|~Search, action: Low                     }
-  #- { key: B,                           mode: Vi|~Search, action: SemanticLeft            }
-  #- { key: W,                           mode: Vi|~Search, action: SemanticRight           }
-  #- { key: E,                           mode: Vi|~Search, action: SemanticRightEnd        }
-  #- { key: B,      mods: Shift,         mode: Vi|~Search, action: WordLeft                }
-  #- { key: W,      mods: Shift,         mode: Vi|~Search, action: WordRight               }
-  #- { key: E,      mods: Shift,         mode: Vi|~Search, action: WordRightEnd            }
-  #- { key: Key5,   mods: Shift,         mode: Vi|~Search, action: Bracket                 }
-  #- { key: Slash,                       mode: Vi|~Search, action: SearchForward           }
-  #- { key: Slash,  mods: Shift,         mode: Vi|~Search, action: SearchBackward          }
-  #- { key: N,                           mode: Vi|~Search, action: SearchNext              }
-  #- { key: N,      mods: Shift,         mode: Vi|~Search, action: SearchPrevious          }
-
-  # Search Mode
-  #- { key: Return,                mode: Search|Vi,  action: SearchConfirm         }
-  #- { key: Escape,                mode: Search,     action: SearchCancel          }
-  #- { key: C,      mods: Control, mode: Search,     action: SearchCancel          }
-  #- { key: U,      mods: Control, mode: Search,     action: SearchClear           }
-  #- { key: W,      mods: Control, mode: Search,     action: SearchDeleteWord      }
-  #- { key: P,      mods: Control, mode: Search,     action: SearchHistoryPrevious }
-  #- { key: N,      mods: Control, mode: Search,     action: SearchHistoryNext     }
-  #- { key: Up,                    mode: Search,     action: SearchHistoryPrevious }
-  #- { key: Down,                  mode: Search,     action: SearchHistoryNext     }
-  #- { key: Return,                mode: Search|~Vi, action: SearchFocusNext       }
-  #- { key: Return, mods: Shift,   mode: Search|~Vi, action: SearchFocusPrevious   }
-
-  # (Windows, Linux, and BSD only)
-  #- { key: V,              mods: Control|Shift, mode: ~Vi,        action: Paste            }
-  #- { key: C,              mods: Control|Shift,                   action: Copy             }
-  #- { key: F,              mods: Control|Shift, mode: ~Search,    action: SearchForward    }
-  #- { key: B,              mods: Control|Shift, mode: ~Search,    action: SearchBackward   }
-  #- { key: C,              mods: Control|Shift, mode: Vi|~Search, action: ClearSelection   }
-  #- { key: Insert,         mods: Shift,                           action: PasteSelection   }
-  #- { key: Key0,           mods: Control,                         action: ResetFontSize    }
-  #- { key: Equals,         mods: Control,                         action: IncreaseFontSize }
-  #- { key: Plus,           mods: Control,                         action: IncreaseFontSize }
-  #- { key: NumpadAdd,      mods: Control,                         action: IncreaseFontSize }
-  #- { key: Minus,          mods: Control,                         action: DecreaseFontSize }
-  #- { key: NumpadSubtract, mods: Control,                         action: DecreaseFontSize }
-
-  # (Windows only)
-  #- { key: Return,   mods: Alt,           action: ToggleFullscreen }
-
-  # (macOS only)
-  #- { key: K,              mods: Command, mode: ~Vi|~Search, chars: "\x0c"                 }
-  #- { key: K,              mods: Command, mode: ~Vi|~Search, action: ClearHistory          }
-  #- { key: Key0,           mods: Command,                    action: ResetFontSize         }
-  #- { key: Equals,         mods: Command,                    action: IncreaseFontSize      }
-  #- { key: Plus,           mods: Command,                    action: IncreaseFontSize      }
-  #- { key: NumpadAdd,      mods: Command,                    action: IncreaseFontSize      }
-  #- { key: Minus,          mods: Command,                    action: DecreaseFontSize      }
-  #- { key: NumpadSubtract, mods: Command,                    action: DecreaseFontSize      }
-  #- { key: V,              mods: Command,                    action: Paste                 }
-  #- { key: C,              mods: Command,                    action: Copy                  }
-  #- { key: C,              mods: Command, mode: Vi|~Search,  action: ClearSelection        }
-  #- { key: H,              mods: Command,                    action: Hide                  }
-  #- { key: H,              mods: Command|Alt,                action: HideOtherApplications }
-  #- { key: M,              mods: Command,                    action: Minimize              }
-  #- { key: Q,              mods: Command,                    action: Quit                  }
-  #- { key: W,              mods: Command,                    action: Quit                  }
-  #- { key: N,              mods: Command,                    action: CreateNewWindow       }
-  #- { key: F,              mods: Command|Control,            action: ToggleFullscreen      }
-  #- { key: F,              mods: Command, mode: ~Search,     action: SearchForward         }
-  #- { key: B,              mods: Command, mode: ~Search,     action: SearchBackward        }
diff --git a/modules/home.legacy/conf/alacritty/yaml/mouse.yml b/modules/home.legacy/conf/alacritty/yaml/mouse.yml
deleted file mode 100644
index c5d2acbb..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/mouse.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-mouse:
-  # Click settings
-  #
-  # The `double_click` and `triple_click` settings control the time
-  # alacritty should wait for accepting multiple clicks as one double
-  # or triple click.
-  double_click: { threshold: 300 }
-  triple_click: { threshold: 300 }
-
-  # If this is `true`, the cursor is temporarily hidden when typing.
-  hide_when_typing: false
diff --git a/modules/home.legacy/conf/alacritty/yaml/mouse_bindings.yml b/modules/home.legacy/conf/alacritty/yaml/mouse_bindings.yml
deleted file mode 100644
index 82e2b92b..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/mouse_bindings.yml
+++ /dev/null
@@ -1,42 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Mouse bindings
-#
-# Mouse bindings are specified as a list of objects, much like the key
-# bindings further below.
-#
-# To trigger mouse bindings when an application running within Alacritty
-# captures the mouse, the `Shift` modifier is automatically added as a
-# requirement.
-#
-# Each mouse binding will specify a:
-#
-# - `mouse`:
-#
-#   - Middle
-#   - Left
-#   - Right
-#   - Numeric identifier such as `5`
-#
-# - `action` (see key bindings for actions not exclusive to mouse mode)
-#
-# - Mouse exclusive actions:
-#
-#   - ExpandSelection
-#       Expand the selection to the current mouse cursor location.
-#
-# And optionally:
-#
-# - `mods` (see key bindings)
-mouse_bindings:
-#  - { mouse: Right,                 action: ExpandSelection }
-#  - { mouse: Right,  mods: Control, action: ExpandSelection }
-   - { mouse: Middle,  action: Copy  }
diff --git a/modules/home.legacy/conf/alacritty/yaml/scrolling.yml b/modules/home.legacy/conf/alacritty/yaml/scrolling.yml
deleted file mode 100644
index 0d108f76..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/scrolling.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-scrolling:
-  # Maximum number of lines in the scrollback buffer.
-  # Specifying '0' will disable scrolling.
-  history: 10000
-
-  # Scrolling distance multiplier.
-  multiplier: 3
diff --git a/modules/home.legacy/conf/alacritty/yaml/selection.yml b/modules/home.legacy/conf/alacritty/yaml/selection.yml
deleted file mode 100644
index 100118fc..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/selection.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-selection:
-  # This string contains all characters that are used as separators for
-  # "semantic words" in Alacritty.
-  semantic_escape_chars: ",│`|:\"' ()[]{}<>\t"
-
-  # When set to `true`, selected text will be copied to the primary clipboard.
-  save_to_clipboard: false
diff --git a/modules/home.legacy/conf/alacritty/yaml/shell.yml b/modules/home.legacy/conf/alacritty/yaml/shell.yml
deleted file mode 100644
index 4da99581..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/shell.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# Shell
-#
-# You can set `shell.program` to the path of your favorite shell, e.g.
-# `/bin/fish`. Entries in `shell.args` are passed unmodified as arguments to the
-# shell.
-#
-# Default:
-#   - (Linux/BSD/macOS) `$SHELL` or the user's login shell, if `$SHELL` is unset
-#   - (Windows) powershell
-#shell:
-#  program: /bin/bash
-#  args:
-#    - --login
diff --git a/modules/home.legacy/conf/alacritty/yaml/window.yml b/modules/home.legacy/conf/alacritty/yaml/window.yml
deleted file mode 100644
index 2d4006ba..00000000
--- a/modules/home.legacy/conf/alacritty/yaml/window.yml
+++ /dev/null
@@ -1,99 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-window:
-  # Window dimensions (changes require restart)
-  #
-  # Number of lines/columns (not pixels) in the terminal. Both lines and columns
-  # must be non-zero for this to take effect. The number of columns must be at
-  # least `2`, while using a value of `0` for columns and lines will fall back
-  # to the window manager's recommended size
-  dimensions:
-    columns: 0
-    lines: 0
-
-  # Window position (changes require restart)
-  #
-  # Specified in number of pixels.
-  # If the position is not set, the window manager will handle the placement.
-  #position:
-  #  x: 0
-  #  y: 0
-
-  # Window padding (changes require restart)
-  #
-  # Blank space added around the window in pixels. This padding is scaled
-  # by DPI and the specified value is always added at both opposing sides.
-  padding:
-    x: 5
-    y: 5
-
-  # Spread additional padding evenly around the terminal content.
-  #dynamic_padding: false
-
-  # Window decorations
-  #
-  # Values for `decorations`:
-  #     - full: Borders and title bar
-  #     - none: Neither borders nor title bar
-  #
-  # Values for `decorations` (macOS only):
-  #     - transparent: Title bar, transparent background and title bar buttons
-  #     - buttonless: Title bar, transparent background and no title bar buttons
-  decorations: none
-
-  # Background opacity
-  #
-  # Window opacity as a floating point number from `0.0` to `1.0`.
-  # The value `0.0` is completely transparent and `1.0` is opaque.
-  opacity: 0.9
-
-  # Startup Mode (changes require restart)
-  #
-  # Values for `startup_mode`:
-  #   - Windowed
-  #   - Maximized
-  #   - Fullscreen
-  #
-  # Values for `startup_mode` (macOS only):
-  #   - SimpleFullscreen
-  startup_mode: Windowed
-
-  # Window title
-  title: Alacritty
-
-  # Allow terminal applications to change Alacritty's window title.
-  dynamic_title: true
-
-  # Window class (Linux/BSD only):
-  class:
-    # Application instance name
-    instance: Alacritty
-    # General application class
-    general: Alacritty
-
-  # Decorations theme variant
-  #
-  # Override the variant of the System theme/GTK theme/Wayland client side
-  # decorations. Commonly supported values are `Dark`, `Light`, and `None` for
-  # auto pick-up. Set this to `None` to use the default theme variant.
-  decorations_theme_variant: None
-
-  # Resize increments
-  #
-  # Prefer resizing window by discrete steps equal to cell dimensions.
-  #resize_increments: false
-
-  # Make `Option` key behave as `Alt` (macOS only):
-  #   - OnlyLeft
-  #   - OnlyRight
-  #   - Both
-  #   - None (default)
-  #option_as_alt: None
diff --git a/modules/home.legacy/conf/beets/default.nix b/modules/home.legacy/conf/beets/default.nix
index de05ca24..0879b1a5 100644
--- a/modules/home.legacy/conf/beets/default.nix
+++ b/modules/home.legacy/conf/beets/default.nix
@@ -41,9 +41,12 @@ in {
         color = true;
       };
 
-      include = [
-        "./replace_override.yaml"
-      ];
+      replace = {
+        "[/]" = "\\\\";
+        "[\\x00-\\x1f]" = "";
+        "\\s+$" = "";
+        "^\\s+" = "";
+      };
 
       import = {
         # move, instead of copying or linking the files
@@ -62,15 +65,21 @@ in {
       };
 
       paths = let
-        j = lib.strings.concatStringsSep "/";
+        join = lib.strings.concatStringsSep "/";
       in {
-        default = j ["[Default]" "$genre" "$first_artist" "$album ($albumtype)" "$track $title"];
-        "albumtype:live" = j ["[Live]" "$genre" "$first_artist" "$album ($albumtype)" "$track $title"];
-
-        "albumtype:album" = j ["Music" "$genre" "$first_artist" "$album ($albumtype)" "$track $title"];
-        "albumtype::(Single|EP)" = j ["Music" "$genre" "$first_artist_singleton" "$album ($albumtype)" "$track $title"];
-        "albumtype:compilation" = j ["Complilations" "$genre" "Various Artists" "$album ($albumtype)" "$track $title"];
-        "albumtype:soundtrack" = j ["Soundtracks" "$genre" "$first_artist" "$album" "$track $title"];
+        "albumtype:live" = join [
+          "[Live, please delete]"
+          "$genre"
+          "$primary_artist" # (= $albumartists[0]). From inline plugin
+          "$album ($albumtype)"
+          "$track $title"
+        ];
+
+        default = join [
+          "$primary_artist" # (= $albumartists[0]). From inline plugin
+          "$album%aunique{}"
+          "$track $title"
+        ];
       };
 
       inherit plugins;
@@ -96,20 +105,17 @@ in {
     };
 
     mpdIntegration = {
-      enableStats = true;
       enableUpdate = true;
       host = config.home.sessionVariables.MPD_HOST;
     };
   };
 
-  xdg.configFile."beets/replace_override.yaml".source = ./replace_override.yaml;
-
-  # Use the json formatter instead of the YAML one, as the YAML formatter mangles the
-  # longer python inline strings.
-  # YAML is a superset of JSON.
-  xdg.configFile."beets/config.yaml".source =
-    lib.mkForce
-    ((pkgs.formats.json {}).generate
-      "beets-config"
-      config.programs.beets.settings);
+  # # Use the json formatter instead of the YAML one, as the YAML formatter mangles the
+  # # longer python inline strings.
+  # # YAML is a superset of JSON.
+  # xdg.configFile."beets/config.yaml".source =
+  #   lib.mkForce
+  #   ((pkgs.formats.json {}).generate
+  #     "beets-config"
+  #     config.programs.beets.settings);
 }
diff --git a/modules/home.legacy/conf/beets/plugins.nix b/modules/home.legacy/conf/beets/plugins.nix
index 09eeac5b..aaeab843 100644
--- a/modules/home.legacy/conf/beets/plugins.nix
+++ b/modules/home.legacy/conf/beets/plugins.nix
@@ -17,39 +17,25 @@
   # <2024-08-07>
   # "scrub"
 
-  # Help submitting stuff to music brainz
-  "mbsubmit"
-
   # Extract things from the music file
   # "xtractor"
 
+  "musicbrainz"
+
   # Calculate replay gain
   "replaygain"
 
   # Check for bad files
   "badfiles"
 
-  # Alows to use inline python for parsing tags
-  "inline"
-
-  # Support player integration
-  "play"
-
   # Show tags on files/queries
   "info"
 
-  # Create playlist from `play_count`/`skip_count` (gathered by the `mpdstats`
-  # plugin)
-  # Note that this should come _before_ the `mpdupdate` plugin, to ensure that
-  # `mpdupgate` can propagate changed playlist to `mpd`.
-  "smartplaylist"
+  "inline"
 
   # Warn, when importing a matching item
   "ihate"
 
-  # Allow fuzzy searching
-  "fuzzy"
-
   # Filter out duplicates
   "duplicates"
 
@@ -59,9 +45,6 @@
   # Download album art
   "fetchart"
 
-  # Fetches tags from `last.fm` and adds them as genres to imported music
-  "lastgenre"
-
   # Run commands on events
   "hook"
 
@@ -71,6 +54,5 @@
   # Allow beets to understand deezer id's
   # "deezer"
 
-  "mpdstats" # Transfer MPD stats to beets
   "mpdupdate" # Update MPD database on import
 ]
diff --git a/modules/home.legacy/conf/beets/plugins/default.nix b/modules/home.legacy/conf/beets/plugins/default.nix
index 65cd935c..2b2bd607 100644
--- a/modules/home.legacy/conf/beets/plugins/default.nix
+++ b/modules/home.legacy/conf/beets/plugins/default.nix
@@ -11,15 +11,10 @@
   imports = [
     ./badfiles
     ./duplicates
-    ./fuzzy
     ./ihate
     ./inline
-    ./lastgenre
     ./lyrics
-    ./mbsubmit
-    ./play
     ./replaygain
-    ./smartplaylist
     # ./xtractor
   ];
 }
diff --git a/modules/home.legacy/conf/beets/plugins/fuzzy/default.nix b/modules/home.legacy/conf/beets/plugins/fuzzy/default.nix
deleted file mode 100644
index de37c4e8..00000000
--- a/modules/home.legacy/conf/beets/plugins/fuzzy/default.nix
+++ /dev/null
@@ -1,15 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  programs.beets.settings.fuzzy = {
-    # The prefix denoting that a search should be run in fuzzy mode
-    prefix = ".";
-  };
-}
diff --git a/modules/home.legacy/conf/beets/plugins/ihate/default.nix b/modules/home.legacy/conf/beets/plugins/ihate/default.nix
index 51cb6f11..2356ec3b 100644
--- a/modules/home.legacy/conf/beets/plugins/ihate/default.nix
+++ b/modules/home.legacy/conf/beets/plugins/ihate/default.nix
@@ -11,6 +11,7 @@
   programs.beets.settings.ihate = {
     warn = [
       "title:commentary"
+      "title:live"
       "albumtype:live"
     ];
   };
diff --git a/modules/home.legacy/conf/beets/plugins/inline/default.nix b/modules/home.legacy/conf/beets/plugins/inline/default.nix
index b5655028..bf476c9f 100644
--- a/modules/home.legacy/conf/beets/plugins/inline/default.nix
+++ b/modules/home.legacy/conf/beets/plugins/inline/default.nix
@@ -8,44 +8,9 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {...}: {
-  programs.beets.settings = {
-    item_fields = {
-      # Taken from https://github.com/trapd00r/configs/blob/4f3dada5700846cca6c2869e6fa6b3c795b87b67/beets/config.yaml
-      first_artist =
-        /*
-        python
-        */
-        ''
-          # import an album to another artists directory, like:
-          # Tom Jones │1999│ Burning Down the House [Single, CD, FLAC]
-          # to The Cardigans/+singles/Tom Jones & the Cardigans │1999│ Burning Down the House [Single, CD, FLAC]
-          # https://github.com/beetbox/beets/discussions/4012#discussioncomment-1021414
-          # beet import --set myartist='The Cardigans'
-          # we must first check to see if myartist is defined, that is, given on
-          # import time, or we raise an NameError exception.
-          try:
-            myartist
-          except NameError:
-            import re
-            return re.split(',|\\s+(feat(.?|uring)|&|(Vs|Ft).)', albumartist, 1, flags=re.IGNORECASE)[0]
-          else:
-            return myartist
-        '';
-
-      first_artist_singleton =
-        /*
-        python
-        */
-        ''
-          try:
-            myartist
-          except NameError:
-            import re
-            return re.split(',|\\s+(feat(.?|uring)|&|(Vs|Ft).)', artist, 1, flags=re.IGNORECASE)[0]
-          else:
-            return myartist
-        '';
-    };
-    album_fields = {};
+  programs.beets.settings.item_fields = {
+    primary_artist =
+      # python
+      ''albumartists[0]'';
   };
 }
diff --git a/modules/home.legacy/conf/beets/plugins/lastgenre/default.nix b/modules/home.legacy/conf/beets/plugins/lastgenre/default.nix
deleted file mode 100644
index 4d3dcfb0..00000000
--- a/modules/home.legacy/conf/beets/plugins/lastgenre/default.nix
+++ /dev/null
@@ -1,16 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  programs.beets.settings.lastgenre = {
-    prefer_specific = false;
-    # Lookup the track, not the album
-    source = "track";
-  };
-}
diff --git a/modules/home.legacy/conf/beets/plugins/mbsubmit/default.nix b/modules/home.legacy/conf/beets/plugins/mbsubmit/default.nix
index bdcb3721..e69de29b 100644
--- a/modules/home.legacy/conf/beets/plugins/mbsubmit/default.nix
+++ b/modules/home.legacy/conf/beets/plugins/mbsubmit/default.nix
@@ -1,18 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  lib,
-  pkgs,
-  ...
-}: {
-  programs.beets.settings.mbsubmit = {
-    picard_path = lib.getExe pkgs.picard;
-  };
-}
diff --git a/modules/home.legacy/conf/beets/plugins/smartplaylist/default.nix b/modules/home.legacy/conf/beets/plugins/smartplaylist/default.nix
deleted file mode 100644
index 9b52c1ad..00000000
--- a/modules/home.legacy/conf/beets/plugins/smartplaylist/default.nix
+++ /dev/null
@@ -1,42 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{config, ...}: {
-  programs.beets.settings.smartplaylist = {
-    relative_to = config.services.mpd.musicDirectory;
-    playlist_dir = config.services.mpd.playlistDirectory;
-    forward_slash = false;
-
-    # Show the real m3u file paths, when running `--pretend`
-    pretend_paths = true;
-
-    playlists = [
-      {
-        name = "artists-$first_artist.m3u";
-        query = "";
-      }
-      {
-        name = "ratings-good.m3u";
-        query = "rating:0.7..1.0";
-      }
-      {
-        name = "ratings-mediocre.m3u";
-        query = "rating:0.4..0.7";
-      }
-      {
-        name = "ratings-bad.m3u";
-        query = "rating:0.0..0.4";
-      }
-      {
-        name = "not_played.m3u";
-        query = "-play_count: artist:";
-      }
-    ];
-  };
-}
diff --git a/modules/home.legacy/conf/beets/replace_override.yaml b/modules/home.legacy/conf/beets/replace_override.yaml
deleted file mode 100644
index aea5e54a..00000000
--- a/modules/home.legacy/conf/beets/replace_override.yaml
+++ /dev/null
@@ -1,20 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
----
-replace:
-    '[\\/]': _
-    '^\.': _
-    '[\x00-\x1f]': _
-    '[<>:"\?\*\|]': _
-    '\.$': _
-    '\s+$': ''
-    '^\s+': ''
-    '^-': _
diff --git a/modules/home.legacy/conf/default.nix b/modules/home.legacy/conf/default.nix
index de02f844..89502a64 100644
--- a/modules/home.legacy/conf/default.nix
+++ b/modules/home.legacy/conf/default.nix
@@ -9,30 +9,21 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {...}: {
   imports = [
-    ./alacritty
     ./beets
     ./btop
     ./dconf
     ./gammastep
     ./gtk
     ./himalaya
-    ./hyfetch
-    ./iamb
     ./keepassxc
-    ./latexindent
     ./mail
-    ./mako
     ./mbsync
     ./mumble
     ./neomutt
-    ./nix-index
     ./npm
     ./prusa_slicer
     ./python
-    ./rclone
-    ./rofi
     ./starship
     ./swayidle
-    ./tridactyl
   ];
 }
diff --git a/modules/home.legacy/conf/hyfetch/default.nix b/modules/home.legacy/conf/hyfetch/default.nix
deleted file mode 100644
index bac0731e..00000000
--- a/modules/home.legacy/conf/hyfetch/default.nix
+++ /dev/null
@@ -1,29 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  programs.hyfetch = {
-    enable = true;
-    settings = {
-      preset = "rainbow";
-      mode = "rgb";
-      light_dark = "dark";
-      lightness = 0.65;
-      color_align = {
-        mode = "horizontal";
-        custom_colors = [];
-        fore_back = null;
-      };
-      backend = "neofetch";
-      distro = null;
-      pride_month_shown = [];
-      pride_month_disable = false;
-    };
-  };
-}
diff --git a/modules/home.legacy/conf/iamb/config.json b/modules/home.legacy/conf/iamb/config.json
deleted file mode 100644
index ca06d543..00000000
--- a/modules/home.legacy/conf/iamb/config.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
-    "profiles": {
-        "soispha": {
-            "user_id": "@soispha:vhack.eu",
-            "url": "https://matrix.vhack.eu"
-        }
-    },
-    "default_profile": "soispha"
-}
diff --git a/modules/home.legacy/conf/iamb/config.json.license b/modules/home.legacy/conf/iamb/config.json.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/home.legacy/conf/iamb/config.json.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/home.legacy/conf/iamb/default.nix b/modules/home.legacy/conf/iamb/default.nix
deleted file mode 100644
index 764e2efc..00000000
--- a/modules/home.legacy/conf/iamb/default.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  xdg.configFile."iamb/config.json".source = ./config.json;
-}
diff --git a/modules/home.legacy/conf/latexindent/default.nix b/modules/home.legacy/conf/latexindent/default.nix
deleted file mode 100644
index aeedd411..00000000
--- a/modules/home.legacy/conf/latexindent/default.nix
+++ /dev/null
@@ -1,13 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  xdg.configFile."latexindent/indentconfig.yaml".source = ./indentconfig.yaml;
-  xdg.configFile."latexindent/mysettings.yaml".source = ./mysettings.yaml;
-}
diff --git a/modules/home.legacy/conf/latexindent/indentconfig.yaml b/modules/home.legacy/conf/latexindent/indentconfig.yaml
deleted file mode 100644
index 6465a17a..00000000
--- a/modules/home.legacy/conf/latexindent/indentconfig.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-paths:
-- /home/dt/.config/latexindent/mysettings.yaml
diff --git a/modules/home.legacy/conf/latexindent/mysettings.yaml b/modules/home.legacy/conf/latexindent/mysettings.yaml
deleted file mode 100644
index 122821da..00000000
--- a/modules/home.legacy/conf/latexindent/mysettings.yaml
+++ /dev/null
@@ -1,682 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# defaultSettings.yaml for latexindent.pl, version 3.19.1, 2022-12-04
-#                      a script that aims to
-#                      beautify .tex, .sty, .cls files
-#
-# (or latexindent.exe if you're on Windows)
-#
-#---------------------------------------------------------------------------------------
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# See http://www.gnu.org/licenses/.
-#
-# Chris Hughes, 2017
-#
-# For all communication, please visit: https://github.com/cmhughes/latexindent.pl
-#
-#---------------------------------------------------------------------------------------
-# You should feel encouraged to change anything you like in these settings, but
-# it would probably be better to have your own user settings
-# files somewhere else - remember that this file may be overwritten
-# when you update your tex distribution. Please see the manual linked from:
-#
-#       https://github.com/cmhughes/latexindent.pl
-#
-# for details of how to create and configure your own settings files.
-#
-# Please read the manual (linked from above) first to understand what each switch does.
-#
-#---------------------------------------------------------------------------------------
-
-# latexindent can be called to act on a file without using the file's extension,
-# e.g, simply
-#       latexindent myfile
-# in which case the choice of file extension is chosen
-# according to the choices made in fileExtensionPreference
-# Other file extensions can be added.
-fileExtensionPreference:
-    .tex: 1
-    .sty: 2
-    .cls: 3
-    .bib: 4
-
-# default file extension of backup file (if -w switch is active)
-# for example, if your .tex file is called
-#       myfile.tex
-# and you specify the backupExtension as BACKUP.bak then your
-# backup file will be
-#       myfileBACKUP.bak
-backupExtension: .bak
-
-# only one backup per file:
-#   - if onlyOneBackUp is 0 then, as a safety measure,
-#     the number on the extension increments by 1 each time:
-#
-#           myfile.bak0, myfile.bak1, myfile.bak2
-#   - if you set onlyOnebackUp to 1, then the backup file will
-#     be overwritten each time (not recommended until you trust the script)
-onlyOneBackUp: 0
-
-# some users may want a finite number of backup files,
-# say at most 3; in which case, they can change this maxNumberOfBackUps.
-#
-# If maxNumberOfBackUps is set to 0 (or less) then infinitely
-# many backups are possible, unless onlyOneBackUp is switched on
-maxNumberOfBackUps: 0
-
-# some users may wish to cycle through back up files.
-#
-# for example, with maxNumberOfBackUps: 4, they may
-# wish to delete the oldest back up file, and keep only the most recent.
-#
-#    copy myfile.bak1 to myfile.bak0
-#    copy myfile.bak2 to myfile.bak1
-#    copy myfile.bak3 to myfile.bak2
-#    copy myfile.bak4 to myfile.bak3
-#
-# the back up will be written to myfile.bak4
-cycleThroughBackUps: 0
-
-# preferences for information displayed in the log file
-logFilePreferences:
-    showEveryYamlRead: 1
-    showAmalgamatedSettings: 0
-    showDecorationStartCodeBlockTrace: 0
-    showDecorationFinishCodeBlockTrace: 0
-    endLogFileWith: '--------------'
-    showGitHubInfoFooter: 1
-    Dumper:
-      Terse: 1
-      Indent: 1
-      Useqq: 1
-      Deparse: 1
-      Quotekeys: 0
-      Sortkeys: 1
-      Pair: " => "
-
-#  verbatim environments specified
-#  in this field will not be changed at all!
-verbatimEnvironments:
-    verbatim: 1
-    lstlisting: 1
-    minted: 1
-
-#  verbatim commands such as \verb! body !, \lstinline$something else$
-verbatimCommands:
-    verb: 1
-    lstinline: 1
-
-#  no indent blocks (not necessarily verbatim
-#  environments) which are marked as %\begin{noindent}
-#  or anything else that you detail in the following
-noIndentBlock:
-    noindent: 1
-    cmhtest: 1
-
-# \begin{document} and \end{document} are treated differently
-# by latexindent within filecontents environments
-fileContentsEnvironments:
-    filecontents: 1
-    filecontents*: 1
-
-# indent preamble
-indentPreamble: 1
-
-# assume no preamble in cls, sty, by default
-lookForPreamble:
-    .tex: 1
-    .sty: 0
-    .cls: 0
-    .bib: 0
-
-# some preambles can contain \begin and \end statements
-# that are not in their 'standard environment block', for example,
-# consider the following key = values:
-#    preheadhook={\begin{mdframed}[style=myframedstyle]},
-#    postfoothook=\end{mdframed},
-preambleCommandsBeforeEnvironments: 0
-
-# default value of indentation
-defaultIndent: "    "
-
-# remove trailing whitespace from all lines
-removeTrailingWhitespace:
-    beforeProcessing: 0
-    afterProcessing: 1
-
-# name of code blocks that should have their body aligned at ampersand delimiters
-lookForAlignDelims:
-   tabular:
-      delims: 1
-      alignDoubleBackSlash: 1
-      spacesBeforeDoubleBackSlash: 1
-      multiColumnGrouping: 0
-      alignRowsWithoutMaxDelims: 1
-      spacesBeforeAmpersand: 1
-      spacesAfterAmpersand: 1
-      justification: left
-      alignFinalDoubleBackSlash: 0
-      dontMeasure: 0
-      delimiterRegEx: '(?<!\\)(&)'
-      delimiterJustification: left
-      lookForChildCodeBlocks: 1
-   tabularx:
-      delims: 1
-   longtable: 1
-   tabu: 1
-   array: 1
-   matrix: 1
-   listabla: 1
-   # amsmath
-   align: 1
-   align*: 1
-   alignat: 1
-   alignat*: 1
-   aligned: 1
-   bmatrix: 1
-   Bmatrix: 1
-   cases: 1
-   flalign: 1
-   flalign*: 1
-   pmatrix: 1
-   vmatrix: 1
-   Vmatrix: 1
-   # mathtools
-   cases*: 1
-   dcases: 1
-   dcases*: 1
-   rcases: 1
-   rcases*: 1
-   drcases: 1
-   drcases*: 1
-   # nicematrix
-   NiceTabular: 1
-   NiceMatrix: 1
-   pNiceMatrix: 1
-   bNiceMatrix: 1
-   BNiceMatrix: 1
-   vNiceMatrix: 1
-   VNiceMatrix: 1
-   NiceArray: 1
-   pNiceArrayC: 1
-   bNiceArrayC: 1
-   BNiceArrayC: 1
-   vNiceArrayC: 1
-   VNiceArrayC: 1
-   NiceArrayCwithDelims: 1
-   pNiceArrayRC: 1
-   bNiceArrayRC: 1
-   BNiceArrayRC: 1
-   vNiceArrayRC: 1
-   VNiceArrayRC: 1
-   NiceArrayRCwithDelims: 1
-   # tabularray
-   tblr: 1
-   longtblr: 1
-   talltblr: 1
-
-# if you want the script to look for \item commands
-# and format it, as follows (for example),
-#       \begin{itemize}
-#           \item content here
-#                 next line is indented
-#                 next line is indented
-#           \item another item
-#       \end{itemize}
-# then populate indentAfterItems. See also itemNames
-indentAfterItems:
-    itemize: 1
-    itemize*: 1
-    enumerate: 1
-    enumerate*: 1
-    description: 1
-    description*: 1
-    list: 1
-
-# if you want to use other names for your items (for example, \part)
-# then populate them here; note that you can trick latexindent.pl
-# into indenting all kinds of commands (within environments specified in
-# indentAfterItems) using this technique.
-itemNames:
-    item: 1
-    myitem: 1
-
-# specialBeginEnd is, by default, mathmode focus, although
-# there's no restrictions
-specialBeginEnd:
-    displayMath:
-        begin: '\\\['
-        end: '\\\]'
-        lookForThis: 1
-    inlineMath:
-        begin: '(?<!\$)(?<!\\)\$(?!\$)'
-        end: '(?<!\\)\$(?!\$)'
-        lookForThis: 1
-    displayMathTeX:
-        begin: '\$\$'
-        end: '\$\$'
-        lookForThis: 1
-    specialBeforeCommand: 0
-
-# if you want to add indentation after
-# a heading, such as \part, \chapter, etc
-# then populate it in here - you can add
-# an indent rule to indentRules if you would
-# like something other than defaultIndent
-#
-# you can also change the level if you like,
-# or add your own title command
-indentAfterHeadings:
-    part:
-       indentAfterThisHeading: 0
-       level: 1
-    chapter:
-       indentAfterThisHeading: 0
-       level: 2
-    section:
-       indentAfterThisHeading: 0
-       level: 3
-    subsection:
-       indentAfterThisHeading: 0
-       level: 4
-    subsection*:
-       indentAfterThisHeading: 0
-       level: 4
-    subsubsection:
-       indentAfterThisHeading: 0
-       level: 5
-    paragraph:
-       indentAfterThisHeading: 0
-       level: 6
-    subparagraph:
-       indentAfterThisHeading: 0
-       level: 7
-
-# maximum indentation, off by default
-maximumIndentation: -1
-
-# if you don't want to have additional indentation
-# in a code block, then add it to noAdditionalIndent; note that
-# code blocks in this field will inherit
-# the *current* level of indentation they just won't
-# get any *additional* indentation
-noAdditionalIndent:
-    myexample: 0
-    mydefinition: 0
-    problem: 0
-    exercises: 0
-    mysolution: 0
-    foreach: 0
-    widepage: 0
-    comment: 0
-    document: 0
-    frame: 0
-
-# if you have indent rules for particular code blocks
-# then you can populate them in indentRules; for example, you might just want
-# to use a space " " or maybe a double tab "        "
-indentRules:
-   myenvironment: "        "
-   anotherenvironment: "                "
-   chapter: " "
-   section: " "
-   item: "      "
-   myitem: "        "
-
-# set noAdditionalIndent globally for codeblocks
-noAdditionalIndentGlobal:
-    environments: 0
-    commands: 0
-    optionalArguments: 0
-    mandatoryArguments: 0
-    ifElseFi: 0
-    items: 0
-    keyEqualsValuesBracesBrackets: 0
-    namedGroupingBracesBrackets: 0
-    UnNamedGroupingBracesBrackets: 0
-    specialBeginEnd: 0
-    afterHeading: 0
-    filecontents: 0
-
-# set indentRules globally for codeblocks; these need
-# to be horizontal spaces, if they are to be used
-indentRulesGlobal:
-    environments: 0
-    commands: 0
-    optionalArguments: 0
-    mandatoryArguments: 0
-    ifElseFi: 0
-    items: 0
-    keyEqualsValuesBracesBrackets: 0
-    namedGroupingBracesBrackets: 0
-    UnNamedGroupingBracesBrackets: 0
-    specialBeginEnd: 0
-    afterHeading: 0
-    filecontents: 0
-
-# command code block details
-commandCodeBlocks:
-    roundParenthesesAllowed: 1
-    stringsAllowedBetweenArguments:
-      -
-        amalgamate: 1
-      - 'node'
-      - 'at'
-      - 'to'
-      - 'decoration'
-      - '\+\+'
-      - '\-\-'
-      - '\#\#\d'
-    commandNameSpecial:
-      -
-        amalgamate: 1
-      - '@ifnextchar\['
-
-# change dos line breaks into unix
-dos2unixlinebreaks: 1
-
-# modifyLineBreaks will only be searched if the -m
-# switch is active
-#
-# poly-switch examples:
-#
-#    BeginStartsOnOwnLine:
-#       modify line breaks before a begin statement
-#
-#       when set to -1, e.g
-#               some text some text
-#               \begin{myenvironment}
-#           will be changed to
-#               some text some text \begin{myenvironment}
-#       when set to 0, the switch is ignored
-#       when set to 1, e.g
-#               some text some text \begin{myenvironment}
-#           will be changed to
-#               some text some text
-#               \begin{myenvironment}
-#       when set to 2, e.g
-#               some text some text \begin{myenvironment}
-#           will be changed to
-#               some text some text%
-#               \begin{myenvironment}
-#       when set to 3, e.g
-#               some text some text \begin{myenvironment}
-#           will be changed to
-#               some text some text
-#
-#               \begin{myenvironment}
-#
-#    BodyStartsOnOwnLine:
-#       modify line breaks before the beginning of the body
-#
-#       when set to -1, e.g
-#               \begin{myenv}
-#                   body text body text
-#           will be changed to
-#               \begin{myenv}body text body text
-#       when set to 0, the switch is ignored
-#       when set to 1, e.g
-#               \begin{myenv}body text body text
-#           will be changed to
-#               \begin{myenv}
-#                   body text body text
-#       when set to 2, e.g
-#               \begin{myenv}body text body text
-#           will be changed to
-#               \begin{myenv}%
-#                   body text body text
-#       when set to 3, e.g
-#               \begin{myenv}body text body text
-#           will be changed to
-#               \begin{myenv}
-#
-#                   body text body text
-#
-#    EndStartsOnOwnLine:
-#       modify line breaks before the end statement
-#
-#       when set to -1, e.g
-#               some text some text
-#               \end{myenvironment}
-#           will be changed to
-#               some text some text \end{myenvironment}
-#       when set to 0, the switch is ignored
-#       when set to 1, e.g
-#               some text some text \end{myenvironment}
-#           will be changed to
-#               some text some text
-#               \end{myenvironment}
-#       when set to 2, e.g
-#               some text some text \end{myenvironment}
-#           will be changed to
-#               some text some text%
-#               \end{myenvironment}
-#       when set to 3, e.g
-#               some text some text \end{myenvironment}
-#           will be changed to
-#               some text some text
-#
-#               \end{myenvironment}
-#
-#    EndFinishesWithLineBreak:
-#       modify line breaks after the end statement
-#
-#       when set to -1, e.g
-#               \end{myenvironment}
-#               some text some text
-#           will be changed to
-#                   \end{myenvironment}some text some text
-#       when set to 0, the switch is ignored
-#       when set to 1, e.g
-#               \end{myenvironment}some text some text
-#           will be changed to
-#                   \end{myenvironment}
-#                   some text some text
-#       when set to 2, e.g
-#               \end{myenvironment}some text some text
-#           will be changed to
-#                   \end{myenvironment}%
-#                   some text some text
-#       when set to 3, e.g
-#               \end{myenvironment}some text some text
-#           will be changed to
-#                   \end{myenvironment}
-#
-#                   some text some text
-#
-# you can specify settings on a per-name basis
-modifyLineBreaks:
-    preserveBlankLines: 1
-    condenseMultipleBlankLinesInto: 1
-    oneSentencePerLine:
-        manipulateSentences: 0
-        removeSentenceLineBreaks: 1
-        multipleSpacesToSingle: 1
-        textWrapSentences: 0   # setting to 1 disables main textWrap routine
-        sentenceIndent: ""
-        sentencesFollow:
-            par: 1
-            blankLine: 1
-            fullStop: 1
-            exclamationMark: 1
-            questionMark: 1
-            rightBrace: 1
-            commentOnPreviousLine: 1
-            other: 0
-        sentencesBeginWith:
-            A-Z: 1
-            a-z: 0
-            other: 0
-        sentencesEndWith:
-            basicFullStop: 0
-            betterFullStop: 1
-            exclamationMark: 1
-            questionMark: 1
-            other: 0
-    textWrapOptions:
-        columns: 0
-        multipleSpacesToSingle: 1
-        removeBlockLineBreaks: 1
-        blocksFollow:
-           headings: 1
-           commentOnPreviousLine: 1
-           par: 1
-           blankLine: 1
-           verbatim: 1
-           filecontents: 1
-           other: '\\\]|\\item(?:\h|\[)'      # regex
-        blocksBeginWith:
-           A-Z: 1
-           a-z: 1
-           0-9: 0
-           other: 0                           # regex
-        blocksEndBefore:
-           commentOnOwnLine: 1
-           verbatim: 1
-           filecontents: 1
-           other: '\\begin\{|\\\[|\\end\{'    # regex
-        huge: overflow                        # forbid mid-word line breaks
-        separator: ""
-    # poly-switches below here
-    environments:
-        BeginStartsOnOwnLine: 0
-        BodyStartsOnOwnLine: 0
-        EndStartsOnOwnLine: 0
-        EndFinishesWithLineBreak: 0
-        equation*:
-            BeginStartsOnOwnLine: 0
-            BodyStartsOnOwnLine: 0
-            EndStartsOnOwnLine: 0
-            EndFinishesWithLineBreak: 0
-    ifElseFi:
-        IfStartsOnOwnLine: 0
-        BodyStartsOnOwnLine: 0
-        OrStartsOnOwnLine: 0
-        OrFinishesWithLineBreak: 0
-        ElseStartsOnOwnLine: 0
-        ElseFinishesWithLineBreak: 0
-        FiStartsOnOwnLine: 0
-        FiFinishesWithLineBreak: 0
-        ifnum:
-            IfStartsOnOwnLine: 0
-            BodyStartsOnOwnLine: 0
-            OrStartsOnOwnLine: 0
-            OrFinishesWithLineBreak: 0
-            ElseStartsOnOwnLine: 0
-            ElseFinishesWithLineBreak: 0
-            FiStartsOnOwnLine: 0
-            FiFinishesWithLineBreak: 0
-    commands:
-        CommandStartsOnOwnLine: 0
-        CommandNameFinishesWithLineBreak: 0
-    optionalArguments:
-        LSqBStartsOnOwnLine: 0
-        OptArgBodyStartsOnOwnLine: 0
-        RSqBStartsOnOwnLine: 0
-        RSqBFinishesWithLineBreak: 0
-    mandatoryArguments:
-        LCuBStartsOnOwnLine: 0
-        MandArgBodyStartsOnOwnLine: 0
-        RCuBStartsOnOwnLine: 0
-        RCuBFinishesWithLineBreak: 0
-    keyEqualsValuesBracesBrackets:
-        KeyStartsOnOwnLine: 0
-        EqualsStartsOnOwnLine: 0
-        EqualsFinishesWithLineBreak: 0
-    items:
-        ItemStartsOnOwnLine: 0
-        ItemFinishesWithLineBreak: 0
-    namedGroupingBracesBrackets:
-        NameStartsOnOwnLine: 0
-        NameFinishesWithLineBreak: 0
-    specialBeginEnd:
-        SpecialBeginStartsOnOwnLine: 0
-        SpecialBodyStartsOnOwnLine: 0
-        SpecialEndStartsOnOwnLine: 0
-        SpecialEndFinishesWithLineBreak: 0
-    verbatim:
-        VerbatimBeginStartsOnOwnLine: 0
-        VerbatimEndFinishesWithLineBreak: 0
-
-# replacements, only active when either -r or -rr switches are active
-replacements:
-  -
-    amalgamate: 1
-  -
-    this: 'latexindent.pl'
-    that: 'pl.latexindent'
-    lookForThis: 0
-    when: before
-
-# fineTuning allows you to tweak the internal pattern matching that
-# is central to latexindent.pl
-fineTuning:
-    environments:
-      name: '[a-zA-Z@\*0-9_\\]+'
-    ifElseFi:
-      name: '(?!@?if[a-zA-Z@]*?\{)@?if[a-zA-Z@]*?'
-    commands:
-      name: '[+a-zA-Z@\*0-9_\:]+?'
-    items:
-      canBeFollowedBy: '(?:\[[^]]*?\])|(?:<[^>]*?>)'
-    keyEqualsValuesBracesBrackets:
-      name: '[a-zA-Z@\*0-9_\/.:\#-]+[a-zA-Z@\*0-9_\/.\h\{\}:\#-]*?'
-      follow: '(?:(?<!\\)\{)|,|(?:(?<!\\)\[)'
-    namedGroupingBracesBrackets:
-      name: '[0-9\.a-zA-Z@\*><]+?'
-      follow: '\h|\R|\{|\[|\$|\)|\('
-    UnNamedGroupingBracesBrackets:
-      follow: '\{|\[|,|&|\)|\(|\$'
-    arguments:
-      before: '(?:#\d\h*;?,?\/?)+|\<.*?\>'
-      between: '_|\^|\*'
-    trailingComments:
-      notPreceededBy: '(?<!\\)'
-    modifyLineBreaks:
-      doubleBackSlash: '\\\\(?:\h*\[\h*\d+\h*[a-zA-Z]+\h*\])?'
-      comma: ','
-      betterFullStop: |-
-        (?x)                                # ignore spaces in the below
-        (?:                                 #
-          \.\)                              # .)
-          (?!\h*[a-z])                      # not *followed by* a-z
-        )                                   #
-        |                                   # OR
-        (?:                                 #
-          (?<!                              # not *preceeded by*
-            (?:                             #
-              (?:[eE]\.[gG])                # e.g OR E.g OR e.G OR E.G
-              |                             #
-              (?:[iI]\.[eE])                # i.e OR I.e OR i.E OR I.E
-              |                             #
-              (?:etc)                       # etc
-            )                               #
-          )                                 #
-        )                                   #
-        \.                                  # .
-        (?!                                 # not *followed by*
-          (?:                               #
-            [a-zA-Z0-9-~,]                  #
-            |                               #
-            \),                             # ),
-            |                               #
-            \)\.                            # ).
-          )                                 #
-        )                                   #
diff --git a/modules/home.legacy/conf/mail/accounts/soispha.nix b/modules/home.legacy/conf/mail/accounts/soispha.nix
index 3f952ebf..6bcb0da6 100644
--- a/modules/home.legacy/conf/mail/accounts/soispha.nix
+++ b/modules/home.legacy/conf/mail/accounts/soispha.nix
@@ -42,11 +42,11 @@
   #   };
   # };
   smtp = {
-    host = "mail.vhack.eu";
+    host = "mail.foss-syndicate.org";
     port = 465;
   };
   imap = {
-    host = "mail.vhack.eu";
+    host = "mail.foss-syndicate.org";
     port = 993;
   };
   jmap = {
diff --git a/modules/home.legacy/conf/mail/default.nix b/modules/home.legacy/conf/mail/default.nix
index 17957c82..1805606c 100644
--- a/modules/home.legacy/conf/mail/default.nix
+++ b/modules/home.legacy/conf/mail/default.nix
@@ -58,5 +58,5 @@ in {
     inherit accounts;
   };
 
-  programs.git.extraConfig = accountCredentials;
+  programs.git.settings = accountCredentials;
 }
diff --git a/modules/home.legacy/conf/mako/default.nix b/modules/home.legacy/conf/mako/default.nix
deleted file mode 100644
index 60400987..00000000
--- a/modules/home.legacy/conf/mako/default.nix
+++ /dev/null
@@ -1,49 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  services.mako = {
-    enable = true;
-    backgroundColor = "#2e3440";
-    borderColor = "#88c0d0";
-    borderRadius = 25;
-    borderSize = 2;
-    defaultTimeout = 5000;
-    font = "Source Code Pro 10";
-    width = 500;
-    height = 500;
-    icons = true;
-    ignoreTimeout = true;
-    layer = "overlay";
-    markup = true; # TODO:
-    maxIconSize = 64;
-    sort = "-time";
-    extraConfig = ''
-      [urgency=low]
-      border-color=#cccccc
-
-      [urgency=normal]
-      border-color=#d08770
-
-      [urgency=high]
-      border-size=3
-      border-color=#bf616a
-      default-timeout=0
-
-      [urgency=critical]
-      border-size=4
-      border-color=#bf616a
-      default-timeout=0
-
-      [category=mpd]
-      default-timeout=2000
-      group-by=category
-    '';
-  };
-}
diff --git a/modules/home.legacy/conf/nix-index/default.nix b/modules/home.legacy/conf/nix-index/default.nix
deleted file mode 100644
index 7b84d777..00000000
--- a/modules/home.legacy/conf/nix-index/default.nix
+++ /dev/null
@@ -1,23 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  programs.nix-index = {
-    enable = true;
-    symlinkToCacheHome = true;
-
-    # Handled by myself (and the script is overridden)
-    enableBashIntegration = false;
-    enableZshIntegration = false;
-    enableFishIntegration = false;
-  };
-  programs.nix-index-database = {
-    comma.enable = false;
-  };
-}
diff --git a/modules/home.legacy/conf/rclone/default.nix b/modules/home.legacy/conf/rclone/default.nix
deleted file mode 100644
index 87de601b..00000000
--- a/modules/home.legacy/conf/rclone/default.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  xdg.configFile."rclone/rclone.conf".source = ./rclone.conf;
-}
diff --git a/modules/home.legacy/conf/rclone/rclone.conf b/modules/home.legacy/conf/rclone/rclone.conf
deleted file mode 100644
index 9e1c4f08..00000000
--- a/modules/home.legacy/conf/rclone/rclone.conf
+++ /dev/null
@@ -1,10 +0,0 @@
-[vhack1]
-type = sftp
-host = server1.vhack.eu
-user = soispha
-key_use_agent = true
-known_hosts_file = ~/.local/share/ssh/known_hosts
-shell_type = unix
-md5sum_command = md5sum
-sha1sum_command = sha1sum
-
diff --git a/modules/home.legacy/conf/rclone/rclone.conf.license b/modules/home.legacy/conf/rclone/rclone.conf.license
deleted file mode 100644
index eae6a84c..00000000
--- a/modules/home.legacy/conf/rclone/rclone.conf.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/modules/home.legacy/conf/rofi/default.nix b/modules/home.legacy/conf/rofi/default.nix
deleted file mode 100644
index 3de22ea0..00000000
--- a/modules/home.legacy/conf/rofi/default.nix
+++ /dev/null
@@ -1,19 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{pkgs, ...}: {
-  programs.rofi = {
-    enable = true;
-    package = pkgs.rofi-wayland;
-    terminal = "${pkgs.alacritty}/bin/alacritty";
-    # show-icons = true;
-    # location = "center";
-    theme = ./nord-twoLines.rasi;
-  };
-}
diff --git a/modules/home.legacy/conf/starship/default.nix b/modules/home.legacy/conf/starship/default.nix
index 8d408141..6a6938f7 100644
--- a/modules/home.legacy/conf/starship/default.nix
+++ b/modules/home.legacy/conf/starship/default.nix
@@ -10,20 +10,24 @@
 {
   lib,
   nixosConfig,
+  pkgs,
   ...
 }: {
   programs.starship = {
     enable = true;
     enableZshIntegration = true;
+
     settings = {
       add_newline = false;
       format = lib.concatStrings [
         "$directory"
         "$username"
+        "\${custom.in_nixos_shell}"
         "$cmd_duration"
         "$status"
         "$character"
       ];
+
       right_format = lib.concatStrings (
         [
           "$git_metrics"
@@ -37,24 +41,30 @@
         nixosConfig.soispha.laptop.enable
         "$battery"
       );
+
       scan_timeout = 20;
+
       character = {
         # success_symbol = "[❯](bold blue)";
         # a = "⬢";
         success_symbol = "[](bold blue)";
         error_symbol = "[](bold red)";
       };
+
       status = {
         disabled = false;
         format = "([($common_meaning )($status)( $signal_name)]($style) )";
       };
+
       time = {
         disabled = false;
         format = "[\\[$time\\]]($style)";
       };
+
       username = {
         format = "as [$user]($style) ";
       };
+
       git_branch = {
         format = "[($symbol$branch(:$remote_branch) )]($style)";
       };
@@ -85,22 +95,28 @@
         tag_symbol = "v";
         format = "[(\\[$tag\\] )]($style)";
       };
+
       directory = {
         truncate_to_repo = true;
         read_only = " 󰌾";
         before_repo_root_style = "black bold dimmed";
       };
+
       cmd_duration = {
         min_time = 2000; # Milliseconds
         style = "bold white";
       };
+
       custom = {
-        # status_output = {
-        #   format = "$output";
-        #   command = "if test $STARSHIP_CMD_STATUS -ne 0; then echo \"bold red\"; else echo \"bold cyan\"; fi";
-        #   shell = [ "${pkgs.dash}" ];
-        # };
+        in_nixos_shell = {
+          symbol = "VM ";
+          style = "bold white";
+          when = ''test "$IN_NIXOS_SHELL" = true '';
+          shell = ["${lib.getExe pkgs.dash}"];
+          description = "Show if a shell is run in a vm";
+        };
       };
+
       battery = {
         # '󰁹 '
         #   '󰂄 '
diff --git a/modules/home.legacy/conf/tridactyl/config.vim b/modules/home.legacy/conf/tridactyl/config.vim
deleted file mode 100644
index aa843bc8..00000000
--- a/modules/home.legacy/conf/tridactyl/config.vim
+++ /dev/null
@@ -1,57 +0,0 @@
-" nixos-config - My current NixOS configuration
-"
-" Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-" SPDX-License-Identifier: GPL-3.0-or-later
-"
-" This file is part of my nixos-config.
-"
-" You should have received a copy of the License along with this program.
-" If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-" vim: filetype=vim
-
-" This wipes all existing settings. This means that if a setting in this file
-" is removed, then it will return to default. In other words, this file serves
-" as an enforced single point of truth for Tridactyl's configuration.
-sanitize tridactyllocal tridactylsync
-
-" Just use a blank page for new tab. It would be nicer to use the standard
-" Firefox homepage, but Tridactyl doesn't support this yet.
-"TODO: use custome file
-"set newtab file:///home/soispha/new.html
-
-" Set a nice colorscheme
-colorscheme midnight
-
-" Delete temp files after use
-alias editor_rm composite editor | jsb -p tri.native.run(`rm -f '${JS_ARG[0]}'`)
-bind --mode=insert <C-i> editor_rm
-bind --mode=input <C-i> editor_rm
-
-" Use vim in tmux for editor.
-set editorcmd alacritty -e nvim
-
-" Ctrl-F should use the browser's native 'find' functionality.
-unbind <C-f>
-
-" But also support Tridactyl search too.
-bind / fillcmdline find
-bind ? fillcmdline find -?
-bind l findnext 1
-bind L findnext -1
-" Remove search highlighting.
-bind ,<Space> nohlsearch
-" Use sensitive case. Smart case would be nice here, but it doesn't work.
-set findcase smartcase
-
-" Smooth scrolling, yes please. This is still a bit janky in Tridactyl.
-set smoothscroll true
-
-" The default jump of 10 is a bit much.
-bind t scrollline 5
-bind n scrollline -5
-
-" K and J should move between tabs. x should close them.
-bind T tabprev
-bind N tabnext
-bind x tabclose
diff --git a/modules/home.legacy/conf/tridactyl/default.nix b/modules/home.legacy/conf/tridactyl/default.nix
deleted file mode 100644
index de92c665..00000000
--- a/modules/home.legacy/conf/tridactyl/default.nix
+++ /dev/null
@@ -1,12 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{...}: {
-  xdg.configFile."tridactyl/tridactylrc".source = ./config.vim;
-}
diff --git a/modules/home.legacy/default.nix b/modules/home.legacy/default.nix
index fed2ecf6..8fb209f3 100644
--- a/modules/home.legacy/default.nix
+++ b/modules/home.legacy/default.nix
@@ -7,13 +7,7 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  nixVim,
-  nix-index-database,
-  arkenfox-nixos,
-  config,
-  ...
-}: let
+{config, ...}: let
   inherit (config.home) homeDirectory;
 
   # xdg
@@ -28,10 +22,6 @@ in {
     ./conf
     ./files
     ./pkgs
-
-    nixVim.homeManagerModules.nixvim
-    nix-index-database.hmModules.nix-index
-    arkenfox-nixos.hmModules.arkenfox
   ];
 
   # I don't know what this does, but I've seen it a lot online, so it should be good, right?
@@ -50,7 +40,7 @@ in {
       enable = true;
       createDirectories = true;
       desktop = null;
-      documents = "${homeDirectory}/school/general";
+      documents = "${homeDirectory}/documents/general";
       download = "/tmp/download";
       music = "${homeDirectory}/media/music";
       pictures = "${homeDirectory}/media/pictures";
diff --git a/pkgs/by-name/co/con2pdf/con2pdf.sh b/pkgs/by-name/co/con2pdf/con2pdf.sh
index dbcef77d..ebe35ad3 100755
--- a/pkgs/by-name/co/con2pdf/con2pdf.sh
+++ b/pkgs/by-name/co/con2pdf/con2pdf.sh
@@ -51,7 +51,7 @@ ARGUMENTS:
     NUM | *([0-9]) := 0 | 1 | 2 | 3 | 4
                             Possible numbers of pages, can be more than 4
 
-    DEVICE := [[$(cat %DEVICE_FUNCTION)]]
+    DEVICE := [[$(cat "$DEVICE_FUNCTION")]]
                             Possible scanner names
 
     METHOD := ADF | Flatbed
diff --git a/pkgs/by-name/fu/fupdate-flake/fupdate-flake.sh b/pkgs/by-name/fu/fupdate-flake/fupdate-flake.sh
index 5b8da3ce..00c1e443 100755
--- a/pkgs/by-name/fu/fupdate-flake/fupdate-flake.sh
+++ b/pkgs/by-name/fu/fupdate-flake/fupdate-flake.sh
@@ -169,7 +169,7 @@ update() {
     "$update_script" "$@"
 
     if [ -f "flake.lock" ] && grep '[^0-9]_[0-9]' flake.lock --quiet; then
-        batgrep '[^0-9]_[0-9]' flake.lock
+        grep '[^0-9]_[0-9]' flake.lock
         die "Your flake.nix contains duplicate inputs!"
     fi
 }
@@ -189,6 +189,6 @@ main() {
     fi
 }
 
-main
+main "$@"
 
 # vim: ft=sh
diff --git a/pkgs/by-name/fu/fupdate-flake/package.nix b/pkgs/by-name/fu/fupdate-flake/package.nix
index c8646f26..4e21cd23 100644
--- a/pkgs/by-name/fu/fupdate-flake/package.nix
+++ b/pkgs/by-name/fu/fupdate-flake/package.nix
@@ -13,9 +13,6 @@
   coreutils,
   fd,
   gnugrep,
-  bat-extras, # For `batgrep`
-  bat, # used by batgrep
-  gnused, # required by batgrep
   git,
 }:
 writeShellApplication {
@@ -29,9 +26,6 @@ writeShellApplication {
     coreutils
     fd
     gnugrep
-    bat-extras.batgrep
-    bat # Used by `batgrep`
-    gnused # Required by `batgrep`
     git
   ];
 }
diff --git a/pkgs/by-name/fu/fupdate-sys/fupdate-sys.sh b/pkgs/by-name/fu/fupdate-sys/fupdate-sys.sh
index 4ec3e9e8..57ced766 100755
--- a/pkgs/by-name/fu/fupdate-sys/fupdate-sys.sh
+++ b/pkgs/by-name/fu/fupdate-sys/fupdate-sys.sh
@@ -151,7 +151,7 @@ msg2 "Updating git repository..."
 git pull --rebase
 
 # We use a tempfile, to make this truly async.
-default_branch=$(mktemp)
+default_branch=$(mktemp -t fupdate_flake_XXXX)
 cleanup() {
     rm "$default_branch"
 }
diff --git a/pkgs/by-name/fu/fupdate/Cargo.lock b/pkgs/by-name/fu/fupdate/Cargo.lock
index d93cda59..9e72636a 100644
--- a/pkgs/by-name/fu/fupdate/Cargo.lock
+++ b/pkgs/by-name/fu/fupdate/Cargo.lock
@@ -1,3 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
 # nixos-config - My current NixOS configuration
 #
 # Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
@@ -7,16 +9,13 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
 version = 4
 
 [[package]]
 name = "anstream"
-version = "0.6.18"
+version = "0.6.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -29,50 +28,50 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.10"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
 dependencies = [
  "anstyle",
- "once_cell",
- "windows-sys",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.98"
+version = "1.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
 
 [[package]]
 name = "clap"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -80,9 +79,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
 dependencies = [
  "anstream",
  "anstyle",
@@ -92,9 +91,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.47"
+version = "4.5.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6"
+checksum = "430b4dc2b5e3861848de79627b2bedc9f3342c7da5173a14eaa5d0f8dc18ae5d"
 dependencies = [
  "clap",
  "clap_lex",
@@ -104,9 +103,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.32"
+version = "4.5.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -116,15 +115,15 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.7.4"
+version = "0.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
 
 [[package]]
 name = "fupdate"
@@ -143,39 +142,39 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "is_executable"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2"
+checksum = "baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4"
 dependencies = [
- "winapi",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
 name = "is_terminal_polyfill"
-version = "1.70.1"
+version = "1.70.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
 
 [[package]]
-name = "once_cell"
-version = "1.21.3"
+name = "once_cell_polyfill"
+version = "1.70.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
 dependencies = [
  "proc-macro2",
 ]
@@ -194,9 +193,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -205,9 +204,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.18"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
 
 [[package]]
 name = "utf8parse"
@@ -216,42 +215,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
-name = "winapi"
-version = "0.3.9"
+name = "windows-link"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
 
 [[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
+name = "windows-sys"
+version = "0.60.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets",
+]
 
 [[package]]
 name = "windows-sys"
-version = "0.59.0"
+version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
 dependencies = [
- "windows-targets",
+ "windows-link",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.52.6"
+version = "0.53.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
 dependencies = [
+ "windows-link",
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
@@ -264,48 +257,48 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
diff --git a/pkgs/by-name/fu/fupdate/Cargo.toml b/pkgs/by-name/fu/fupdate/Cargo.toml
index daeea6ec..b62cee51 100644
--- a/pkgs/by-name/fu/fupdate/Cargo.toml
+++ b/pkgs/by-name/fu/fupdate/Cargo.toml
@@ -16,9 +16,9 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-anyhow = "1.0.98"
-clap = { version = "4.5.37", features = ["derive"] }
-clap_complete = { version = "4.5.47", features = ["unstable-dynamic"] }
+anyhow = "1.0.100"
+clap = { version = "4.5.54", features = ["derive"] }
+clap_complete = { version = "4.5.65", features = ["unstable-dynamic"] }
 
 [profile.release]
 lto = true
diff --git a/pkgs/by-name/fu/fupdate/flake.lock b/pkgs/by-name/fu/fupdate/flake.lock
index 07eb6b21..1e997998 100644
--- a/pkgs/by-name/fu/fupdate/flake.lock
+++ b/pkgs/by-name/fu/fupdate/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1745377448,
-        "narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
+        "lastModified": 1768661221,
+        "narHash": "sha256-MJwOjrIISfOpdI9x4C+5WFQXvHtOuj5mqLZ4TMEtk1M=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
+        "rev": "3327b113f2ef698d380df83fbccefad7e83d7769",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/fu/fupdate/flake.nix b/pkgs/by-name/fu/fupdate/flake.nix
index 0ebceece..f06e27ec 100644
--- a/pkgs/by-name/fu/fupdate/flake.nix
+++ b/pkgs/by-name/fu/fupdate/flake.nix
@@ -19,13 +19,13 @@
     pkgs = nixpkgs.legacyPackages."${system}";
   in {
     devShells."${system}".default = pkgs.mkShell {
-      packages = with pkgs; [
-        cargo
-        clippy
-        rustc
-        rustfmt
+      packages =  [
+        pkgs.cargo
+        pkgs.clippy
+        pkgs.rustc
+        pkgs.rustfmt
 
-        cargo-edit
+        pkgs.cargo-edit
       ];
     };
   };
diff --git a/pkgs/by-name/fu/fupdate/src/main.rs b/pkgs/by-name/fu/fupdate/src/main.rs
index e664628a..b4af6cd6 100644
--- a/pkgs/by-name/fu/fupdate/src/main.rs
+++ b/pkgs/by-name/fu/fupdate/src/main.rs
@@ -33,16 +33,12 @@ fn main() -> Result<(), anyhow::Error> {
 
         // println!("Running: `fupdate-{command} {}`", args.join(" "));
 
-        let mut child = Command::new(format!("fupdate-{command}"))
+        let child = Command::new(format!("fupdate-{command}"))
             .args(args)
-            .spawn()
+            .status()
             .with_context(|| format!("Failed to spawn `fupdate-{command}`"))?;
 
-        if !child
-            .wait()
-            .with_context(|| format!("Failed to wait for `fupdate-{command}` to finish"))?
-            .success()
-        {
+        if !child.success() {
             bail!("Command `fupdate-{command} {}` failed!", args.join(" "));
         }
     }
@@ -50,7 +46,12 @@ fn main() -> Result<(), anyhow::Error> {
     Ok(())
 }
 
-#[test]
-fn verify_cli() {
-    CliArgs::command().debug_assert();
+#[cfg(test)]
+mod test {
+    use clap::CommandFactory;
+
+    #[test]
+    fn verify_cli() {
+        super::CliArgs::command().debug_assert();
+    }
 }
diff --git a/pkgs/by-name/fu/fupdate/update.sh b/pkgs/by-name/fu/fupdate/update.sh
index 0b170ec8..8e36e13e 100755
--- a/pkgs/by-name/fu/fupdate/update.sh
+++ b/pkgs/by-name/fu/fupdate/update.sh
@@ -10,4 +10,5 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-cargo update && cargo upgrade
+[ "$1" = "upgrade" ] && cargo upgrade
+cargo update
diff --git a/pkgs/by-name/ge/generate_moz_extension/Cargo.lock b/pkgs/by-name/ge/generate_moz_extension/Cargo.lock
deleted file mode 100644
index c2ad71e9..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/Cargo.lock
+++ /dev/null
@@ -1,1662 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 4
-
-[[package]]
-name = "addr2line"
-version = "0.24.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
-dependencies = [
- "gimli",
-]
-
-[[package]]
-name = "adler2"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
-
-[[package]]
-name = "anyhow"
-version = "1.0.98"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
-
-[[package]]
-name = "atomic-waker"
-version = "1.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
-
-[[package]]
-name = "autocfg"
-version = "1.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
-
-[[package]]
-name = "backtrace"
-version = "0.3.74"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
-dependencies = [
- "addr2line",
- "cfg-if",
- "libc",
- "miniz_oxide",
- "object",
- "rustc-demangle",
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "base64"
-version = "0.22.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
-
-[[package]]
-name = "bitflags"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
-
-[[package]]
-name = "bumpalo"
-version = "3.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
-
-[[package]]
-name = "bytes"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
-
-[[package]]
-name = "cc"
-version = "1.2.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
-dependencies = [
- "shlex",
-]
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-
-[[package]]
-name = "displaydoc"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "encoding_rs"
-version = "0.8.35"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
-name = "equivalent"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
-
-[[package]]
-name = "errno"
-version = "0.3.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
-dependencies = [
- "libc",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "fastrand"
-version = "2.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
-
-[[package]]
-name = "fnv"
-version = "1.0.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
-
-[[package]]
-name = "foreign-types"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-dependencies = [
- "foreign-types-shared",
-]
-
-[[package]]
-name = "foreign-types-shared"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-
-[[package]]
-name = "form_urlencoded"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
-dependencies = [
- "percent-encoding",
-]
-
-[[package]]
-name = "futures"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-executor",
- "futures-io",
- "futures-sink",
- "futures-task",
- "futures-util",
-]
-
-[[package]]
-name = "futures-channel"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
-dependencies = [
- "futures-core",
- "futures-sink",
-]
-
-[[package]]
-name = "futures-core"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
-
-[[package]]
-name = "futures-executor"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
-dependencies = [
- "futures-core",
- "futures-task",
- "futures-util",
-]
-
-[[package]]
-name = "futures-io"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
-
-[[package]]
-name = "futures-macro"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "futures-sink"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
-
-[[package]]
-name = "futures-task"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
-
-[[package]]
-name = "futures-util"
-version = "0.3.31"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
-dependencies = [
- "futures-channel",
- "futures-core",
- "futures-io",
- "futures-macro",
- "futures-sink",
- "futures-task",
- "memchr",
- "pin-project-lite",
- "pin-utils",
- "slab",
-]
-
-[[package]]
-name = "generate_extensions"
-version = "0.1.0"
-dependencies = [
- "anyhow",
- "futures",
- "reqwest",
- "serde",
- "serde_json",
- "tokio",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
-]
-
-[[package]]
-name = "getrandom"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
-dependencies = [
- "cfg-if",
- "libc",
- "r-efi",
- "wasi 0.14.2+wasi-0.2.4",
-]
-
-[[package]]
-name = "gimli"
-version = "0.31.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
-
-[[package]]
-name = "h2"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633"
-dependencies = [
- "atomic-waker",
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.15.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
-
-[[package]]
-name = "http"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565"
-dependencies = [
- "bytes",
- "fnv",
- "itoa",
-]
-
-[[package]]
-name = "http-body"
-version = "1.0.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
-dependencies = [
- "bytes",
- "http",
-]
-
-[[package]]
-name = "http-body-util"
-version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a"
-dependencies = [
- "bytes",
- "futures-core",
- "http",
- "http-body",
- "pin-project-lite",
-]
-
-[[package]]
-name = "httparse"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87"
-
-[[package]]
-name = "hyper"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "itoa",
- "pin-project-lite",
- "smallvec",
- "tokio",
- "want",
-]
-
-[[package]]
-name = "hyper-rustls"
-version = "0.27.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2"
-dependencies = [
- "futures-util",
- "http",
- "hyper",
- "hyper-util",
- "rustls",
- "rustls-pki-types",
- "tokio",
- "tokio-rustls",
- "tower-service",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
-dependencies = [
- "bytes",
- "http-body-util",
- "hyper",
- "hyper-util",
- "native-tls",
- "tokio",
- "tokio-native-tls",
- "tower-service",
-]
-
-[[package]]
-name = "hyper-util"
-version = "0.1.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-util",
- "http",
- "http-body",
- "hyper",
- "libc",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
-]
-
-[[package]]
-name = "icu_collections"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
-dependencies = [
- "displaydoc",
- "yoke",
- "zerofrom",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
-dependencies = [
- "displaydoc",
- "litemap",
- "tinystr",
- "writeable",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_locid_transform_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform_data"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
-
-[[package]]
-name = "icu_normalizer"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
-dependencies = [
- "displaydoc",
- "icu_collections",
- "icu_normalizer_data",
- "icu_properties",
- "icu_provider",
- "smallvec",
- "utf16_iter",
- "utf8_iter",
- "write16",
- "zerovec",
-]
-
-[[package]]
-name = "icu_normalizer_data"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
-
-[[package]]
-name = "icu_properties"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
-dependencies = [
- "displaydoc",
- "icu_collections",
- "icu_locid_transform",
- "icu_properties_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_properties_data"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
-
-[[package]]
-name = "icu_provider"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_provider_macros",
- "stable_deref_trait",
- "tinystr",
- "writeable",
- "yoke",
- "zerofrom",
- "zerovec",
-]
-
-[[package]]
-name = "icu_provider_macros"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "idna"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
-dependencies = [
- "idna_adapter",
- "smallvec",
- "utf8_iter",
-]
-
-[[package]]
-name = "idna_adapter"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
-dependencies = [
- "icu_normalizer",
- "icu_properties",
-]
-
-[[package]]
-name = "indexmap"
-version = "2.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
-dependencies = [
- "equivalent",
- "hashbrown",
-]
-
-[[package]]
-name = "ipnet"
-version = "2.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
-
-[[package]]
-name = "itoa"
-version = "1.0.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
-
-[[package]]
-name = "js-sys"
-version = "0.3.77"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
-dependencies = [
- "once_cell",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "libc"
-version = "0.2.172"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
-
-[[package]]
-name = "litemap"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
-
-[[package]]
-name = "log"
-version = "0.4.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
-
-[[package]]
-name = "memchr"
-version = "2.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
-
-[[package]]
-name = "mime"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-
-[[package]]
-name = "miniz_oxide"
-version = "0.8.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
-dependencies = [
- "adler2",
-]
-
-[[package]]
-name = "mio"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
-dependencies = [
- "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "native-tls"
-version = "0.2.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
-dependencies = [
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
-[[package]]
-name = "object"
-version = "0.36.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
-dependencies = [
- "memchr",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.21.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
-
-[[package]]
-name = "openssl"
-version = "0.10.72"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da"
-dependencies = [
- "bitflags",
- "cfg-if",
- "foreign-types",
- "libc",
- "once_cell",
- "openssl-macros",
- "openssl-sys",
-]
-
-[[package]]
-name = "openssl-macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "openssl-probe"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
-
-[[package]]
-name = "openssl-sys"
-version = "0.9.107"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07"
-dependencies = [
- "cc",
- "libc",
- "pkg-config",
- "vcpkg",
-]
-
-[[package]]
-name = "percent-encoding"
-version = "2.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
-
-[[package]]
-name = "pin-project-lite"
-version = "0.2.16"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
-
-[[package]]
-name = "pin-utils"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
-
-[[package]]
-name = "pkg-config"
-version = "0.3.32"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
-
-[[package]]
-name = "proc-macro2"
-version = "1.0.95"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "quote"
-version = "1.0.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
-dependencies = [
- "proc-macro2",
-]
-
-[[package]]
-name = "r-efi"
-version = "5.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
-
-[[package]]
-name = "reqwest"
-version = "0.12.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb"
-dependencies = [
- "base64",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "http-body-util",
- "hyper",
- "hyper-rustls",
- "hyper-tls",
- "hyper-util",
- "ipnet",
- "js-sys",
- "log",
- "mime",
- "native-tls",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper",
- "system-configuration",
- "tokio",
- "tokio-native-tls",
- "tower",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "windows-registry",
-]
-
-[[package]]
-name = "ring"
-version = "0.17.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
-dependencies = [
- "cc",
- "cfg-if",
- "getrandom 0.2.16",
- "libc",
- "untrusted",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "rustc-demangle"
-version = "0.1.24"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
-
-[[package]]
-name = "rustix"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf"
-dependencies = [
- "bitflags",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "rustls"
-version = "0.23.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0"
-dependencies = [
- "once_cell",
- "rustls-pki-types",
- "rustls-webpki",
- "subtle",
- "zeroize",
-]
-
-[[package]]
-name = "rustls-pemfile"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
-dependencies = [
- "rustls-pki-types",
-]
-
-[[package]]
-name = "rustls-pki-types"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c"
-
-[[package]]
-name = "rustls-webpki"
-version = "0.103.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03"
-dependencies = [
- "ring",
- "rustls-pki-types",
- "untrusted",
-]
-
-[[package]]
-name = "rustversion"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
-
-[[package]]
-name = "ryu"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
-
-[[package]]
-name = "schannel"
-version = "0.1.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d"
-dependencies = [
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "security-framework"
-version = "2.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
-dependencies = [
- "bitflags",
- "core-foundation",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "serde"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
-dependencies = [
- "serde_derive",
-]
-
-[[package]]
-name = "serde_derive"
-version = "1.0.219"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "serde_json"
-version = "1.0.140"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
-dependencies = [
- "itoa",
- "memchr",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "serde_urlencoded"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
-dependencies = [
- "form_urlencoded",
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
-name = "shlex"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
-
-[[package]]
-name = "slab"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
-dependencies = [
- "autocfg",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
-
-[[package]]
-name = "socket2"
-version = "0.5.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
-dependencies = [
- "libc",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "stable_deref_trait"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
-
-[[package]]
-name = "subtle"
-version = "2.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
-
-[[package]]
-name = "syn"
-version = "2.0.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "sync_wrapper"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263"
-dependencies = [
- "futures-core",
-]
-
-[[package]]
-name = "synstructure"
-version = "0.13.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "system-configuration"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
-dependencies = [
- "bitflags",
- "core-foundation",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
-name = "tempfile"
-version = "3.19.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
-dependencies = [
- "fastrand",
- "getrandom 0.3.2",
- "once_cell",
- "rustix",
- "windows-sys 0.59.0",
-]
-
-[[package]]
-name = "tinystr"
-version = "0.7.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
-dependencies = [
- "displaydoc",
- "zerovec",
-]
-
-[[package]]
-name = "tokio"
-version = "1.44.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48"
-dependencies = [
- "backtrace",
- "bytes",
- "libc",
- "mio",
- "pin-project-lite",
- "socket2",
- "tokio-macros",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "tokio-macros"
-version = "2.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "tokio-native-tls"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
-dependencies = [
- "native-tls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-rustls"
-version = "0.26.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b"
-dependencies = [
- "rustls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
-]
-
-[[package]]
-name = "tower"
-version = "0.5.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9"
-dependencies = [
- "futures-core",
- "futures-util",
- "pin-project-lite",
- "sync_wrapper",
- "tokio",
- "tower-layer",
- "tower-service",
-]
-
-[[package]]
-name = "tower-layer"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e"
-
-[[package]]
-name = "tower-service"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
-
-[[package]]
-name = "tracing"
-version = "0.1.41"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
-dependencies = [
- "pin-project-lite",
- "tracing-core",
-]
-
-[[package]]
-name = "tracing-core"
-version = "0.1.33"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
-dependencies = [
- "once_cell",
-]
-
-[[package]]
-name = "try-lock"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
-
-[[package]]
-name = "unicode-ident"
-version = "1.0.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
-
-[[package]]
-name = "untrusted"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
-
-[[package]]
-name = "url"
-version = "2.5.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
-dependencies = [
- "form_urlencoded",
- "idna",
- "percent-encoding",
-]
-
-[[package]]
-name = "utf16_iter"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
-
-[[package]]
-name = "utf8_iter"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
-
-[[package]]
-name = "vcpkg"
-version = "0.2.15"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
-
-[[package]]
-name = "want"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
-dependencies = [
- "try-lock",
-]
-
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
-name = "wasi"
-version = "0.14.2+wasi-0.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
-dependencies = [
- "wit-bindgen-rt",
-]
-
-[[package]]
-name = "wasm-bindgen"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
-dependencies = [
- "cfg-if",
- "once_cell",
- "rustversion",
- "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.50"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
-dependencies = [
- "cfg-if",
- "js-sys",
- "once_cell",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
-name = "wasm-bindgen-macro"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
-dependencies = [
- "quote",
- "wasm-bindgen-macro-support",
-]
-
-[[package]]
-name = "wasm-bindgen-macro-support"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "wasm-bindgen-backend",
- "wasm-bindgen-shared",
-]
-
-[[package]]
-name = "wasm-bindgen-shared"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
-dependencies = [
- "unicode-ident",
-]
-
-[[package]]
-name = "web-sys"
-version = "0.3.77"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "windows-link"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
-
-[[package]]
-name = "windows-registry"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3"
-dependencies = [
- "windows-result",
- "windows-strings",
- "windows-targets 0.53.0",
-]
-
-[[package]]
-name = "windows-result"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
-dependencies = [
- "windows-link",
-]
-
-[[package]]
-name = "windows-strings"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
-dependencies = [
- "windows-link",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.52.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.59.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
- "windows_i686_gnullvm 0.52.6",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
-dependencies = [
- "windows_aarch64_gnullvm 0.53.0",
- "windows_aarch64_msvc 0.53.0",
- "windows_i686_gnu 0.53.0",
- "windows_i686_gnullvm 0.53.0",
- "windows_i686_msvc 0.53.0",
- "windows_x86_64_gnu 0.53.0",
- "windows_x86_64_gnullvm 0.53.0",
- "windows_x86_64_msvc 0.53.0",
-]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.53.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
-
-[[package]]
-name = "wit-bindgen-rt"
-version = "0.39.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
-name = "write16"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
-
-[[package]]
-name = "writeable"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
-
-[[package]]
-name = "yoke"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
-dependencies = [
- "serde",
- "stable_deref_trait",
- "yoke-derive",
- "zerofrom",
-]
-
-[[package]]
-name = "yoke-derive"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
-[[package]]
-name = "zerofrom"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
-dependencies = [
- "zerofrom-derive",
-]
-
-[[package]]
-name = "zerofrom-derive"
-version = "0.1.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
-[[package]]
-name = "zeroize"
-version = "1.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde"
-
-[[package]]
-name = "zerovec"
-version = "0.10.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
-dependencies = [
- "yoke",
- "zerofrom",
- "zerovec-derive",
-]
-
-[[package]]
-name = "zerovec-derive"
-version = "0.10.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
diff --git a/pkgs/by-name/ge/generate_moz_extension/Cargo.toml b/pkgs/by-name/ge/generate_moz_extension/Cargo.toml
deleted file mode 100644
index 11d08177..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/Cargo.toml
+++ /dev/null
@@ -1,24 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-[package]
-name = "generate_extensions"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-anyhow = "1.0.97"
-futures = "0.3.31"
-reqwest = "0.12.15"
-serde = { version = "1.0.219", features = ["derive"] }
-serde_json = "1.0.140"
-tokio = { version = "1.44.2", features = ["macros", "rt-multi-thread"] }
diff --git a/pkgs/by-name/ge/generate_moz_extension/examples/generate_extensions.sh b/pkgs/by-name/ge/generate_moz_extension/examples/generate_extensions.sh
deleted file mode 100755
index 3e990b6d..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/examples/generate_extensions.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/bin/sh
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-tmp=$(mktemp)
-cat <<EOF | awk '!/^\s*#/' >"$tmp"
-    darkreader:navbar
-    keepassxc-browser:navbar
-    vhack-libredirect:navbar
-    # torproject-snowflake:navbar
-    tridactyl-vim:menupanel
-    ublock-origin:menupanel
-EOF
-
-# The cat execution should be unquoted;
-# shellcheck disable=SC2046
-cargo run -- $(cat "$tmp")
-
-rm "$tmp"
diff --git a/pkgs/by-name/ge/generate_moz_extension/flake.lock b/pkgs/by-name/ge/generate_moz_extension/flake.lock
deleted file mode 100644
index c004bc0c..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/flake.lock
+++ /dev/null
@@ -1,98 +0,0 @@
-{
-  "nodes": {
-    "crane": {
-      "locked": {
-        "lastModified": 1745454774,
-        "narHash": "sha256-oLvmxOnsEKGtwczxp/CwhrfmQUG2ym24OMWowcoRhH8=",
-        "owner": "ipetkov",
-        "repo": "crane",
-        "rev": "efd36682371678e2b6da3f108fdb5c613b3ec598",
-        "type": "github"
-      },
-      "original": {
-        "owner": "ipetkov",
-        "repo": "crane",
-        "type": "github"
-      }
-    },
-    "flake-utils": {
-      "inputs": {
-        "systems": "systems"
-      },
-      "locked": {
-        "lastModified": 1731533236,
-        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
-    "nixpkgs": {
-      "locked": {
-        "lastModified": 1745377448,
-        "narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixpkgs-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "root": {
-      "inputs": {
-        "crane": "crane",
-        "flake-utils": "flake-utils",
-        "nixpkgs": "nixpkgs",
-        "rust-overlay": "rust-overlay"
-      }
-    },
-    "rust-overlay": {
-      "inputs": {
-        "nixpkgs": [
-          "nixpkgs"
-        ]
-      },
-      "locked": {
-        "lastModified": 1745548521,
-        "narHash": "sha256-xyliq8oS5OnzXjHRGr92RtmrtYI/dflf2gSEo0wMFjc=",
-        "owner": "oxalica",
-        "repo": "rust-overlay",
-        "rev": "eb0afb4ac0720d55c29e88eb29432103d73ae11d",
-        "type": "github"
-      },
-      "original": {
-        "owner": "oxalica",
-        "repo": "rust-overlay",
-        "type": "github"
-      }
-    },
-    "systems": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    }
-  },
-  "root": "root",
-  "version": 7
-}
diff --git a/pkgs/by-name/ge/generate_moz_extension/flake.nix b/pkgs/by-name/ge/generate_moz_extension/flake.nix
deleted file mode 100644
index a7125642..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/flake.nix
+++ /dev/null
@@ -1,84 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  description = "A simple way to query the mozialla api for extension data";
-
-  inputs = {
-    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
-
-    crane = {
-      url = "github:ipetkov/crane";
-      inputs = {
-        nixpkgs.follows = "nixpkgs";
-      };
-    };
-
-    flake-utils.url = "github:numtide/flake-utils";
-
-    rust-overlay = {
-      url = "github:oxalica/rust-overlay";
-      inputs = {
-        nixpkgs.follows = "nixpkgs";
-        flake-utils.follows = "flake-utils";
-      };
-    };
-  };
-
-  outputs = {
-    self,
-    nixpkgs,
-    crane,
-    flake-utils,
-    rust-overlay,
-    ...
-  }:
-    flake-utils.lib.eachDefaultSystem (system: let
-      pkgs = import nixpkgs {
-        inherit system;
-        overlays = [(import rust-overlay)];
-      };
-
-      rust-stable = pkgs.rust-bin.stable.latest.default;
-      rust-minimal = pkgs.rust-bin.stable.latest.minimal;
-
-      craneLib = (crane.mkLib pkgs).overrideToolchain rust-minimal;
-
-      buildInputs = [
-        pkgs.openssl # needed for openssl
-      ];
-      nativeBuildInputs = [
-        pkgs.pkg-config # needed for openssl
-      ];
-
-      craneBuild = craneLib.buildPackage {
-        src = craneLib.cleanCargoSource ./.;
-        inherit buildInputs nativeBuildInputs;
-
-        doCheck = true;
-      };
-    in {
-      packages.default = craneBuild;
-      app.default = {
-        type = "app";
-        program = "${self.packages.${system}.default}/bin/generate_extensions";
-      };
-      devShells.default = pkgs.mkShell {
-        packages = with pkgs; [
-          cocogitto
-
-          rust-stable
-          cargo-edit
-        ];
-        inherit buildInputs nativeBuildInputs;
-      };
-    });
-}
-# vim: ts=2
-
diff --git a/pkgs/by-name/ge/generate_moz_extension/res/generate_extensions.py b/pkgs/by-name/ge/generate_moz_extension/res/generate_extensions.py
deleted file mode 100644
index a262ca77..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/res/generate_extensions.py
+++ /dev/null
@@ -1,55 +0,0 @@
-#!/usr/bin/env python
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# source: https://github.com/etu/nixconfig/blob/ba47d577c8bfb4a1c06927c34ece34118f4a0460/modules/graphical/firefox/generate.py
-
-from concurrent.futures import ThreadPoolExecutor
-import json
-import requests
-
-EXTENSIONS = sorted(
-    [
-        "darkreader",
-        "firenvim",
-        "keepassxc-browser",
-        "simple-tab-groups",
-    ]
-)
-
-
-def index_ext(ext: str):
-    # print(f"Indexing {ext}...")
-
-    resp = requests.get(f"https://addons.mozilla.org/api/v5/addons/addon/{ext}/").json()
-    rel = resp["current_version"]
-
-    if not rel["file"]["hash"].startswith("sha256:"):
-        raise ValueError("Unhandled hash type")
-
-    return {
-        "pname": ext,
-        "version": rel["version"],
-        "addonId": resp["guid"],
-        "url": rel["file"]["url"],
-        "sha256": rel["file"]["hash"],
-    }
-
-
-if __name__ == "__main__":
-    # outfile = os.path.dirname(os.path.realpath(__file__)) + "/extensions.json"
-
-    with ThreadPoolExecutor() as e:
-        extensions = {ext: e.submit(index_ext, ext) for ext in EXTENSIONS}
-        extensions = {k: v.result() for k, v in extensions.items()}
-
-    # with open(outfile, "w") as f:
-    print(json.dumps(extensions, indent=2))
diff --git a/pkgs/by-name/ge/generate_moz_extension/res/reference.json b/pkgs/by-name/ge/generate_moz_extension/res/reference.json
deleted file mode 100644
index f46ea8ec..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/res/reference.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  "darkreader": {
-    "pname": "darkreader",
-    "version": "4.9.62",
-    "addonId": "addon@darkreader.org",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4053589/darkreader-4.9.62.xpi",
-    "sha256": "sha256:e537a2cee45ed7c26f79ecd3ed362620e3f00d24c158532a58e163a63a3d60cc"
-  },
-  "firenvim": {
-    "pname": "firenvim",
-    "version": "0.2.14",
-    "addonId": "firenvim@lacamb.re",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4026386/firenvim-0.2.14.xpi",
-    "sha256": "sha256:a8c495a59e30eaabbb3fcd188db9b5e28b40bffefe41a3f0fa22ecc58c80c2b6"
-  },
-  "keepassxc-browser": {
-    "pname": "keepassxc-browser",
-    "version": "1.8.4",
-    "addonId": "keepassxc-browser@keepassxc.org",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4045866/keepassxc_browser-1.8.4.xpi",
-    "sha256": "sha256:cc39aa058cb8915cfc88424e2e1cebe3ccfc3f95d7bddb2abd0c4905d2b17719"
-  },
-  "simple-tab-groups": {
-    "pname": "simple-tab-groups",
-    "version": "4.7.2.1",
-    "addonId": "simple-tab-groups@drive4ik",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/3873608/simple_tab_groups-4.7.2.1.xpi",
-    "sha256": "sha256:75077589098ca62c00b86cf9554c6120bf8dc04c5f916fe26f84915f5147b2a4"
-  }
-}
diff --git a/pkgs/by-name/ge/generate_moz_extension/res/reference.json.license b/pkgs/by-name/ge/generate_moz_extension/res/reference.json.license
deleted file mode 100644
index eae6a84c..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/res/reference.json.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/pkgs/by-name/ge/generate_moz_extension/res/test.json b/pkgs/by-name/ge/generate_moz_extension/res/test.json
deleted file mode 100644
index daa1d19a..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/res/test.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  "darkreader": {
-    "addon_id": "addon@darkreader.org",
-    "pname": "darkreader",
-    "sha256": "sha256:e537a2cee45ed7c26f79ecd3ed362620e3f00d24c158532a58e163a63a3d60cc",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4053589/darkreader-4.9.62.xpi",
-    "version": "4.9.62"
-  },
-  "firenvim": {
-    "addon_id": "firenvim@lacamb.re",
-    "pname": "firenvim",
-    "sha256": "sha256:a8c495a59e30eaabbb3fcd188db9b5e28b40bffefe41a3f0fa22ecc58c80c2b6",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4026386/firenvim-0.2.14.xpi",
-    "version": "0.2.14"
-  },
-  "keepassxc-browser": {
-    "addon_id": "keepassxc-browser@keepassxc.org",
-    "pname": "keepassxc-browser",
-    "sha256": "sha256:cc39aa058cb8915cfc88424e2e1cebe3ccfc3f95d7bddb2abd0c4905d2b17719",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/4045866/keepassxc_browser-1.8.4.xpi",
-    "version": "1.8.4"
-  },
-  "simple-tab-groups": {
-    "addon_id": "simple-tab-groups@drive4ik",
-    "pname": "simple-tab-groups",
-    "sha256": "sha256:75077589098ca62c00b86cf9554c6120bf8dc04c5f916fe26f84915f5147b2a4",
-    "url": "https://addons.mozilla.org/firefox/downloads/file/3873608/simple_tab_groups-4.7.2.1.xpi",
-    "version": "4.7.2.1"
-  }
-}
diff --git a/pkgs/by-name/ge/generate_moz_extension/res/test.json.license b/pkgs/by-name/ge/generate_moz_extension/res/test.json.license
deleted file mode 100644
index eae6a84c..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/res/test.json.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/pkgs/by-name/ge/generate_moz_extension/src/main.rs b/pkgs/by-name/ge/generate_moz_extension/src/main.rs
deleted file mode 100644
index 58a19160..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/src/main.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-// nixos-config - My current NixOS configuration
-//
-// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of my nixos-config.
-//
-// You should have received a copy of the License along with this program.
-// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-use std::env::args;
-
-use anyhow::{bail, Context};
-use futures::StreamExt;
-use reqwest::Client;
-use serde_json::{json, Map, Value};
-
-pub mod types;
-
-macro_rules! get_json_value {
-    ($key:expr, $json_value:ident, $type:ident, $get:ident) => {
-        match $json_value.get($key) {
-            Some(resp) => {
-                let resp = resp.to_owned();
-                if resp.$type() {
-                    resp.$get().expect(
-                        "The should have been checked in the if guard, so unpacking here is fine",
-                    ).to_owned()
-                } else {
-                    bail!(
-                        "Value {} => \n{}\n is not of type: {}",
-                        $key,
-                        resp,
-                        stringify!($type)
-                    );
-                }
-            }
-            None => {
-                bail!(
-                    "There seems to be no '{}' in your json data (json value: '{}')\n Has the api changend?",
-                    $key, serde_json::to_string_pretty(&$json_value).expect("Will always work")
-                );
-            }
-        }
-    };
-}
-
-use futures::stream::futures_unordered::FuturesUnordered;
-use types::{Extension, InputExtension};
-
-#[tokio::main]
-async fn main() -> anyhow::Result<()> {
-    let mut extensions: Vec<InputExtension> = vec![];
-    for input_extension in args()
-        .skip(1)
-        .map(|str| InputExtension::try_from(str))
-        .collect::<Vec<anyhow::Result<InputExtension>>>()
-    {
-        extensions.push(input_extension?);
-    }
-
-    let resulting_extensions = process_extensions(extensions).await?;
-
-    let mut output = Map::new();
-    for extension in resulting_extensions {
-        output.insert(extension.pname.clone(), json!(extension));
-    }
-
-    println!(
-        "{}",
-        serde_json::to_string_pretty(&serde_json::Value::Object(output)).expect(
-            "This is constructed from json, it should also be possible to serialize it again"
-        )
-    );
-    Ok(())
-}
-
-async fn process_extensions(extensions: Vec<InputExtension>) -> anyhow::Result<Vec<Extension>> {
-    let mut output = Vec::with_capacity(extensions.len());
-
-    let client = Client::new();
-    for extension in extensions
-        .iter()
-        .map(|ext| {
-            let local_client = &client;
-            index_extension(ext, local_client)
-        })
-        .collect::<FuturesUnordered<_>>()
-        .collect::<Vec<_>>()
-        .await
-    {
-        output.push(extension?);
-    }
-    Ok(output)
-}
-
-async fn index_extension(extension: &InputExtension, client: &Client) -> anyhow::Result<Extension> {
-    let response = client
-        .get(format!(
-            "https://addons.mozilla.org/api/v5/addons/addon/{}",
-            extension,
-        ))
-        .send()
-        .await
-        .context("Accessing the mozzila extenios api failed with error: {e}")?;
-
-    eprintln!("Indexing {} ({})...", extension, response.status());
-    let response: Value = serde_json::from_str(
-        &response
-            .text()
-            .await
-            .context("Turning the response to text fail with error: {e}")?,
-    )
-    .context("Deserializing the response failed! Error: {e}")?;
-
-    if let Some(detail) = response.get("detail") {
-        if detail == "Not found." {
-            bail!("Your extension ('{}') was not found!", extension);
-        }
-    };
-
-    let release = { get_json_value!("current_version", response, is_object, as_object) };
-
-    #[allow(non_snake_case)]
-    let addonId = { get_json_value!("guid", response, is_string, as_str) };
-
-    let version = { get_json_value!("version", release, is_string, as_str) };
-    let file = { get_json_value!("file", release, is_object, as_object) };
-
-    let url = { get_json_value!("url", file, is_string, as_str) };
-    let sha256 = {
-        let hash = get_json_value!("hash", file, is_string, as_str);
-        if hash.starts_with("sha256:") {
-            hash
-        } else {
-            bail!("This hash type is unhandled: {}", hash);
-        }
-    };
-
-    Ok(Extension {
-        pname: extension.moz_name.clone(),
-        default_area: extension.default_area,
-        version,
-        addonId,
-        url,
-        sha256,
-    })
-}
diff --git a/pkgs/by-name/ge/generate_moz_extension/src/types.rs b/pkgs/by-name/ge/generate_moz_extension/src/types.rs
deleted file mode 100644
index 231e747c..00000000
--- a/pkgs/by-name/ge/generate_moz_extension/src/types.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// nixos-config - My current NixOS configuration
-//
-// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of my nixos-config.
-//
-// You should have received a copy of the License along with this program.
-// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-use std::fmt::Display;
-
-use anyhow::anyhow;
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize)]
-#[allow(non_snake_case)]
-pub struct Extension {
-    pub pname: String,
-    pub default_area: DefaultArea,
-    pub version: String,
-    pub addonId: String,
-    pub url: String,
-    pub sha256: String,
-}
-
-#[derive(Debug, Clone)]
-pub struct InputExtension {
-    pub moz_name: String,
-    pub default_area: DefaultArea,
-}
-#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
-#[allow(non_camel_case_types)]
-pub enum DefaultArea {
-    navbar,
-    menupanel,
-}
-
-impl Display for DefaultArea {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            DefaultArea::navbar => f.write_str("navbar"),
-            DefaultArea::menupanel => f.write_str("menupanel"),
-        }
-    }
-}
-
-impl TryFrom<&str> for DefaultArea {
-    type Error = anyhow::Error;
-
-    fn try_from(value: &str) -> Result<Self, Self::Error> {
-        match value {
-            "navbar" => Ok(Self::navbar),
-            "menupanel" => Ok(Self::menupanel),
-            _ => Err(anyhow!(
-                "Your <default_area> needs to be one of 'navbar' or 'menupanel', but is: '{}'",
-                value
-            )),
-        }
-    }
-}
-
-impl Display for InputExtension {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.write_str(&self.moz_name)
-    }
-}
-impl TryFrom<String> for InputExtension {
-    type Error = anyhow::Error;
-
-    fn try_from(value: String) -> Result<Self, Self::Error> {
-        if let Some((moz_name, default_area)) = value.split_once(':') {
-            Ok(Self {
-                moz_name: moz_name.to_owned(),
-                default_area: default_area.try_into()?,
-            })
-        } else {
-            Err(anyhow!("Can't parse the input string as a InputExtension!\n Needs to be: '<moz_name>:<default_area>'"))
-        }
-    }
-}
diff --git a/pkgs/by-name/gi/git-edit-index/git-edit-index.sh b/pkgs/by-name/gi/git-edit-index/git-edit-index.sh
index 460125b8..a9434381 100755
--- a/pkgs/by-name/gi/git-edit-index/git-edit-index.sh
+++ b/pkgs/by-name/gi/git-edit-index/git-edit-index.sh
@@ -56,7 +56,7 @@ materialize_file() {
 }
 
 edit() {
-    files_to_add="$(mktemp)"
+    files_to_add="$(mktemp -t git_edit_index_XXXXX)"
     cleanup() {
         rm "$files_to_add"
     }
@@ -78,6 +78,7 @@ edit() {
     fi
 }
 
+end_of_cli_options=false
 for arg in "$@"; do
     case "$arg" in
     "--help" | "-h")
diff --git a/pkgs/by-name/i3/i3bar-river-patched/0001-feat-crate-bar-Put-the-leftmost-block-in-the-middle-.patch b/pkgs/by-name/i3/i3bar-river-patched/0001-feat-crate-bar-Put-the-leftmost-block-in-the-middle-.patch
new file mode 100644
index 00000000..7bfdd7bc
--- /dev/null
+++ b/pkgs/by-name/i3/i3bar-river-patched/0001-feat-crate-bar-Put-the-leftmost-block-in-the-middle-.patch
@@ -0,0 +1,110 @@
+From 8ae692a461fad2f23231d50b78bb706408facfe6 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Tue, 20 May 2025 19:58:57 +0200
+Subject: [PATCH] feat(crate::bar): Put the leftmost block in the middle of the
+ bar
+
+This is a workaround for the limitation in the i3 blocks protocol, as
+this does not allow for centred blocks.
+---
+ src/bar.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 52 insertions(+), 11 deletions(-)
+
+diff --git a/src/bar.rs b/src/bar.rs
+index 96533e3..76f8025 100644
+--- a/src/bar.rs
++++ b/src/bar.rs
+@@ -338,16 +338,55 @@ impl Bar {
+         }
+ 
+         // Display the blocks
+-        render_blocks(
+-            &cairo_ctx,
+-            &ss.config,
+-            palette,
+-            ss.blocks_cache.get_computed(),
+-            &mut self.blocks_btns,
+-            offset_left,
+-            width_f,
+-            height_f,
+-        );
++        {
++            if !ss.blocks_cache.get_computed().is_empty() {
++                let first_block = &ss.blocks_cache.get_computed()[0];
++
++                let blocks = &ss.blocks_cache.get_computed()[1..];
++
++                let other_start = render_blocks(
++                    &cairo_ctx,
++                    &ss.config,
++                    palette,
++                    blocks,
++                    &mut self.blocks_btns,
++                    offset_left,
++                    width_f,
++                    height_f,
++                );
++
++                // Draw the first block _after_ the other ones, so that we can nudge it more to the
++                // left, if the others are spanning over the middle.
++                let mut start = (width_f / 2.0) - (first_block.full.width / 2.0);
++                if start + first_block.full.width > other_start {
++                    start = other_start
++                        - first_block.full.width
++                        - first_block.block.separator_block_width as f64;
++                }
++
++                first_block.full.render(
++                    &cairo_ctx,
++                    RenderOptions {
++                        x_offset: start,
++                        bar_height: height_f,
++                        fg_color: first_block.block.color.unwrap_or(palette.color),
++                        bg_color: first_block.block.background,
++                        r_left: ss.config.blocks_r,
++                        r_right: ss.config.blocks_r,
++                        overlap: ss.config.blocks_overlap,
++                    },
++                );
++
++                self.blocks_btns.push(
++                    start,
++                    first_block.full.width,
++                    (
++                        first_block.block.name.clone(),
++                        first_block.block.instance.clone(),
++                    ),
++                );
++            }
++        }
+ 
+         self.viewport
+             .set_destination(conn, self.width as i32, self.height as i32);
+@@ -422,7 +461,7 @@ fn render_blocks(
+     offset_left: f64,
+     full_width: f64,
+     full_height: f64,
+-) {
++) -> f64 {
+     context.rectangle(offset_left, 0.0, full_width - offset_left, full_height);
+     context.clip();
+ 
+@@ -507,6 +546,7 @@ fn render_blocks(
+     }
+ 
+     // Render blocks
++    let leftmost_start = full_width - blocks_width;
+     buttons.clear();
+     for series in blocks_computed {
+         let s_len = series.blocks.len();
+@@ -550,6 +590,7 @@ fn render_blocks(
+     }
+ 
+     context.reset_clip();
++    leftmost_start
+ }
+ 
+ fn layer_surface_cb(ctx: EventCtx<State, ZwlrLayerSurfaceV1>) {
+-- 
+2.49.0
+
diff --git a/pkgs/by-name/i3/i3bar-river-patched/package.nix b/pkgs/by-name/i3/i3bar-river-patched/package.nix
new file mode 100644
index 00000000..26f11ab3
--- /dev/null
+++ b/pkgs/by-name/i3/i3bar-river-patched/package.nix
@@ -0,0 +1,54 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  lib,
+  fetchFromGitHub,
+  rustPlatform,
+  pkg-config,
+  pango,
+}:
+rustPlatform.buildRustPackage {
+  pname = "i3bar-river-patched";
+  version = "1.1.0-unstable-2025-05-20";
+
+  src = fetchFromGitHub {
+    owner = "bpeetz";
+    repo = "i3bar-river";
+    rev = "d460a9a283426e9474a0034a146d09816e92f571";
+    hash = "sha256-E04b2FzEhOX5NyE/VpEGdg27Sg+1+lSSRZbGyX6PXrk=";
+  };
+
+  cargoHash = "sha256-jIB4XH67FmtPxAatHkuW8v5mNgr/KsyriaBNZ5t2dLo=";
+
+  cargoPatches = [
+    # TODO(@bpeetz): Open an issues, whether something like that could be up-streamed. <2025-05-20>
+    ./0001-feat-crate-bar-Put-the-leftmost-block-in-the-middle-.patch
+  ];
+
+  # Remove the WMs that I don't use.
+  buildNoDefaultFeatures = true;
+  buildFeatures = [
+    # "hyprland"
+    # "niri"
+    "river"
+  ];
+
+  nativeBuildInputs = [pkg-config];
+  buildInputs = [pango];
+
+  meta = with lib; {
+    description = "Port of i3bar for river";
+    homepage = "https://github.com/MaxVerevkin/i3bar-river";
+    license = licenses.gpl3Only;
+    maintainers = with maintainers; [nicegamer7];
+    mainProgram = "i3bar-river";
+    platforms = platforms.linux;
+  };
+}
diff --git a/modules/home.legacy/conf/beets/plugins/play/default.nix b/pkgs/by-name/i3/i3status-rust-patched/package.nix
index 9d26f16a..a103e275 100644
--- a/modules/home.legacy/conf/beets/plugins/play/default.nix
+++ b/pkgs/by-name/i3/i3status-rust-patched/package.nix
@@ -8,16 +8,15 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
-  lib,
-  pkgs,
-  config,
-  ...
-}: {
-  programs.beets.settings.play = {
-    command = "${lib.getExe pkgs.mpc} $args add";
-    relative_to = config.services.mpd.musicDirectory;
+  i3status-rust,
+}:
+i3status-rust.overrideAttrs (final: prev: {
+  pname = "${prev.pname}-patched";
 
-    # Run the command with the returned paths as arguments
-    raw = true;
-  };
-}
+  patches =
+    (prev.patches or [])
+    ++ [
+      # Btrfs support for disk_space block.
+      ./patches/0001-disk_space-Support-btrfs-backend.patch
+    ];
+})
diff --git a/pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch b/pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch
new file mode 100644
index 00000000..8ef0af2e
--- /dev/null
+++ b/pkgs/by-name/i3/i3status-rust-patched/patches/0001-disk_space-Support-btrfs-backend.patch
@@ -0,0 +1,190 @@
+From 78d2936b67064e3b5e700a2859d00ea3dd6eda4c Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Sun, 18 May 2025 20:22:04 +0200
+Subject: [PATCH 1/3] disk_space: Support btrfs backend
+
+Btrfs is too smart for the statvfs based backend (i.e., only counting
+blocks leads to wrong numbers).
+
+For example, a btrfs disk with a lot of de-duplicated blocks (via the copy
+on write mechanism) might have a drastically over-reported disk usage.
+
+The btrfs backend is currently implemented by parsing the output of the
+`btrfs filesystem usage --raw` command. This is suboptimal, as this now
+relies on the command output not changing.
+
+Vendoring the algorithm used internally by the `btrfs` command does not
+seem to be a reasonable alternative, considering that the code[1] is
+rather complex, low level and would require semi-constant maintenance.
+Additionally, the c code would need bindings to be usable from rust.
+
+I assume, that the `btrfs` command output will stay rather similar in
+the future, as a lot of tools rely on directly parsing it (see the
+various scripts in the issue, this commit fixes).
+
+[1]: https://github.com/kdave/btrfs-progs/blob/eeab081e9d9fbdf4583122ed1caedf541383cf2d/cmds/filesystem-usage.c#L442
+
+Fixes: #1654
+---
+ src/blocks/disk_space.rs | 112 +++++++++++++++++++++++++++++++++++----
+ 1 file changed, 101 insertions(+), 11 deletions(-)
+
+diff --git a/src/blocks/disk_space.rs b/src/blocks/disk_space.rs
+index 79bfebd27..da0d3f518 100644
+--- a/src/blocks/disk_space.rs
++++ b/src/blocks/disk_space.rs
+@@ -12,6 +12,7 @@
+ //! `alert` | A value which will trigger critical block state | `10.0`
+ //! `info_type` | Determines which information will affect the block state. Possible values are `"available"`, `"free"` and `"used"` | `"available"`
+ //! `alert_unit` | The unit of `alert` and `warning` options. If not set, percents are used. Possible values are `"B"`, `"KB"`, `"KiB"`, `"MB"`, `"MiB"`, `"GB"`, `"Gib"`, `"TB"` and `"TiB"` | `None`
++//! `backend` | The backend to use when querying disk usage. Possible values are `"vfs"` (like `du(1)`) and `"btrfs"` | `"vfs"`
+ //!
+ //! Placeholder  | Value                                                              | Type   | Unit
+ //! -------------|--------------------------------------------------------------------|--------|-------
+@@ -63,9 +64,12 @@
+ 
+ // make_log_macro!(debug, "disk_space");
+ 
++use std::cell::OnceCell;
++
+ use super::prelude::*;
+ use crate::formatting::prefix::Prefix;
+ use nix::sys::statvfs::statvfs;
++use tokio::process::Command;
+ 
+ #[derive(Copy, Clone, Debug, Deserialize, SmartDefault)]
+ #[serde(rename_all = "lowercase")]
+@@ -76,11 +80,20 @@ pub enum InfoType {
+     Used,
+ }
+ 
++#[derive(Copy, Clone, Debug, Deserialize, SmartDefault)]
++#[serde(rename_all = "lowercase")]
++pub enum Backend {
++    #[default]
++    Vfs,
++    Btrfs,
++}
++
+ #[derive(Deserialize, Debug, SmartDefault)]
+ #[serde(deny_unknown_fields, default)]
+ pub struct Config {
+     #[default("/".into())]
+     pub path: ShellString,
++    pub backend: Backend,
+     pub info_type: InfoType,
+     pub format: FormatConfig,
+     pub format_alt: Option<FormatConfig>,
+@@ -128,17 +141,9 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
+     loop {
+         let mut widget = Widget::new().with_format(format.clone());
+ 
+-        let statvfs = statvfs(&*path).error("failed to retrieve statvfs")?;
+-
+-        // Casting to be compatible with 32-bit systems
+-        #[allow(clippy::unnecessary_cast)]
+-        let (total, used, available, free) = {
+-            let total = (statvfs.blocks() as u64) * (statvfs.fragment_size() as u64);
+-            let used = ((statvfs.blocks() as u64) - (statvfs.blocks_free() as u64))
+-                * (statvfs.fragment_size() as u64);
+-            let available = (statvfs.blocks_available() as u64) * (statvfs.block_size() as u64);
+-            let free = (statvfs.blocks_free() as u64) * (statvfs.block_size() as u64);
+-            (total, used, available, free)
++        let (total, used, available, free) = match config.backend {
++            Backend::Vfs => get_vfs(&*path)?,
++            Backend::Btrfs => get_btrfs(&path).await?,
+         };
+ 
+         let result = match config.info_type {
+@@ -205,3 +210,88 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
+         }
+     }
+ }
++
++fn get_vfs<P>(path: &P) -> Result<(u64, u64, u64, u64)>
++where
++    P: ?Sized + nix::NixPath,
++{
++    let statvfs = statvfs(path).error("failed to retrieve statvfs")?;
++
++    // Casting to be compatible with 32-bit systems
++    #[allow(clippy::unnecessary_cast)]
++    {
++        let total = (statvfs.blocks() as u64) * (statvfs.fragment_size() as u64);
++        let used = ((statvfs.blocks() as u64) - (statvfs.blocks_free() as u64))
++            * (statvfs.fragment_size() as u64);
++        let available = (statvfs.blocks_available() as u64) * (statvfs.block_size() as u64);
++        let free = (statvfs.blocks_free() as u64) * (statvfs.block_size() as u64);
++
++        Ok((total, used, available, free))
++    }
++}
++
++async fn get_btrfs(path: &str) -> Result<(u64, u64, u64, u64)> {
++    const OUTPUT_CHANGED: &str = "Btrfs filesystem usage output format changed";
++
++    fn remove_estimate_min(estimate_str: &str) -> Result<&str> {
++        estimate_str.trim_matches('\t')
++            .split_once("\t")
++            .ok_or(Error::new(OUTPUT_CHANGED))
++            .map(|v| v.0)
++    }
++
++    macro_rules! get {
++        ($source:expr, $name:expr, $variable:ident) => {
++            get!(@pre_op (|a| {Ok::<_, Error>(a)}), $source, $name, $variable)
++        };
++        (@pre_op $function:expr, $source:expr, $name:expr, $variable:ident) => {
++            if $source.starts_with(concat!($name, ":")) {
++                let (found_name, variable_str) =
++                    $source.split_once(":").ok_or(Error::new(OUTPUT_CHANGED))?;
++
++                let variable_str = $function(variable_str)?;
++
++                debug_assert_eq!(found_name, $name);
++                $variable
++                    .set(variable_str.trim().parse().error(OUTPUT_CHANGED)?)
++                    .map_err(|_| Error::new(OUTPUT_CHANGED))?;
++            }
++        };
++    }
++
++    let filesystem_usage = Command::new("btrfs")
++        .args(["filesystem", "usage", "--raw", path])
++        .output()
++        .await
++        .error("Failed to collect btrfs filesystem usage info")?
++        .stdout;
++
++    {
++        let final_total = OnceCell::new();
++        let final_used = OnceCell::new();
++        let final_free = OnceCell::new();
++
++        let mut lines = filesystem_usage.lines();
++        while let Some(line) = lines
++            .next_line()
++            .await
++            .error("Failed to read output of btrfs filesystem usage")?
++        {
++            let line = line.trim();
++
++            // See btrfs-filesystem(8) for an explanation for the rows.
++            get!(line, "Device size", final_total);
++            get!(line, "Used", final_used);
++            get!(@pre_op remove_estimate_min, line, "Free (estimated)", final_free);
++        }
++
++        Ok((
++            *final_total.get().ok_or(Error::new(OUTPUT_CHANGED))?,
++            *final_used.get().ok_or(Error::new(OUTPUT_CHANGED))?,
++            // HACK(@bpeetz): We also return the free disk space as the available one, because btrfs
++            // does not tell us which disk space is reserved for the fs. <2025-05-18>
++            *final_free.get().ok_or(Error::new(OUTPUT_CHANGED))?,
++            *final_free.get().ok_or(Error::new(OUTPUT_CHANGED))?,
++        ))
++    }
++}
+-- 
+2.49.0
+
diff --git a/pkgs/by-name/lf/lf-make-map/Cargo.lock b/pkgs/by-name/lf/lf-make-map/Cargo.lock
index 51cbf6ad..1e293fde 100644
--- a/pkgs/by-name/lf/lf-make-map/Cargo.lock
+++ b/pkgs/by-name/lf/lf-make-map/Cargo.lock
@@ -12,12 +12,6 @@
 version = 4
 
 [[package]]
-name = "android-tzdata"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
-
-[[package]]
 name = "android_system_properties"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -28,9 +22,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.18"
+version = "0.6.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -43,79 +37,79 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.10"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
 dependencies = [
  "anstyle",
- "once_cell",
+ "once_cell_polyfill",
  "windows-sys",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.98"
+version = "1.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
 
 [[package]]
 name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
 
 [[package]]
 name = "bumpalo"
-version = "3.17.0"
+version = "3.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
 
 [[package]]
 name = "cc"
-version = "1.2.20"
+version = "1.2.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
+checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932"
 dependencies = [
+ "find-msvc-tools",
  "shlex",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "1.0.0"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
 
 [[package]]
 name = "chrono"
-version = "0.4.40"
+version = "0.4.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
 dependencies = [
- "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
@@ -125,9 +119,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -135,9 +129,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
 dependencies = [
  "anstream",
  "anstyle",
@@ -147,9 +141,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.32"
+version = "4.5.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -159,15 +153,15 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.7.4"
+version = "0.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
 
 [[package]]
 name = "core-foundation-sys"
@@ -176,6 +170,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
+name = "find-msvc-tools"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
+
+[[package]]
 name = "heck"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -183,15 +183,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "hermit-abi"
-version = "0.5.0"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.63"
+version = "0.1.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -213,9 +213,9 @@ dependencies = [
 
 [[package]]
 name = "is-terminal"
-version = "0.4.16"
+version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
+checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -224,15 +224,15 @@ dependencies = [
 
 [[package]]
 name = "is_terminal_polyfill"
-version = "1.70.1"
+version = "1.70.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
 
 [[package]]
 name = "js-sys"
-version = "0.3.77"
+version = "0.3.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
 dependencies = [
  "once_cell",
  "wasm-bindgen",
@@ -240,9 +240,9 @@ dependencies = [
 
 [[package]]
 name = "keymaps"
-version = "1.1.1"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a522bbaa39bddd54945580e369ed37113ea96f4cb8f0322be0d5e04aa4d7293"
+checksum = "ea59e8e461942cf1d6a7ad938848d6fd2e40eb43799c21192c09226ecc86710f"
 dependencies = [
  "thiserror",
 ]
@@ -261,15 +261,15 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.172"
+version = "0.2.180"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
 
 [[package]]
 name = "log"
-version = "0.4.27"
+version = "0.4.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
 
 [[package]]
 name = "num-traits"
@@ -287,28 +287,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
 name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
 
 [[package]]
 name = "same-file"
@@ -346,9 +352,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.101"
+version = "2.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -366,18 +372,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "2.0.12"
+version = "2.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "2.0.12"
+version = "2.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -386,19 +392,18 @@ dependencies = [
 
 [[package]]
 name = "thread_local"
-version = "1.1.8"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
 dependencies = [
  "cfg-if",
- "once_cell",
 ]
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.18"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
 
 [[package]]
 name = "utf8parse"
@@ -418,35 +423,22 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
 dependencies = [
  "cfg-if",
  "once_cell",
  "rustversion",
  "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -454,40 +446,40 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
 dependencies = [
+ "bumpalo",
  "proc-macro2",
  "quote",
  "syn",
- "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "winapi-util"
-version = "0.1.9"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
 name = "windows-core"
-version = "0.61.0"
+version = "0.62.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
 dependencies = [
  "windows-implement",
  "windows-interface",
@@ -498,9 +490,9 @@ dependencies = [
 
 [[package]]
 name = "windows-implement"
-version = "0.60.0"
+version = "0.60.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -509,9 +501,9 @@ dependencies = [
 
 [[package]]
 name = "windows-interface"
-version = "0.59.1"
+version = "0.59.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -520,97 +512,33 @@ dependencies = [
 
 [[package]]
 name = "windows-link"
-version = "0.1.1"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
 
 [[package]]
 name = "windows-result"
-version = "0.3.2"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-strings"
-version = "0.4.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-sys"
-version = "0.59.0"
+version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
 dependencies = [
- "windows-targets",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
-dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows-link",
 ]
-
-[[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
-
-[[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
-
-[[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
-
-[[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/pkgs/by-name/lf/lf-make-map/Cargo.toml b/pkgs/by-name/lf/lf-make-map/Cargo.toml
index 22860e12..15d48115 100644
--- a/pkgs/by-name/lf/lf-make-map/Cargo.toml
+++ b/pkgs/by-name/lf/lf-make-map/Cargo.toml
@@ -17,9 +17,9 @@ edition = "2024"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-anyhow = "1.0.98"
-clap = { version = "4.5.37", features = ["derive", "env"] }
-keymaps = "1.1.1"
-log = "0.4.27"
+anyhow = "1.0.100"
+clap = { version = "4.5.54", features = ["derive", "env"] }
+keymaps = "1.2.0"
+log = "0.4.29"
 stderrlog = "0.6.0"
 walkdir = "2.5.0"
diff --git a/pkgs/by-name/lf/lf-make-map/flake.lock b/pkgs/by-name/lf/lf-make-map/flake.lock
index 07eb6b21..1e997998 100644
--- a/pkgs/by-name/lf/lf-make-map/flake.lock
+++ b/pkgs/by-name/lf/lf-make-map/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1745377448,
-        "narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
+        "lastModified": 1768661221,
+        "narHash": "sha256-MJwOjrIISfOpdI9x4C+5WFQXvHtOuj5mqLZ4TMEtk1M=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
+        "rev": "3327b113f2ef698d380df83fbccefad7e83d7769",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/lf/lf-make-map/flake.nix b/pkgs/by-name/lf/lf-make-map/flake.nix
index 20925aca..8ce8ff0f 100644
--- a/pkgs/by-name/lf/lf-make-map/flake.nix
+++ b/pkgs/by-name/lf/lf-make-map/flake.nix
@@ -19,13 +19,13 @@
     pkgs = nixpkgs.legacyPackages."${system}";
   in {
     devShells."${system}".default = pkgs.mkShell {
-      packages = with pkgs; [
-        cargo
-        clippy
-        rustc
-        rustfmt
+      packages = [
+        pkgs.cargo
+        pkgs.clippy
+        pkgs.rustc
+        pkgs.rustfmt
 
-        cargo-edit
+        pkgs.cargo-edit
       ];
     };
   };
diff --git a/pkgs/by-name/lf/lf-make-map/src/mapping/map_key.rs b/pkgs/by-name/lf/lf-make-map/src/mapping/map_key.rs
index 10b612fd..5fd046fb 100644
--- a/pkgs/by-name/lf/lf-make-map/src/mapping/map_key.rs
+++ b/pkgs/by-name/lf/lf-make-map/src/mapping/map_key.rs
@@ -157,7 +157,7 @@ This should not happen, please report the bug!",
         };
 
         assert_eq!(
-            value.len(),
+            value.chars().count(),
             number_of_chars,
             "'{}' does not have expected length of: {}",
             value,
diff --git a/pkgs/by-name/lf/lf-make-map/tests/cases/child_insert/test.sh b/pkgs/by-name/lf/lf-make-map/tests/cases/child_insert/test.sh
index 90ebe1ce..af6a1391 100755
--- a/pkgs/by-name/lf/lf-make-map/tests/cases/child_insert/test.sh
+++ b/pkgs/by-name/lf/lf-make-map/tests/cases/child_insert/test.sh
@@ -10,7 +10,7 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-test="$(mktemp --directory)"
+test="$(mktemp --directory -t lf_make_map_test_XXXX)"
 
 cleanup() {
     rm --recursive "$test"
diff --git a/pkgs/by-name/lf/lf-make-map/tests/cases/simple/test.sh b/pkgs/by-name/lf/lf-make-map/tests/cases/simple/test.sh
index 6e127d28..22f97009 100755
--- a/pkgs/by-name/lf/lf-make-map/tests/cases/simple/test.sh
+++ b/pkgs/by-name/lf/lf-make-map/tests/cases/simple/test.sh
@@ -12,7 +12,7 @@
 
 # We need to hard code this, so that our output matches the golden sample.
 base="/tmp/tmp.DfcgjemfCG"
-test="$(mktemp --directory)"
+test="$(mktemp --directory -t lf_make_temp_test_XXXXX)"
 
 [ -d "$base" ] && {
     echo "$base already exists!"
diff --git a/pkgs/by-name/mp/mpdpopm/.envrc b/pkgs/by-name/mp/mpdpopm/.envrc
new file mode 100644
index 00000000..9f477e71
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/.envrc
@@ -0,0 +1,22 @@
+#!/usr/bin/env sh
+
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+use flake || use nix
+watch_file flake.nix
+
+PATH_add ./scripts
+PATH_add ./target/debug/
+PATH_add ./target/release/
+
+if on_git_branch; then
+    echo && git status --short --branch
+fi
diff --git a/pkgs/by-name/mp/mpdpopm/.gitignore b/pkgs/by-name/mp/mpdpopm/.gitignore
new file mode 100644
index 00000000..c80d7eef
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/.gitignore
@@ -0,0 +1,16 @@
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+# build
+/target
+/result
+
+# dev env
+.direnv
diff --git a/pkgs/by-name/mp/mpdpopm/Cargo.lock b/pkgs/by-name/mp/mpdpopm/Cargo.lock
new file mode 100644
index 00000000..8b61799a
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/Cargo.lock
@@ -0,0 +1,1449 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 4
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "android_system_properties"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon",
+ "colorchoice",
+ "is_terminal_polyfill",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
+
+[[package]]
+name = "anstyle-parse"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
+dependencies = [
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-query"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "3.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
+dependencies = [
+ "anstyle",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "ascii-canvas"
+version = "4.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef1e3e699d84ab1b0911a1010c5c106aa34ae89aeac103be5ce0c3859db1e891"
+dependencies = [
+ "term",
+]
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
+
+[[package]]
+name = "bit-set"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+
+[[package]]
+name = "bitflags"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "boolinator"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
+
+[[package]]
+name = "bumpalo"
+version = "3.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
+
+[[package]]
+name = "bytes"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
+
+[[package]]
+name = "cc"
+version = "1.2.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "chrono"
+version = "0.4.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
+dependencies = [
+ "iana-time-zone",
+ "js-sys",
+ "num-traits",
+ "wasm-bindgen",
+ "windows-link",
+]
+
+[[package]]
+name = "clap"
+version = "4.5.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
+dependencies = [
+ "clap_builder",
+ "clap_derive",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.5.54"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_derive"
+version = "4.5.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
+
+[[package]]
+name = "colorchoice"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+]
+
+[[package]]
+name = "either"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
+
+[[package]]
+name = "ena"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
+dependencies = [
+ "log",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
+
+[[package]]
+name = "fixedbitset"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99"
+
+[[package]]
+name = "futures"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e"
+
+[[package]]
+name = "futures-executor"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f"
+dependencies = [
+ "futures-core",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-io"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7"
+
+[[package]]
+name = "futures-task"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988"
+
+[[package]]
+name = "futures-util"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasip2",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "iana-time-zone"
+version = "0.1.64"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
+dependencies = [
+ "android_system_properties",
+ "core-foundation-sys",
+ "iana-time-zone-haiku",
+ "js-sys",
+ "log",
+ "wasm-bindgen",
+ "windows-core",
+]
+
+[[package]]
+name = "iana-time-zone-haiku"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "is_terminal_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
+
+[[package]]
+name = "js-sys"
+version = "0.3.85"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
+dependencies = [
+ "once_cell",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "keccak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
+dependencies = [
+ "cpufeatures",
+]
+
+[[package]]
+name = "lalrpop"
+version = "0.22.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba4ebbd48ce411c1d10fb35185f5a51a7bfa3d8b24b4e330d30c9e3a34129501"
+dependencies = [
+ "ascii-canvas",
+ "bit-set",
+ "ena",
+ "itertools",
+ "lalrpop-util",
+ "petgraph",
+ "pico-args",
+ "regex",
+ "regex-syntax",
+ "sha3",
+ "string_cache",
+ "term",
+ "unicode-xid",
+ "walkdir",
+]
+
+[[package]]
+name = "lalrpop-util"
+version = "0.22.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b5baa5e9ff84f1aefd264e6869907646538a52147a755d494517a8007fb48733"
+dependencies = [
+ "regex-automata",
+ "rustversion",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.180"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
+name = "matchers"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
+name = "memchr"
+version = "2.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
+name = "mio"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc"
+dependencies = [
+ "libc",
+ "wasi",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "mpdpopm"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "async-trait",
+ "boolinator",
+ "chrono",
+ "clap",
+ "errno",
+ "futures",
+ "lalrpop",
+ "lalrpop-util",
+ "lazy_static",
+ "os_str_bytes",
+ "pin-project",
+ "rand",
+ "regex",
+ "serde",
+ "serde_json",
+ "shlex",
+ "tokio",
+ "toml",
+ "tracing",
+ "tracing-subscriber",
+]
+
+[[package]]
+name = "new_debug_unreachable"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
+
+[[package]]
+name = "nu-ansi-term"
+version = "0.50.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "os_str_bytes"
+version = "7.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63eceb7b5d757011a87d08eb2123db15d87fb0c281f65d101ce30a1e96c3ad5c"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "petgraph"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772"
+dependencies = [
+ "fixedbitset",
+ "indexmap",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "pico-args"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315"
+
+[[package]]
+name = "pin-project"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
+dependencies = [
+ "zerocopy",
+]
+
+[[package]]
+name = "precomputed-hash"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "5.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
+
+[[package]]
+name = "rand"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
+dependencies = [
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.149"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "sha3"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
+dependencies = [
+ "digest",
+ "keccak",
+]
+
+[[package]]
+name = "sharded-slab"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b"
+dependencies = [
+ "errno",
+ "libc",
+]
+
+[[package]]
+name = "siphasher"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
+
+[[package]]
+name = "slab"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
+name = "socket2"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
+dependencies = [
+ "libc",
+ "windows-sys 0.60.2",
+]
+
+[[package]]
+name = "string_cache"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f"
+dependencies = [
+ "new_debug_unreachable",
+ "parking_lot",
+ "phf_shared",
+ "precomputed-hash",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "syn"
+version = "2.0.114"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "term"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8c27177b12a6399ffc08b98f76f7c9a1f4fe9fc967c784c5a071fa8d93cf7e1"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "thread_local"
+version = "1.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "tokio"
+version = "1.49.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86"
+dependencies = [
+ "bytes",
+ "libc",
+ "mio",
+ "pin-project-lite",
+ "signal-hook-registry",
+ "socket2",
+ "tokio-macros",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "tokio-macros"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "toml"
+version = "0.9.11+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46"
+dependencies = [
+ "indexmap",
+ "serde_core",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.7.5+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
+name = "toml_parser"
+version = "1.0.6+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
+dependencies = [
+ "winnow",
+]
+
+[[package]]
+name = "toml_writer"
+version = "1.0.6+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
+
+[[package]]
+name = "tracing"
+version = "0.1.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
+dependencies = [
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
+dependencies = [
+ "log",
+ "once_cell",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex-automata",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
+name = "typenum"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "valuable"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
+
+[[package]]
+name = "wasip2"
+version = "1.0.2+wasi-0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
+dependencies = [
+ "wit-bindgen",
+]
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "rustversion",
+ "wasm-bindgen-macro",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
+dependencies = [
+ "bumpalo",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "windows-core"
+version = "0.62.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
+dependencies = [
+ "windows-implement",
+ "windows-interface",
+ "windows-link",
+ "windows-result",
+ "windows-strings",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-interface"
+version = "0.59.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-result"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-strings"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.53.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
+dependencies = [
+ "windows-link",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.53.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
+
+[[package]]
+name = "winnow"
+version = "0.7.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
+
+[[package]]
+name = "wit-bindgen"
+version = "0.51.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
+
+[[package]]
+name = "zerocopy"
+version = "0.8.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7456cf00f0685ad319c5b1693f291a650eaf345e941d082fc4e03df8a03996ac"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.8.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1328722bbf2115db7e19d69ebcc15e795719e2d66b60827c6a69a117365e37a0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65"
diff --git a/pkgs/by-name/mp/mpdpopm/Cargo.toml b/pkgs/by-name/mp/mpdpopm/Cargo.toml
new file mode 100644
index 00000000..71232236
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/Cargo.toml
@@ -0,0 +1,46 @@
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+[package]
+name = "mpdpopm"
+description = "Maintain ratings & playcounts for your mpd server"
+version = "0.1.0"
+edition = "2024"
+license = "AGPL-3.0-or-later"
+homepage = ""
+repository = "https://git.vhack.eu/bpeetz/nixos-config"
+authors = ["Benedikt Peetz", "Mechael Herstine"]
+keywords = ["mpd", "music", "daemon"]
+categories = ["multimedia", "network-programming", "database"]
+
+[build-dependencies]
+lalrpop = { version = "0.22", features = ["lexer"] }
+
+[dependencies]
+async-trait = "0.1"
+boolinator = "2.4"
+chrono = "0.4"
+clap = {version = "4.5", features = ["derive"]}
+errno = "0.3"
+futures = "0.3"
+lalrpop-util = { version = "0.22", features = ["lexer"] }
+lazy_static = "1.5"
+os_str_bytes = "7.1"
+pin-project = "1.1"
+regex = "1.12"
+serde = { version = "1.0", features = ["derive"] }
+serde_json = "1.0.149"
+toml = "0.9"
+tokio = { version = "1.49", features = ["io-util", "macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
+tracing = "0.1.44"
+tracing-subscriber = { version = "0.3.22", features = ["env-filter"]}
+anyhow = "1.0.100"
+shlex = "1.3.0"
+rand = "0.9.2"
diff --git a/pkgs/by-name/mp/mpdpopm/README.md b/pkgs/by-name/mp/mpdpopm/README.md
new file mode 100644
index 00000000..3c2d961b
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/README.md
@@ -0,0 +1,260 @@
+
+# Table of Contents
+
+1.  [Introduction](#orgb2618c9)
+2.  [What Can You Do With It?](#orgf1adf2c)
+3.  [Licsense](#org3f75b89)
+4.  [Prerequisites](#org67de102)
+5.  [Installing](#installing)
+    1.  [Use the pre-built binaries](#orgb2e3434)
+    2.  [Crates.io](#org971a8b3)
+    3.  [Use the Debian package](#org55e51f8)
+    4.  [Use the Arch package](#org49ada47)
+    5.  [Autotools source distributions](#org9c94559)
+    6.  [Building from source](#org64bc5dd)
+6.  [Getting Started](#getting_started)
+    1.  [Program Structure](#org4a22fae)
+    2.  [Getting Set-up](#orgfbd2d7d)
+        1.  [MPD](#orgb37b483)
+        2.  [mppopmd](#org38f4b69)
+        3.  [mppopm](#orgfa9dacf)
+7.  [Status & Roadmap](#orgd90c7da)
+
+
+
+<a id="orgb2618c9"></a>
+
+# Introduction
+
+[mpdpopm](https://github.com/sp1ff/mpdpopm) provides a companion daemon to [MPD](https://www.musicpd.org/) for maintaining play counts, ratings and last-played timestamps, along with an associated CLI for talking to the companion daemon. Similar to [mpdfav](https://github.com/vincent-petithory/mpdfav), but written in Rust (which I prefer to Go), it will maintain this information in your sticker database. Along the lines of [mpdcron](https://alip.github.io/mpdcron), it will also allow you to keep that information up-to-date in your tags by invoking external (user-provided & -configured) commands.
+
+This README focuses on obtaining & installing [mpdpopm](https://github.com/sp1ff/mpdpopm); the user manual is distributed with the package in [Texinfo](https://www.gnu.org/software/texinfo/) format. The HTML version of the user manual is hosted on my personal [site](https://www.unwoundstack.com/doc/mpdpopm/curr).
+
+
+<a id="orgf1adf2c"></a>
+
+# What Can You Do With It?
+
+Once you've [installed](#installing) & [started](#getting_started) [mpdpopm](https://github.com/sp1ff/mpdpopm), its daemon (`mppopmd`) will sit in the background noting the songs you play and updating play counts & last played timestamps in your [MPD](https://www.musicpd.org/) sticker database. If you'd like to rate a song, you can send `mppopmd` a message using your favorte MPD client, or with the `mppopm` CLI that comes along with this package; `mppopmd` will note the rating, as well.
+
+If you'd like to make use of this information in your song selection, you can ask `mppopmd` to queue-up songs on this basis by saying things like:
+
+    mppopm findadd "(rating > 128)"
+
+to add all songs with a rating greater than 128 to the play queue, or
+
+    mppopm findadd "(lastplayed <= \"2022-12-28\")"
+
+to add all songs that haven't been played in the last year.
+
+
+<a id="org3f75b89"></a>
+
+# Licsense
+
+[mpdpopm](https://github.com/sp1ff/mpdpopm) is GPL v3 software.
+
+
+<a id="org67de102"></a>
+
+# Prerequisites
+
+[Music Player Daemon](https://www.musicpd.org/): "Music Player Daemon (MPD) is a flexible, powerful, server-side application for playing music. Through plugins and libraries it can play a variety of sound files while being controlled by its network protocol." If you're reading this, I assume you're already running MPD, so this document won't have much to say on installing & configuring it other than that you **do** need to setup the sticker database by setting `sticker_file` in your configuration.
+
+If you choose to use the pre-built binaries or the Debian or Arch packages (available under [releases](https://github.com/sp1ff/mpdpopm/releases)), that's all you'll need&#x2013; you can jump ahead to the section entitled [Installing](#getting_started), below.
+
+If you would prefer to download [mpdpopm](https://github.com/sp1ff/mpdpopm) from [crates.io](https://crates.io/crates/mpdpopm), you'll need need the [Rust](https://www.rust-lang.org/tools/install) toolchain ("Rust is a memory- & thread-safe language with no runtime or garbage collector"). Installing the toolchain is easy:
+
+    curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
+
+[mpdpopm](https://github.com/sp1ff/mpdpopm) is also available as an Autotools source distribution (also under [releases](https://github.com/sp1ff/mpdpopm/releases)), and of course you can just clone the repo & build the project from source. In either of those two cases you'll need the Gnu [Autotools](https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html) installed in addition to Rust. In the former case, grab the tarball in the format of your choice & perform the usual "./configure && make && make install" incantation. In the latter, you'll need to invoke "./bootstrap" after you clone the repo. Again, if you're considering that route, I assume you're familiar with the Autotools & won't say much about them here.
+
+
+<a id="installing"></a>
+
+# Installing
+
+As mentioned above, you can install [mpdpopm](https://github.com/sp1ff/mpdpopm) in a few different ways. In increasing order of complexity:
+
+
+<a id="orgb2e3434"></a>
+
+## Use the pre-built binaries
+
+Thanks  to a suggestion by [m040601](https://github.com/m040601), you can download pre-built binaries for each [release](https://github.com/sp1ff/mpdpopm/releases). At the time of this writing, only Linux & MacOS are supported, and only on x86<sub>64</sub> at that. If that works for you, you can do something like:
+
+    cd /tmp
+    curl -L --output mpdpopm-0.3.5.tar.gz https://github.com/sp1ff/mpdpopm/releases/download/0.3.5/mpdpopm-0.3.5-x86_64-unknown-linux.tar.gz
+    tar xf mpdpopm-0.3.5.tar.gz
+    tree mpdpopm-0.3.5-x86_64-unknown-linux/
+    mpdpopm-0.3.5-x86_64-unknown-linux/
+    ├── bin
+    │   ├── mppopm
+    │   └── mppopmd
+    └── doc
+        ├── AUTHORS
+        ├── ChangeLog
+        ├── COPYING
+        ├── NEWS
+        ├── README.org
+        ├── THANKS
+        ├── mppopmd.conf
+        ├── mppopmd.info
+        └── mppopmd.service
+    
+    2 directories, 10 files
+
+Copy the binaries `mppopmd` (the daemon) and `mppopm` (the CLI) to a convenient place (e.g. `/usr/local/bin` or `$HOME/.local/bin`) and proceed to [Getting Started](#getting_started), below.
+
+
+<a id="org971a8b3"></a>
+
+## Crates.io
+
+If you've got the Rust toolchain installed, just say `cargo install mpdpopm`. The binaries will now be in `$HOME/.cargo/bin`, and you can proceed to [Getting Started](#getting_started), below.
+
+
+<a id="org55e51f8"></a>
+
+## Use the Debian package
+
+If you're running on a Debian-based Linux distribution, and you're on an x86<sub>64</sub> processor, I've begun providing a Debian binary package, courtesy of the very cool [cargo-deb](https://github.com/mmstick/cargo-deb) Cargo helper command. Just do:
+
+    cd /tmp
+    curl -L -O https://github.com/sp1ff/mpdpopm/releases/download/0.3.5/mpdpopm_0.3.5_amd64.deb
+    sudo dpkg -i mpdpopm_0.3.5_amd64.deb
+
+The binaries will be placed in `/usr/local/bin`, and you can proceed to [Getting Started](#getting_started), below.
+
+
+<a id="org49ada47"></a>
+
+## Use the Arch package
+
+If you're running on an Arch-based Linux distribution, I maintain a few packages in the [AUR](https://aur.archlinux.org/):
+
+-   [mpdpopm](https://aur.archlinux.org/packages/mpdpopm): which will grab the latest release & build it locally
+-   [mpdpopm-git](https://aur.archlinux.org/packages/mpdpopm-git): grab `HEAD` from `master` & build it locally
+-   [mpdpopm-bin](https://aur.archlinux.org/packages/mpdpopm-bin): grab the pre-built binaries from the latest release & install 'em
+
+You can clone the git repo for whichever package you'd like to use (remotes at link), do `makepkg` & then use pacman to install the package you just built, or use an AUR package manager (I use `yay`, e.g.)
+
+
+<a id="org9c94559"></a>
+
+## Autotools source distributions
+
+If you've got the Rust toolchain as well as Autotools installed, you can build from source via Autotools:
+
+    cd /tmp
+    curl -L -O https://github.com/sp1ff/mpdpopm/releases/download/0.3.5/mpdpopm-0.3.5.tar.xz
+    tar xf mpdpopm-0.3.5.tar.xz
+    cd mpdpopm-0.3.5
+    ./configure
+    make
+    make check
+    sudo make install
+
+All the usual `configure` options apply (`--prefix`, e.g.) In particular, you can say `--enable-debug` to produce debug builds.
+
+
+<a id="org64bc5dd"></a>
+
+## Building from source
+
+Finally, and again if you have the build toolchain (Rust & Autotools) installed, you can build from source:
+
+    git clone git@github.com:sp1ff/mpdpopm.git
+    cd mpdpopm
+    ./bootstrap
+    ./configure
+    make
+    make check
+    sudo make install
+
+Notice the call to `./bootstrap`, in this case.
+
+
+<a id="getting_started"></a>
+
+# Getting Started
+
+This README provides a "quick-start" guide to getting mpdpopm up & running. For detailed user docs, refer to the [manual](https://www.unwoundstack.com/doc/mpdpopm/curr).
+
+
+<a id="org4a22fae"></a>
+
+## Program Structure
+
+[mpdpopm](https://github.com/sp1ff/mpdpopm) provides two programs:
+
+1.  `mppopmd` is the companion daemon process
+2.  `mppopm` is the associated command-line interface to the daemon
+
+`mppopmd` will monitor `mpd` for song playback & note when songs complete; this is how it knows to increment the playcount & update the last played timestamp for each song to which you listen. `mppopmd` records this information (i.e. play counts, last played and ratings) using `mpd` [stickers](https://www.musicpd.org/doc/html/protocol.html#stickers). A sticker is a little bit of textual information which clients can attach to songs in the form of a name-value pair. [mpdpopm](https://github.com/sp1ff/mpdpopm) defines a new sticker name for each of these items & udpates the values for each song when & as requested.
+
+Of course, other `mpd` clients will not, in general, be aware of `mppopmd` or the stickers it sets: you the user will have to bridge that gap. You could of course just fire-up `netcat` & start sending commands over the MPD protocol using `sendmessage`, but that's not particularly convenient&#x2013; that's where `mppopm` comes in. `mppopm` is the client interface; one can through it instruct `mppopmd` to set ratings, get & set the various stickers mpdpopm knows about, and even search for songs in terms of mpdpopm attributes & add them to the play queue.
+
+
+<a id="orgfbd2d7d"></a>
+
+## Getting Set-up
+
+
+<a id="orgb37b483"></a>
+
+### MPD
+
+If you're reading this, I assume you already have MPD up & running, so this section will be brief. One note, prompted by user [m040601](https://github.com/m040601), however: as mentioned above, [mpdpopm](https://github.com/sp1ff/mpdpopm) leverages the MPD sticker database. I was chagrined to find that if you do not configure MPD to maintain a sticker database, all sticker commands will simply be disabled. Therefore, before setting up [mpdpopm](https://github.com/sp1ff/mpdpopm), find your `mpd` configuration file and check to be sure you have a `sticker_file` entry; something like this:
+
+    sticker_file "/home/sp1ff/lib/mpd/sticker.sql"
+
+Check also that the you have write access to the named file & its parent directory.
+
+
+<a id="org38f4b69"></a>
+
+### mppopmd
+
+The daemon depends on a configuration file that you'll need to provide. Most `mppopmd` configuration items have sensible defaults, but there are a few that will need to be customized to your MPD setup. A sample configuration file is provided with all distributions; see also the user [manual](https://www.unwoundstack.com/doc/mpdpopm/curr#mppopmd-Configuration) for detailed documentation.
+
+You'll likely want to run the program in the foreground initially for ease of trouble-shooting, but after that you'll probably want to run it as a daemon. Again see the [manual](https://www.unwoundstack.com/doc/mpdopmd/curr#mppopmd-as-a-Daemon) for detailed instructions.
+
+Once you've got the daemon running to your satisfaction, if you're on a systemd-based Linux distribution, have a look at the sample systemd unit file thanks to [tanshoku](https://github.com/tanshoku).
+
+[tanshoku](https://github.com/tanshoku) was kind enough to contribute a systemd unit for this purpose. At present, the build does not install it, but provides it as an example and leaves it to the user to install should they desire (and after they have edited it to suit their configuration). You can find it in `${prefix}/share/mpdpopm/examples` for the Autotools distribution, `/usr/local/share/mpdpopm/examples` for the Debian package, and in the `doc` folder for the pre-built binaries.
+
+
+<a id="orgfa9dacf"></a>
+
+### mppopm
+
+At this point, [mpdpopm](https://github.com/sp1ff/mpdpopm) will happily monitor your playback history & keep play counts & last played timestamps for you. If you would like to rate tracks, however, you will need to somehow induce your favorite mpd client to send a "rating" message to the [mpdpopm](https://github.com/sp1ff/mpdpopm) commands channel ("unwoundstack.com:commands" by default). Since this is unlikely to be convenient, I wrote an mpd client for the purpose: a little CLI called `mppopm`. You can simply execute
+
+    mppopm set-rating '*****'
+
+to set the current track's rating to five "stars" (say `mppopm --help` for an explanation of the rating system; in brief&#x2013; it's Winamp's). NB. the set rating command by default produces no output; if you want confirmation that something's happening, use the `-v` flag.
+
+The CLI offers "get" & "set" commands for play counts, last played timestamps & the rating. It also provides commands for searching your songs on the basis of play count, rating & last played times in addition to the usual artist, title &c. Say `mppopm --help` for a full list of options, including how to tell it where the mpd server can be found on your network.
+
+
+<a id="orgd90c7da"></a>
+
+# Status & Roadmap
+
+I am currently using [mpdpopm](https://github.com/sp1ff/mpdpopm) day in & day out with my music collection, but it's early days; I have chosen the version number (0.n) in the hopes of indicating that. Right now, mpdpopm is the bare-bones of an app: it's plumbing, not the sink.
+
+Heretofore, you could use the `mppopm` CLI to, say, rate the current song, but in order to actually <span class="underline">do</span> anything with that rating in the future, you'd have had to  write some kind of mpd client for yourself. With the 0.2 release, I've added support for extended MPD filter syntax that allows queries that include the stickers that [mpdpopm](https://github.com/sp1ff/mpdpopm) manages&#x2013; so you can now, for instance, say:
+
+    mppopm findadd "(artist =~ \"foo\") and (rating > 175)"
+
+MPD will handle the "artist =~" clause & [mpdpopm](https://github.com/sp1ff/mpdpopm) the "rating >" clause, as well as combining the results.
+
+This will hopefully be a start to making [mpdpopm](https://github.com/sp1ff/mpdpopm) into a more of a user-facing application than a developer-facing utlity.
+
+Windows support may be some time coming; the daemon depends on Unix signal handling, the MPD Unix socket, and the Unix daemon logic, especially `fork` & `exec`&#x2026; if you'd like to run it on Windows, let me know&#x2013; if there's enough interest, and I can get some kind of Windows VM setup, I'll look at a port.
+
+Longer-term, I see [mpdpopm](https://github.com/sp1ff/mpdpopm) as a "dual" to mpd&#x2013; mpd commits to never altering your files. mpdpopm will take on that task in terms of tags, at least. To address the "plumbing, not the sink" problem, I'd like to author a client that will handle player control (of course), but also visualization & tag editing&#x2013; a complete music library solution.
+
+Suggestions, bug reports & PRs welcome!
+
diff --git a/pkgs/by-name/mp/mpdpopm/README.org b/pkgs/by-name/mp/mpdpopm/README.org
new file mode 100644
index 00000000..ebc91262
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/README.org
@@ -0,0 +1,214 @@
+#+TITLE: README
+#+AUTHOR: Michael Herstine
+#+DESCRIPTION: mpdpopm
+#+EMAIL: sp1ff@pobox.com
+#+DATE: <2025-10-19 Sun 19:17>
+#+AUTODATE: t
+
+* Introduction
+
+[[https://github.com/sp1ff/mpdpopm][mpdpopm]] provides a companion daemon to [[https://www.musicpd.org/][MPD]] for maintaining play counts, ratings and last-played timestamps, along with an associated CLI for talking to the companion daemon. Similar to [[https://github.com/vincent-petithory/mpdfav][mpdfav]], but written in Rust (which I prefer to Go), it will maintain this information in your sticker database. Along the lines of [[https://alip.github.io/mpdcron][mpdcron]], it will also allow you to keep that information up-to-date in your tags by invoking external (user-provided & -configured) commands.
+
+This README focuses on obtaining & installing [[https://github.com/sp1ff/mpdpopm][mpdpopm]]; the user manual is distributed with the package in [[https://www.gnu.org/software/texinfo/][Texinfo]] format. The HTML version of the user manual is hosted on my personal [[https://www.unwoundstack.com/doc/mpdpopm/curr][site]].
+
+* What Can You Do With It?
+
+Once you've [[#installing][installed]] & [[#getting_started][started]] [[https://github.com/sp1ff/mpdpopm][mpdpopm]], its daemon (=mppopmd=) will sit in the background noting the songs you play and updating play counts & last played timestamps in your [[https://www.musicpd.org/][MPD]] sticker database. If you'd like to rate a song, you can send =mppopmd= a message using your favorte MPD client, or with the =mppopm= CLI that comes along with this package; =mppopmd= will note the rating, as well.
+
+If you'd like to make use of this information in your song selection, you can ask =mppopmd= to queue-up songs on this basis by saying things like:
+
+#+BEGIN_SRC bash
+mppopm findadd "(rating > 128)"
+#+END_SRC
+
+to add all songs with a rating greater than 128 to the play queue, or
+
+#+BEGIN_SRC bash
+mppopm findadd "(lastplayed <= \"2022-12-28\")"
+#+END_SRC
+
+to add all songs that haven't been played in the last year.
+
+* Licsense
+
+[[https://github.com/sp1ff/mpdpopm][mpdpopm]] is GPL v3 software.
+
+* Prerequisites
+
+[[https://www.musicpd.org/][Music Player Daemon]]: "Music Player Daemon (MPD) is a flexible, powerful, server-side application for playing music. Through plugins and libraries it can play a variety of sound files while being controlled by its network protocol." If you're reading this, I assume you're already running MPD, so this document won't have much to say on installing & configuring it other than that you *do* need to setup the sticker database by setting =sticker_file= in your configuration.
+
+If you choose to use the pre-built binaries or the Debian or Arch packages (available under [[https://github.com/sp1ff/mpdpopm/releases][releases]]), that's all you'll need-- you can jump ahead to the section entitled [[#getting_started][Installing]], below.
+
+If you would prefer to download [[https://github.com/sp1ff/mpdpopm][mpdpopm]] from [[https://crates.io/crates/mpdpopm][crates.io]], you'll need need the [[https://www.rust-lang.org/tools/install][Rust]] toolchain ("Rust is a memory- & thread-safe language with no runtime or garbage collector"). Installing the toolchain is easy:
+
+#+BEGIN_SRC bash
+curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
+#+END_SRC
+
+[[https://github.com/sp1ff/mpdpopm][mpdpopm]] is also available as an Autotools source distribution (also under [[https://github.com/sp1ff/mpdpopm/releases][releases]]), and of course you can just clone the repo & build the project from source. In either of those two cases you'll need the Gnu [[https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html][Autotools]] installed in addition to Rust. In the former case, grab the tarball in the format of your choice & perform the usual "./configure && make && make install" incantation. In the latter, you'll need to invoke "./bootstrap" after you clone the repo. Again, if you're considering that route, I assume you're familiar with the Autotools & won't say much about them here.
+
+* Installing
+  :PROPERTIES:
+  :CUSTOM_ID: installing
+  :END:
+
+As mentioned above, you can install [[https://github.com/sp1ff/mpdpopm][mpdpopm]] in a few different ways. In increasing order of complexity:
+
+** Use the pre-built binaries
+
+Thanks  to a suggestion by [[https://github.com/m040601][m040601]], you can download pre-built binaries for each [[https://github.com/sp1ff/mpdpopm/releases][release]]. At the time of this writing, only Linux & MacOS are supported, and only on x86_64 at that. If that works for you, you can do something like:
+
+#+BEGIN_SRC bash
+cd /tmp
+curl -L --output mpdpopm-0.3.5.tar.gz https://github.com/sp1ff/mpdpopm/releases/download/0.3.5/mpdpopm-0.3.5-x86_64-unknown-linux.tar.gz
+tar xf mpdpopm-0.3.5.tar.gz
+tree mpdpopm-0.3.5-x86_64-unknown-linux/
+mpdpopm-0.3.5-x86_64-unknown-linux/
+├── bin
+│   ├── mppopm
+│   └── mppopmd
+└── doc
+    ├── AUTHORS
+    ├── ChangeLog
+    ├── COPYING
+    ├── NEWS
+    ├── README.org
+    ├── THANKS
+    ├── mppopmd.conf
+    ├── mppopmd.info
+    └── mppopmd.service
+
+2 directories, 10 files
+#+END_SRC
+
+Copy the binaries =mppopmd= (the daemon) and =mppopm= (the CLI) to a convenient place (e.g. =/usr/local/bin= or =$HOME/.local/bin=) and proceed to [[#getting_started][Getting Started]], below.
+
+** Crates.io
+
+If you've got the Rust toolchain installed, just say =cargo install mpdpopm=. The binaries will now be in =$HOME/.cargo/bin=, and you can proceed to [[#getting_started][Getting Started]], below.
+
+** Use the Debian package
+
+If you're running on a Debian-based Linux distribution, and you're on an x86_64 processor, I've begun providing a Debian binary package, courtesy of the very cool [[https://github.com/mmstick/cargo-deb][cargo-deb]] Cargo helper command. Just do:
+
+#+BEGIN_SRC bash
+cd /tmp
+curl -L -O https://github.com/sp1ff/mpdpopm/releases/download/0.3.5/mpdpopm_0.3.5_amd64.deb
+sudo dpkg -i mpdpopm_0.3.5_amd64.deb
+#+END_SRC
+
+The binaries will be placed in =/usr/local/bin=, and you can proceed to [[#getting_started][Getting Started]], below.
+
+** Use the Arch package
+
+If you're running on an Arch-based Linux distribution, I maintain a few packages in the [[https://aur.archlinux.org/][AUR]]:
+
+  - [[https://aur.archlinux.org/packages/mpdpopm][mpdpopm]]: which will grab the latest release & build it locally
+  - [[https://aur.archlinux.org/packages/mpdpopm-git][mpdpopm-git]]: grab =HEAD= from =master= & build it locally
+  - [[https://aur.archlinux.org/packages/mpdpopm-bin][mpdpopm-bin]]: grab the pre-built binaries from the latest release & install 'em
+
+You can clone the git repo for whichever package you'd like to use (remotes at link), do =makepkg= & then use pacman to install the package you just built, or use an AUR package manager (I use =yay=, e.g.)
+** Autotools source distributions
+
+If you've got the Rust toolchain as well as Autotools installed, you can build from source via Autotools:
+
+#+BEGIN_SRC bash
+cd /tmp
+curl -L -O https://github.com/sp1ff/mpdpopm/releases/download/0.3.5/mpdpopm-0.3.5.tar.xz
+tar xf mpdpopm-0.3.5.tar.xz
+cd mpdpopm-0.3.5
+./configure
+make
+make check
+sudo make install
+#+END_SRC
+
+All the usual =configure= options apply (=--prefix=, e.g.) In particular, you can say =--enable-debug= to produce debug builds.
+
+** Building from source
+
+Finally, and again if you have the build toolchain (Rust & Autotools) installed, you can build from source:
+
+#+BEGIN_SRC bash
+git clone git@github.com:sp1ff/mpdpopm.git
+cd mpdpopm
+./bootstrap
+./configure
+make
+make check
+sudo make install
+#+END_SRC
+
+Notice the call to =./bootstrap=, in this case.
+
+* Getting Started
+  :PROPERTIES:
+  :CUSTOM_ID: getting_started
+  :END:
+
+This README provides a "quick-start" guide to getting mpdpopm up & running. For detailed user docs, refer to the [[https://www.unwoundstack.com/doc/mpdpopm/curr][manual]].
+
+** Program Structure
+
+[[https://github.com/sp1ff/mpdpopm][mpdpopm]] provides two programs:
+
+  1. =mppopmd= is the companion daemon process
+  2. =mppopm= is the associated command-line interface to the daemon
+
+=mppopmd= will monitor =mpd= for song playback & note when songs complete; this is how it knows to increment the playcount & update the last played timestamp for each song to which you listen. =mppopmd= records this information (i.e. play counts, last played and ratings) using =mpd= [[https://www.musicpd.org/doc/html/protocol.html#stickers][stickers]]. A sticker is a little bit of textual information which clients can attach to songs in the form of a name-value pair. [[https://github.com/sp1ff/mpdpopm][mpdpopm]] defines a new sticker name for each of these items & udpates the values for each song when & as requested.
+
+Of course, other =mpd= clients will not, in general, be aware of =mppopmd= or the stickers it sets: you the user will have to bridge that gap. You could of course just fire-up =netcat= & start sending commands over the MPD protocol using =sendmessage=, but that's not particularly convenient-- that's where =mppopm= comes in. =mppopm= is the client interface; one can through it instruct =mppopmd= to set ratings, get & set the various stickers mpdpopm knows about, and even search for songs in terms of mpdpopm attributes & add them to the play queue.
+
+** Getting Set-up
+
+*** MPD
+
+If you're reading this, I assume you already have MPD up & running, so this section will be brief. One note, prompted by user [[https://github.com/m040601][m040601]], however: as mentioned above, [[https://github.com/sp1ff/mpdpopm][mpdpopm]] leverages the MPD sticker database. I was chagrined to find that if you do not configure MPD to maintain a sticker database, all sticker commands will simply be disabled. Therefore, before setting up [[https://github.com/sp1ff/mpdpopm][mpdpopm]], find your =mpd= configuration file and check to be sure you have a =sticker_file= entry; something like this:
+
+#+BEGIN_EXAMPLE
+  sticker_file "/home/sp1ff/lib/mpd/sticker.sql"
+#+END_EXAMPLE
+
+Check also that the you have write access to the named file & its parent directory.
+
+*** mppopmd
+
+The daemon depends on a configuration file that you'll need to provide. Most =mppopmd= configuration items have sensible defaults, but there are a few that will need to be customized to your MPD setup. A sample configuration file is provided with all distributions; see also the user [[https://www.unwoundstack.com/doc/mpdpopm/curr#mppopmd-Configuration][manual]] for detailed documentation.
+
+You'll likely want to run the program in the foreground initially for ease of trouble-shooting, but after that you'll probably want to run it as a daemon. Again see the [[https://www.unwoundstack.com/doc/mpdopmd/curr#mppopmd-as-a-Daemon][manual]] for detailed instructions.
+
+Once you've got the daemon running to your satisfaction, if you're on a systemd-based Linux distribution, have a look at the sample systemd unit file thanks to [[https://github.com/tanshoku][tanshoku]].
+
+[[https://github.com/tanshoku][tanshoku]] was kind enough to contribute a systemd unit for this purpose. At present, the build does not install it, but provides it as an example and leaves it to the user to install should they desire (and after they have edited it to suit their configuration). You can find it in =${prefix}/share/mpdpopm/examples= for the Autotools distribution, =/usr/local/share/mpdpopm/examples= for the Debian package, and in the =doc= folder for the pre-built binaries.
+
+*** mppopm
+
+At this point, [[https://github.com/sp1ff/mpdpopm][mpdpopm]] will happily monitor your playback history & keep play counts & last played timestamps for you. If you would like to rate tracks, however, you will need to somehow induce your favorite mpd client to send a "rating" message to the [[https://github.com/sp1ff/mpdpopm][mpdpopm]] commands channel ("unwoundstack.com:commands" by default). Since this is unlikely to be convenient, I wrote an mpd client for the purpose: a little CLI called =mppopm=. You can simply execute
+
+#+BEGIN_SRC bash
+mppopm set-rating '*****'
+#+END_SRC
+
+to set the current track's rating to five "stars" (say =mppopm --help= for an explanation of the rating system; in brief-- it's Winamp's). NB. the set rating command by default produces no output; if you want confirmation that something's happening, use the =-v= flag.
+
+The CLI offers "get" & "set" commands for play counts, last played timestamps & the rating. It also provides commands for searching your songs on the basis of play count, rating & last played times in addition to the usual artist, title &c. Say =mppopm --help= for a full list of options, including how to tell it where the mpd server can be found on your network.
+
+* Status & Roadmap
+
+I am currently using [[https://github.com/sp1ff/mpdpopm][mpdpopm]] day in & day out with my music collection, but it's early days; I have chosen the version number (0.n) in the hopes of indicating that. Right now, mpdpopm is the bare-bones of an app: it's plumbing, not the sink.
+
+Heretofore, you could use the =mppopm= CLI to, say, rate the current song, but in order to actually _do_ anything with that rating in the future, you'd have had to  write some kind of mpd client for yourself. With the 0.2 release, I've added support for extended MPD filter syntax that allows queries that include the stickers that [[https://github.com/sp1ff/mpdpopm][mpdpopm]] manages-- so you can now, for instance, say:
+
+#+BEGIN_EXAMPLE
+mppopm findadd "(artist =~ \"foo\") and (rating > 175)"
+#+END_EXAMPLE
+
+MPD will handle the "artist =~" clause & [[https://github.com/sp1ff/mpdpopm][mpdpopm]] the "rating >" clause, as well as combining the results.
+
+This will hopefully be a start to making [[https://github.com/sp1ff/mpdpopm][mpdpopm]] into a more of a user-facing application than a developer-facing utlity.
+
+Windows support may be some time coming; the daemon depends on Unix signal handling, the MPD Unix socket, and the Unix daemon logic, especially =fork= & =exec=... if you'd like to run it on Windows, let me know-- if there's enough interest, and I can get some kind of Windows VM setup, I'll look at a port.
+
+Longer-term, I see [[https://github.com/sp1ff/mpdpopm][mpdpopm]] as a "dual" to mpd-- mpd commits to never altering your files. mpdpopm will take on that task in terms of tags, at least. To address the "plumbing, not the sink" problem, I'd like to author a client that will handle player control (of course), but also visualization & tag editing-- a complete music library solution.
+
+Suggestions, bug reports & PRs welcome!
diff --git a/pkgs/by-name/mp/mpdpopm/build.rs b/pkgs/by-name/mp/mpdpopm/build.rs
new file mode 100644
index 00000000..04586f29
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/build.rs
@@ -0,0 +1,15 @@
+extern crate lalrpop;
+fn main() {
+    let out_dir = std::env::var("OUT_DIR").unwrap();
+
+    lalrpop::Configuration::new()
+        .emit_comments(true)
+        .emit_whitespace(true)
+        .log_verbose()
+        .set_out_dir(out_dir)
+        .process_dir("./")
+        .unwrap();
+
+    println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-changed=./src/filters.lalrpop");
+}
diff --git a/pkgs/by-name/mp/mpdpopm/config.lsp b/pkgs/by-name/mp/mpdpopm/config.lsp
new file mode 100644
index 00000000..0e9b587d
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/config.lsp
@@ -0,0 +1,10 @@
+{
+  "conn": {
+    "Local": {
+      "path": "/run/user/1000/mpd/socket"
+    }
+  },
+  "local_music_dir": "/home/soispha/media/music/beets",
+  "log": "/home/soispha/.local/share/mpdpopm/log",
+  "version": "1"
+}
diff --git a/pkgs/by-name/mp/mpdpopm/flake.lock b/pkgs/by-name/mp/mpdpopm/flake.lock
new file mode 100644
index 00000000..c1d50dc3
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/flake.lock
@@ -0,0 +1,48 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1769237874,
+        "narHash": "sha256-saOixpqPT4fiE/M8EfHv9I98f3sSEvt6nhMJ/z0a7xI=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "523257564973361cc3e55e3df3e77e68c20b0b80",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nixpkgs": "nixpkgs",
+        "treefmt-nix": "treefmt-nix"
+      }
+    },
+    "treefmt-nix": {
+      "inputs": {
+        "nixpkgs": [
+          "nixpkgs"
+        ]
+      },
+      "locked": {
+        "lastModified": 1768158989,
+        "narHash": "sha256-67vyT1+xClLldnumAzCTBvU0jLZ1YBcf4vANRWP3+Ak=",
+        "owner": "numtide",
+        "repo": "treefmt-nix",
+        "rev": "e96d59dff5c0d7fddb9d113ba108f03c3ef99eca",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "treefmt-nix",
+        "type": "github"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/pkgs/by-name/mp/mpdpopm/flake.nix b/pkgs/by-name/mp/mpdpopm/flake.nix
new file mode 100644
index 00000000..f6b622fe
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/flake.nix
@@ -0,0 +1,66 @@
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+{
+  description = "A mpd rating tracker";
+
+  inputs = {
+    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+
+    treefmt-nix = {
+      url = "github:numtide/treefmt-nix";
+      inputs = {
+        nixpkgs.follows = "nixpkgs";
+      };
+    };
+  };
+
+  outputs = {
+    self,
+    nixpkgs,
+    treefmt-nix,
+    ...
+  }: let
+    system = "x86_64-linux";
+    pkgs = nixpkgs.legacyPackages."${system}";
+
+    treefmtEval = import ./treefmt.nix {inherit treefmt-nix pkgs;};
+  in {
+    checks."${system}" = {
+      formatting = treefmtEval.config.build.check self;
+    };
+
+    formatter."${system}" = treefmtEval.config.build.wrapper;
+
+    devShells."${system}".default = pkgs.mkShell {
+      packages = [
+        # rust stuff
+        pkgs.cargo
+        pkgs.clippy
+        pkgs.rustc
+        pkgs.rustfmt
+        pkgs.mold
+
+        pkgs.cargo-edit
+        pkgs.cargo-expand
+        pkgs.cargo-flamegraph
+
+        # Releng
+        pkgs.git-bug
+        pkgs.reuse
+        pkgs.cocogitto
+
+        # Perf
+        pkgs.hyperfine
+      ];
+    };
+  };
+}
+# vim: ts=2
+
diff --git a/pkgs/by-name/ya/yambar-modules/package.nix b/pkgs/by-name/mp/mpdpopm/package.nix
index ea25633e..907bb1cf 100644
--- a/pkgs/by-name/ya/yambar-modules/package.nix
+++ b/pkgs/by-name/mp/mpdpopm/package.nix
@@ -7,17 +7,23 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{rustPlatform}:
-rustPlatform.buildRustPackage {
-  pname = "yambar-modules";
+{
+  rustPlatform,
+  lib,
+}:
+rustPlatform.buildRustPackage (finalAttrs: {
+  pname = "mpdpopm";
   version = "0.1.0";
 
+  buildInputs = [];
+  nativeBuildInputs = [ ];
+
   src = ./.;
   cargoLock = {
     lockFile = ./Cargo.lock;
   };
 
   meta = {
-    mainProgram = "yambar-modules";
+    mainProgram = "mpdpopm";
   };
-}
+})
diff --git a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs
new file mode 100644
index 00000000..faa651bf
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopm.rs
@@ -0,0 +1,604 @@
+// Copyright (C) 2020-2025 Michael herstine <sp1ff@pobox.com>
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+//! # mppopm
+//!
+//! mppopmd client
+//!
+//! # Introduction
+//!
+//! `mppopmd` is a companion daemon for [mpd](https://www.musicpd.org/) that maintains play counts &
+//! ratings. Similar to [mpdfav](https://github.com/vincent-petithory/mpdfav), but written in Rust
+//! (which I prefer to Go), it will allow you to maintain that information in your tags, as well as
+//! the sticker database, by invoking external commands to keep your tags up-to-date (something
+//! along the lines of [mpdcron](https://alip.github.io/mpdcron)). `mppopm` is a command-line client
+//! for `mppopmd`. Run `mppopm --help` for detailed usage.
+
+use mpdpopm::{
+    clients::{Client, PlayerStatus},
+    config::{self, Config},
+    filters::ExpressionParser,
+    filters_ast::{FilterStickerNames, evaluate},
+    messanges::COMMAND_CHANNEL,
+    storage::{last_played, play_count, rating},
+};
+
+use anyhow::{Context, Result, anyhow, bail};
+use clap::{Parser, Subcommand};
+use tracing::{debug, info, level_filters::LevelFilter, trace};
+use tracing_subscriber::{EnvFilter, Registry, layer::SubscriberExt};
+
+use std::path::PathBuf;
+
+/// Map `tracks' argument(s) to a Vec of String containing one or more mpd URIs
+///
+/// Several sub-commands take zero or more positional arguments meant to name tracks, with the
+/// convention that zero indicates that the sub-command should use the currently playing track.
+/// This is a convenience function for mapping the value returned by [`get_many`] to a
+/// convenient representation of the user's intentions.
+///
+/// [`get_many`]: [`clap::ArgMatches::get_many`]
+async fn map_tracks(client: &mut Client, args: Option<Vec<String>>) -> Result<Vec<String>> {
+    let files = match args {
+        Some(iter) => iter,
+        None => {
+            let file = provide_file(client, None).await?;
+            vec![file]
+        }
+    };
+    Ok(files)
+}
+
+async fn provide_file(client: &mut Client, maybe_file: Option<String>) -> Result<String> {
+    let file = match maybe_file {
+        Some(file) => file,
+        None => {
+            match client
+                .status()
+                .await
+                .context("Failed to get status of client")?
+            {
+                PlayerStatus::Play(curr) | PlayerStatus::Pause(curr) => curr
+                    .file
+                    .to_str()
+                    .ok_or_else(|| anyhow!("Path is not utf8: `{}`", curr.file.display()))?
+                    .to_string(),
+                PlayerStatus::Stopped => {
+                    bail!("Player is stopped");
+                }
+            }
+        }
+    };
+
+    Ok(file)
+}
+
+/// Retrieve ratings for one or more tracks
+async fn get_ratings(
+    client: &mut Client,
+    tracks: Option<Vec<String>>,
+    with_uri: bool,
+) -> Result<()> {
+    let mut ratings: Vec<(String, i8)> = Vec::new();
+
+    for file in map_tracks(client, tracks).await? {
+        let rating = rating::get(client, &file).await?;
+
+        ratings.push((file, rating.unwrap_or_default()));
+    }
+
+    if ratings.len() == 1 && !with_uri {
+        println!("{}", ratings[0].1);
+    } else {
+        for pair in ratings {
+            println!("{}: {}", pair.0, pair.1);
+        }
+    }
+
+    Ok(())
+}
+
+/// Rate a track
+async fn set_rating(client: &mut Client, rating: i8, arg: Option<String>) -> Result<()> {
+    let is_current = arg.is_none();
+    let file = provide_file(client, arg).await?;
+
+    rating::set(client, &file, rating).await?;
+
+    match is_current {
+        false => info!("Set the rating for \"{}\" to \"{}\".", file, rating),
+        true => info!("Set the rating for the current song to \"{}\".", rating),
+    }
+
+    Ok(())
+}
+
+/// Rate a track by incrementing the current rating
+async fn inc_rating(client: &mut Client, arg: Option<String>) -> Result<()> {
+    let is_current = arg.is_none();
+    let file = provide_file(client, arg).await?;
+
+    let now = rating::get(client, &file).await?;
+
+    rating::set(client, &file, now.unwrap_or_default().saturating_add(1)).await?;
+
+    match is_current {
+        false => info!("Incremented the rating for \"{}\".", file),
+        true => info!("Incremented the rating for the current song."),
+    }
+
+    Ok(())
+}
+
+/// Rate a track by decrementing the current rating
+async fn decr_rating(client: &mut Client, arg: Option<String>) -> Result<()> {
+    let is_current = arg.is_none();
+    let file = provide_file(client, arg).await?;
+
+    let now = rating::get(client, &file).await?;
+
+    rating::set(client, &file, now.unwrap_or_default().saturating_sub(1)).await?;
+
+    match is_current {
+        false => info!("Decremented the rating for \"{}\".", file),
+        true => info!("Decremented the rating for the current song."),
+    }
+
+    Ok(())
+}
+
+/// Retrieve the playcount for one or more tracks
+async fn get_play_counts(
+    client: &mut Client,
+    tracks: Option<Vec<String>>,
+    with_uri: bool,
+) -> Result<()> {
+    let mut playcounts: Vec<(String, usize)> = Vec::new();
+    for file in map_tracks(client, tracks).await? {
+        let playcount = play_count::get(client, &file).await?.unwrap_or_default();
+        playcounts.push((file, playcount));
+    }
+
+    if playcounts.len() == 1 && !with_uri {
+        println!("{}", playcounts[0].1);
+    } else {
+        for pair in playcounts {
+            println!("{}: {}", pair.0, pair.1);
+        }
+    }
+
+    Ok(())
+}
+
+/// Set the playcount for a track
+async fn set_play_counts(client: &mut Client, playcount: usize, arg: Option<String>) -> Result<()> {
+    let is_current = arg.is_none();
+    let file = provide_file(client, arg).await?;
+
+    play_count::set(client, &file, playcount).await?;
+
+    match is_current {
+        false => info!("Set the playcount for \"{}\" to \"{}\".", file, playcount),
+        true => info!(
+            "Set the playcount for the current song to \"{}\".",
+            playcount
+        ),
+    }
+
+    Ok(())
+}
+
+/// Retrieve the last played time for one or more tracks
+async fn get_last_playeds(
+    client: &mut Client,
+    tracks: Option<Vec<String>>,
+    with_uri: bool,
+) -> Result<()> {
+    let mut lastplayeds: Vec<(String, Option<u64>)> = Vec::new();
+    for file in map_tracks(client, tracks).await? {
+        let lastplayed = last_played::get(client, &file).await?;
+        lastplayeds.push((file, lastplayed));
+    }
+
+    if lastplayeds.len() == 1 && !with_uri {
+        println!(
+            "{}",
+            match lastplayeds[0].1 {
+                Some(t) => format!("{}", t),
+                None => String::from("N/A"),
+            }
+        );
+    } else {
+        for pair in lastplayeds {
+            println!(
+                "{}: {}",
+                pair.0,
+                match pair.1 {
+                    Some(t) => format!("{}", t),
+                    None => String::from("N/A"),
+                }
+            );
+        }
+    }
+
+    Ok(())
+}
+
+/// Set the playcount for a track
+async fn set_last_playeds(client: &mut Client, lastplayed: u64, arg: Option<String>) -> Result<()> {
+    let is_current = arg.is_none();
+    let file = provide_file(client, arg).await?;
+
+    last_played::set(client, &file, lastplayed).await?;
+
+    match is_current {
+        false => info!("Set last played for \"{}\" to \"{}\".", file, lastplayed),
+        true => info!(
+            "Set last played for the current song to \"{}\".",
+            lastplayed
+        ),
+    }
+
+    Ok(())
+}
+
+/// Retrieve the list of stored playlists
+async fn get_playlists(client: &mut Client) -> Result<()> {
+    let mut pls = client.get_stored_playlists().await?;
+    pls.sort();
+    println!("Stored playlists:");
+    for pl in pls {
+        println!("{}", pl);
+    }
+    Ok(())
+}
+
+/// Add songs selected by filter to the queue
+async fn searchadd(client: &mut Client, filter: &str, case_sensitive: bool) -> Result<()> {
+    let ast = match ExpressionParser::new().parse(filter) {
+        Ok(ast) => ast,
+        Err(err) => {
+            bail!("Failed to parse filter: `{}`", err)
+        }
+    };
+
+    debug!("ast: {:#?}", ast);
+
+    let mut results = Vec::new();
+    for song in evaluate(&ast, case_sensitive, client, &FilterStickerNames::default())
+        .await
+        .context("Failed to evaluate filter")?
+    {
+        let out = client.add(&song).await;
+
+        if out.is_ok() {
+            eprintln!("Added: `{}`", song)
+        }
+
+        results.push(out);
+    }
+
+    match results.into_iter().collect::<Result<Vec<()>>>() {
+        Ok(_) => Ok(()),
+        Err(err) => Err(err),
+    }
+}
+
+/// `mppopmd' client
+#[derive(Parser)]
+struct Args {
+    /// path to configuration file
+    #[arg(short, long)]
+    config: Option<PathBuf>,
+
+    /// enable verbose logging
+    #[arg(short, long)]
+    verbose: bool,
+
+    /// enable debug loggin (implies --verbose)
+    #[arg(short, long)]
+    debug: bool,
+
+    #[command(subcommand)]
+    command: SubCommand,
+}
+
+#[derive(Subcommand)]
+enum RatingCommand {
+    /// retrieve the rating for one or more tracks
+    ///
+    /// With no arguments, retrieve the rating of the current song & print it
+    /// on stdout. With one argument, retrieve that track's rating & print it
+    /// on stdout. With multiple arguments, print their ratings on stdout, one
+    /// per line, prefixed by the track name.
+    ///
+    /// Ratings are expressed as an integer between -128 & 128, exclusive, with
+    /// the convention that 0 denotes "un-rated".
+    #[clap(verbatim_doc_comment)]
+    Get {
+        /// Always show the song URI, even when there is only one track
+        #[arg(short, long)]
+        with_uri: bool,
+
+        tracks: Option<Vec<String>>,
+    },
+
+    /// set the rating for one track
+    ///
+    /// With one argument, set the rating of the current song to that argument.
+    /// With a second argument, rate that song at the first argument. Ratings
+    /// may be expressed a an integer between 0 & 255, inclusive.
+    #[clap(verbatim_doc_comment)]
+    Set { rating: i8, track: Option<String> },
+
+    /// increment the rating for one track
+    ///
+    /// With one argument, increment the rating of the current song.
+    /// With a second argument, rate that song at the first argument.
+    #[clap(verbatim_doc_comment)]
+    Inc { track: Option<String> },
+
+    /// decrement the rating for one track
+    ///
+    /// With one argument, decrement the rating of the current song.
+    /// With a second argument, rate that song at the first argument.
+    #[clap(verbatim_doc_comment)]
+    Decr { track: Option<String> },
+}
+
+#[derive(Subcommand)]
+enum PlayCountCommand {
+    /// retrieve the play count for one or more tracks
+    ///
+    /// With no arguments, retrieve the play count of the current song & print it
+    /// on stdout. With one argument, retrieve that track's play count & print it
+    /// on stdout. With multiple arguments, print their play counts on stdout, one
+    /// per line, prefixed by the track name.
+    #[clap(verbatim_doc_comment)]
+    Get {
+        /// Always show the song URI, even when there is only one track
+        #[arg(short, long)]
+        with_uri: bool,
+
+        tracks: Option<Vec<String>>,
+    },
+
+    /// set the play count for one track
+    ///
+    /// With one argument, set the play count of the current song to that argument. With a
+    /// second argument, set the play count for that song to the first.
+    #[clap(verbatim_doc_comment)]
+    Set {
+        play_count: usize,
+        track: Option<String>,
+    },
+}
+
+#[derive(Subcommand)]
+enum LastPlayedCommand {
+    /// retrieve the last played timestamp for one or more tracks
+    ///
+    /// With no arguments, retrieve the last played timestamp of the current
+    /// song & print it on stdout. With one argument, retrieve that track's
+    /// last played time & print it on stdout. With multiple arguments, print
+    /// their last played times on stdout, one per line, prefixed by the track
+    /// name.
+    ///
+    /// The last played timestamp is expressed in seconds since Unix epoch.
+    #[clap(verbatim_doc_comment)]
+    Get {
+        /// Always show the song URI, even when there is only one track
+        #[arg(short, long)]
+        with_uri: bool,
+
+        tracks: Option<Vec<String>>,
+    },
+
+    /// set the last played timestamp for one track
+    ///
+    /// With one argument, set the last played time of the current song. With two
+    /// arguments, set the last played time for the second argument to the first.
+    /// The last played timestamp is expressed in seconds since Unix epoch.
+    #[clap(verbatim_doc_comment)]
+    Set {
+        last_played: u64,
+        track: Option<String>,
+    },
+}
+
+#[derive(Subcommand)]
+enum PlaylistsCommand {
+    /// retrieve the list of stored playlists
+    #[clap(verbatim_doc_comment)]
+    Get {},
+}
+
+#[derive(Subcommand)]
+enum DjCommand {
+    /// Activate the automatic DJ mode on the mpdpopmd daemon.
+    ///
+    /// In this mode, the daemon will automatically add new tracks to the playlist based on a
+    /// recommendation algorithm.
+    #[clap(verbatim_doc_comment)]
+    Start {},
+
+    /// Deactivate the automatic DJ mode on the mpdpopmd daemon.
+    ///
+    /// In this mode, the daemon will automatically add new tracks to the playlist based on a
+    /// recommendation algorithm.
+    #[clap(verbatim_doc_comment)]
+    Stop {},
+}
+
+#[derive(Subcommand)]
+enum SubCommand {
+    /// Change details about rating.
+    Rating {
+        #[command(subcommand)]
+        command: RatingCommand,
+    },
+
+    /// Change details about play count.
+    PlayCount {
+        #[command(subcommand)]
+        command: PlayCountCommand,
+    },
+
+    /// Change details about last played date.
+    LastPlayed {
+        #[command(subcommand)]
+        command: LastPlayedCommand,
+    },
+
+    /// Change details about generated playlists.
+    Playlists {
+        #[command(subcommand)]
+        command: PlaylistsCommand,
+    },
+
+    /// search for songs matching matching a filter and add them to the queue
+    ///
+    /// This command extends the MPD command `searchadd' (which will search the MPD database) to allow
+    /// searches on attributes managed by mpdpopm: rating, playcount & last played time.
+    ///
+    /// The MPD `searchadd' <https://www.musicpd.org/doc/html/protocol.html#command-searchadd> will search
+    /// the MPD database for songs that match a given filter & add them to the play queue. The filter syntax
+    /// is documented here <https://www.musicpd.org/doc/html/protocol.html#filter-syntax>.
+    ///
+    /// This command adds three new terms on which you can filter: rating, playcount & lastplayed. Each is
+    /// expressed as an unsigned integer, with zero interpreted as "not set". For instance:
+    ///
+    ///     mppopm searchadd "(rating > 2)"
+    ///
+    /// Will add all songs in the library with a rating sticker > 2 to the play queue.
+    ///
+    /// mppopm also introduces OR clauses (MPD only supports AND), so that:
+    ///
+    ///     mppopm searchadd "((rating > 2) AND (artist =~ \"pogues\"))"
+    ///
+    /// will add all songs whose artist tag matches the regexp "pogues" with a rating greater than
+    /// 2.
+    #[clap(verbatim_doc_comment)]
+    Searchadd {
+        filter: String,
+
+        /// Respect the casing, when performing the filter evaluation.
+        #[arg(short, long, default_value_t = false)]
+        case_sensitive: bool,
+    },
+
+    /// Modify the automatic DJ mode on the mpdpopmd daemon.
+    ///
+    /// In this mode, the daemon will automatically add new tracks to the playlist based on a
+    /// recommendation algorithm.
+    Dj {
+        #[command(subcommand)]
+        command: DjCommand,
+    },
+}
+
+#[tokio::main]
+async fn main() -> Result<()> {
+    let args = Args::parse();
+
+    let config = if let Some(configpath) = &args.config {
+        match std::fs::read_to_string(configpath) {
+            Ok(text) => config::from_str(&text).with_context(|| {
+                format!("Failed to parse config file at: `{}`", configpath.display())
+            })?,
+            Err(err) => {
+                // Either they did _not_, in which case they probably want to know that the config
+                // file they explicitly asked for does not exist, or there was some other problem,
+                // in which case we're out of options, anyway. Either way:
+                bail!(
+                    "Failed to read config file at: `{}`, because: {err}",
+                    configpath.display()
+                )
+            }
+        }
+    } else {
+        Config::default()
+    };
+
+    // Handle log verbosity: debug => verbose
+    let lf = match (args.verbose, args.debug) {
+        (_, true) => LevelFilter::TRACE,
+        (true, false) => LevelFilter::DEBUG,
+        _ => LevelFilter::WARN,
+    };
+
+    tracing::subscriber::set_global_default(
+        Registry::default()
+            .with(
+                tracing_subscriber::fmt::Layer::default()
+                    .compact()
+                    .with_writer(std::io::stdout),
+            )
+            .with(
+                EnvFilter::builder()
+                    .with_default_directive(lf.into())
+                    .from_env()
+                    .unwrap(),
+            ),
+    )
+    .unwrap();
+
+    trace!("logging configured.");
+
+    let mut client = match config.conn {
+        config::Connection::Local { path } => Client::open(path).await?,
+        config::Connection::TCP { host, port } => {
+            Client::connect(format!("{}:{}", host, port)).await?
+        }
+    };
+
+    match args.command {
+        SubCommand::Rating { command } => match command {
+            RatingCommand::Get { with_uri, tracks } => {
+                get_ratings(&mut client, tracks, with_uri).await
+            }
+            RatingCommand::Set { rating, track } => set_rating(&mut client, rating, track).await,
+            RatingCommand::Inc { track } => inc_rating(&mut client, track).await,
+            RatingCommand::Decr { track } => decr_rating(&mut client, track).await,
+        },
+        SubCommand::PlayCount { command } => match command {
+            PlayCountCommand::Get { with_uri, tracks } => {
+                get_play_counts(&mut client, tracks, with_uri).await
+            }
+            PlayCountCommand::Set { play_count, track } => {
+                set_play_counts(&mut client, play_count, track).await
+            }
+        },
+        SubCommand::LastPlayed { command } => match command {
+            LastPlayedCommand::Get { with_uri, tracks } => {
+                get_last_playeds(&mut client, tracks, with_uri).await
+            }
+            LastPlayedCommand::Set { last_played, track } => {
+                set_last_playeds(&mut client, last_played, track).await
+            }
+        },
+        SubCommand::Playlists { command } => match command {
+            PlaylistsCommand::Get {} => get_playlists(&mut client).await,
+        },
+        SubCommand::Searchadd {
+            filter,
+            case_sensitive,
+        } => searchadd(&mut client, &filter, case_sensitive).await,
+        SubCommand::Dj { command } => match command {
+            DjCommand::Start {} => client.send_message(COMMAND_CHANNEL, "dj start").await,
+            DjCommand::Stop {} => client.send_message(COMMAND_CHANNEL, "dj stop").await,
+        },
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs
new file mode 100644
index 00000000..643611d6
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/bin/mpdpopmd.rs
@@ -0,0 +1,150 @@
+// Copyright (C) 2020-2025 Michael herstine <sp1ff@pobox.com>
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+//! # mppopmd
+//!
+//! Maintain ratings & playcounts for your mpd server.
+//!
+//! # Introduction
+//!
+//! This is a companion daemon for [mpd](https://www.musicpd.org/) that maintains play counts &
+//! ratings. Similar to [mpdfav](https://github.com/vincent-petithory/mpdfav), but written in Rust
+//! (which I prefer to Go), it will allow you to maintain that information in your tags, as well as
+//! the sticker database, by invoking external commands to keep your tags up-to-date (something
+//! along the lines of [mpdcron](https://alip.github.io/mpdcron)).
+
+use mpdpopm::{
+    config::{self, Config},
+    mpdpopm,
+};
+
+use anyhow::{Context, Result, bail};
+use clap::Parser;
+use tracing::{info, level_filters::LevelFilter};
+use tracing_subscriber::{EnvFilter, Layer, Registry, layer::SubscriberExt};
+
+use std::{io, path::PathBuf, sync::MutexGuard};
+
+pub struct MyMutexGuardWriter<'a>(MutexGuard<'a, std::fs::File>);
+
+impl io::Write for MyMutexGuardWriter<'_> {
+    #[inline]
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    #[inline]
+    fn flush(&mut self) -> io::Result<()> {
+        self.0.flush()
+    }
+
+    #[inline]
+    fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    #[inline]
+    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
+        self.0.write_all(buf)
+    }
+
+    #[inline]
+    fn write_fmt(&mut self, fmt: std::fmt::Arguments<'_>) -> io::Result<()> {
+        self.0.write_fmt(fmt)
+    }
+}
+
+/// mpd + POPM
+///
+/// `mppopmd' is a companion daemon for `mpd' that maintains playcounts & ratings,
+/// as well as implementing some handy functions. It maintains ratings & playcounts in the sticker
+/// database, but it allows you to keep that information in your tags, as well, by invoking external
+/// commands to keep your tags up-to-date.
+#[derive(Parser)]
+struct Args {
+    /// path to configuration file
+    #[arg(short, long)]
+    config: Option<PathBuf>,
+
+    /// enable verbose logging
+    #[arg(short, long)]
+    verbose: bool,
+
+    /// enable debug loggin (implies --verbose)
+    #[arg(short, long)]
+    debug: bool,
+}
+
+/// Entry point for `mpdopmd'.
+///
+/// Do *not* use the #[tokio::main] attribute here! If this program is asked to daemonize (the usual
+/// case), we will fork after tokio has started its thread pool, with disastrous consequences.
+/// Instead, stay synchronous until we've daemonized (or figured out that we don't need to), and
+/// only then fire-up the tokio runtime.
+fn main() -> Result<()> {
+    use mpdpopm::vars::VERSION;
+
+    let args = Args::parse();
+
+    let config = if let Some(cfgpath) = &args.config {
+        match std::fs::read_to_string(cfgpath) {
+            Ok(text) => config::from_str(&text).with_context(|| {
+                format!("Failed to parse config file at: `{}`", cfgpath.display())
+            })?,
+            // The config file (defaulted or not) either didn't exist, or we were unable to read its
+            // contents...
+            Err(err) => {
+                // Either they did _not_, in which case they probably want to know that the config
+                // file they explicitly asked for does not exist, or there was some other problem,
+                // in which case we're out of options, anyway. Either way:
+                bail!(
+                    "No config file could be read at: `{}`, because: {err}",
+                    cfgpath.display()
+                )
+            }
+        }
+    } else {
+        Config::default()
+    };
+
+    // `--verbose' & `--debug' work as follows: if `--debug' is present, log at level Trace, no
+    // matter what. Else, if `--verbose' is present, log at level Debug. Else, log at level Info.
+    let lf = match (args.verbose, args.debug) {
+        (_, true) => LevelFilter::TRACE,
+        (true, false) => LevelFilter::DEBUG,
+        _ => LevelFilter::INFO,
+    };
+
+    let filter = EnvFilter::builder()
+        .with_default_directive(lf.into())
+        .from_env()
+        .context("Failed to construct env filter")?;
+
+    let formatter: Box<dyn Layer<Registry> + Send + Sync> = {
+        Box::new(
+            tracing_subscriber::fmt::Layer::default()
+                .compact()
+                .with_writer(io::stdout),
+        )
+    };
+
+    tracing::subscriber::set_global_default(Registry::default().with(formatter).with(filter))
+        .unwrap();
+
+    info!("mppopmd {VERSION} logging at level {lf:#?}.");
+    let rt = tokio::runtime::Runtime::new().unwrap();
+
+    rt.block_on(mpdpopm(config)).context("Main mpdpopm failed")
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/clients.rs b/pkgs/by-name/mp/mpdpopm/src/clients.rs
new file mode 100644
index 00000000..b934714a
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/clients.rs
@@ -0,0 +1,1200 @@
+// Copyright (C) 2020-2025 Michael herstine <sp1ff@pobox.com>
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+//! mpd clients and associated utilities.
+//!
+//! # Introduction
+//!
+//! This module contains basic types implementing various MPD client operations (cf. the [mpd
+//! protocol](http://www.musicpd.org/doc/protocol/)). Since issuing the "idle" command will tie up
+//! the connection, MPD clients often use multiple connections to the server (one to listen for
+//! updates, one or more on which to issue commands). This modules provides two different client
+//! types: [Client] for general-purpose use and [IdleClient] for long-lived connections listening
+//! for server notifiations.
+//!
+//! Note that there *is* another idiom (used in [libmpdel](https://github.com/mpdel/libmpdel),
+//! e.g.): open a single connection & issue an "idle" command. When you want to issue a command,
+//! send a "noidle", then the command, then "idle" again.  This isn't a race condition, as the
+//! server will buffer any changes that took place when you were not idle & send them when you
+//! re-issue the "idle" command. This crate however takes the approach of two channels (like
+//! [mpdfav](https://github.com/vincent-petithory/mpdfav)).
+
+use anyhow::{Context, Error, Result, anyhow, bail, ensure};
+use async_trait::async_trait;
+use regex::Regex;
+use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
+use tokio::net::{TcpStream, ToSocketAddrs, UnixStream};
+use tracing::{debug, info};
+
+use lazy_static::lazy_static;
+
+use std::{
+    collections::HashMap,
+    convert::TryFrom,
+    fmt,
+    marker::{Send, Unpin},
+    path::{Path, PathBuf},
+    str::FromStr,
+};
+
+// Some default error context messages
+const ENCODING_SNAFU: &str = "Failed to interpete text as utf8";
+const IO_SNAFU: &str = "Failed read from mpd socket";
+
+/// A description of the current track, suitable for our purposes (as in, it only tracks the
+/// attributes needed for this module's functionality).
+#[derive(Clone, Debug)]
+pub struct CurrentSong {
+    /// Identifier, unique within the play queue, identifying this particular track; if the same
+    /// file is listed twice in the `mpd' play queue each instance will get a distinct songid
+    pub songid: u64,
+
+    /// Path, relative to `mpd' music directory root of this track
+    pub file: std::path::PathBuf,
+
+    /// Elapsed time, in seconds, in this track
+    pub elapsed: f64,
+
+    /// Total track duration, in seconds
+    pub duration: f64,
+}
+
+impl CurrentSong {
+    fn new(songid: u64, file: std::path::PathBuf, elapsed: f64, duration: f64) -> CurrentSong {
+        CurrentSong {
+            songid,
+            file,
+            elapsed,
+            duration,
+        }
+    }
+    /// Compute the ratio of the track that has elapsed, expressed as a floating point between 0 & 1
+    pub fn played_pct(&self) -> f64 {
+        self.elapsed / self.duration
+    }
+}
+
+/// The MPD player itself can be in one of three states: playing, paused or stopped. In the first
+/// two there is a "current" song.
+#[derive(Clone, Debug)]
+pub enum PlayerStatus {
+    Play(CurrentSong),
+    Pause(CurrentSong),
+    Stopped,
+}
+
+impl PlayerStatus {
+    pub fn current_song(&self) -> Option<&CurrentSong> {
+        match self {
+            PlayerStatus::Play(curr) | PlayerStatus::Pause(curr) => Some(curr),
+            PlayerStatus::Stopped => None,
+        }
+    }
+}
+
+/// A trait representing a simple, textual request/response protocol like that
+/// [employed](https://www.musicpd.org/doc/html/protocol.html) by [MPD](https://www.musicpd.org/):
+/// the caller sends a textual command & the server responds with a (perhaps multi-line) textual
+/// response.
+///
+/// This trait also enables unit testing client implementations. Note that it is async-- cf.
+/// [async_trait](https://docs.rs/async-trait/latest/async_trait/).
+#[async_trait]
+pub trait RequestResponse {
+    async fn req(&mut self, msg: &str) -> Result<String>;
+    /// The hint is used to size the buffer prior to reading the response
+    async fn req_w_hint(&mut self, msg: &str, hint: usize) -> Result<String>;
+}
+
+#[cfg(test)]
+pub mod test_mock {
+    use super::*;
+
+    /// Mock is an implementation of [`RequestRespone`] that checks expected requests & responses,
+    /// and will panic if it sees anything unexpected
+    pub struct Mock {
+        inmsgs: Vec<String>,
+        outmsgs: Vec<String>,
+    }
+
+    impl Mock {
+        pub fn new(convo: &[(&str, &str)]) -> Mock {
+            let (left, right): (Vec<&str>, Vec<&str>) = convo.iter().copied().rev().unzip();
+            Mock {
+                inmsgs: left.iter().map(|x| x.to_string()).collect(),
+                outmsgs: right.iter().map(|x| x.to_string()).collect(),
+            }
+        }
+    }
+
+    #[async_trait]
+    impl RequestResponse for Mock {
+        async fn req(&mut self, msg: &str) -> Result<String> {
+            self.req_w_hint(msg, 512).await
+        }
+        async fn req_w_hint(&mut self, msg: &str, _hint: usize) -> Result<String> {
+            assert_eq!(msg, self.inmsgs.pop().unwrap());
+            Ok(self.outmsgs.pop().unwrap())
+        }
+    }
+
+    #[tokio::test]
+    async fn mock_smoke_test() {
+        let mut mock = Mock::new(&[("ping", "pong"), ("from", "to")]);
+        assert_eq!(mock.req("ping").await.unwrap(), "pong");
+        assert_eq!(mock.req("from").await.unwrap(), "to");
+    }
+
+    #[tokio::test]
+    #[should_panic]
+    async fn mock_negative_test() {
+        let mut mock = Mock::new(&[("ping", "pong")]);
+        assert_eq!(mock.req("ping").await.unwrap(), "pong");
+        let _should_panic = mock.req("not there!").await.unwrap();
+    }
+}
+
+/// [MPD](https://www.musicpd.org/) connections talk the same
+/// [protocol](https://www.musicpd.org/doc/html/protocol.html) over either a TCP or a Unix socket.
+///
+/// # Examples
+///
+/// Implementations are provided for tokio [UnixStream] and [TcpStream], but [MpdConnection] is a
+/// trait that can work in terms of any asynchronous communications channel (so long as it is also
+/// [Send] and [Unpin] so async executors can pass them between threads.
+///
+/// To create a connection to an `MPD` server over a Unix domain socket:
+///
+/// ```no_run
+/// use std::path::Path;
+/// use tokio::net::UnixStream;
+/// use mpdpopm::clients::MpdConnection;
+/// let local_conn = MpdConnection::<UnixStream>::connect(Path::new("/var/run/mpd/mpd.sock"));
+/// ```
+///
+/// In this example, `local_conn` is a Future that will resolve to a Result containing the
+/// [MpdConnection] Unix domain socket implementation once the socket has been established, the MPD
+/// server greets us & the protocol version has been parsed.
+///
+/// or over a TCP socket:
+///
+/// ```no_run
+/// use std::net::SocketAddrV4;
+/// use tokio::net::{TcpStream, ToSocketAddrs};
+/// use mpdpopm::clients::MpdConnection;
+/// let tcp_conn = MpdConnection::<TcpStream>::connect("localhost:6600".parse::<SocketAddrV4>().unwrap());
+/// ```
+///
+/// Here, `tcp_conn` is a Future that will resolve to a Result containing the [MpdConnection] TCP
+/// implementation on successful connection to the MPD server (i.e. the connection is established,
+/// the server greets us & we parse the protocol version).
+///
+///
+pub struct MpdConnection<T: AsyncRead + AsyncWrite + Send + Unpin> {
+    sock: T,
+    _protocol_ver: String,
+}
+
+/// MpdConnection implements RequestResponse using the usual (async) socket I/O
+///
+/// The callers need not include the trailing newline in their requests; the implementation will
+/// append it.
+#[async_trait]
+impl<T> RequestResponse for MpdConnection<T>
+where
+    T: AsyncRead + AsyncWrite + Send + Unpin,
+{
+    async fn req(&mut self, msg: &str) -> Result<String> {
+        self.req_w_hint(msg, 512).await
+    }
+    async fn req_w_hint(&mut self, msg: &str, hint: usize) -> Result<String> {
+        self.sock
+            .write_all(format!("{}\n", msg).as_bytes())
+            .await
+            .context(IO_SNAFU)?;
+        let mut buf = Vec::with_capacity(hint);
+
+        // Given the request/response nature of the MPD protocol, our callers expect a complete
+        // response. Therefore we need to loop here until we see either "...^OK\n" or
+        // "...^ACK...\n".
+        let mut cb = 0; // # bytes read so far
+        let mut more = true; // true as long as there is more to read
+        while more {
+            cb += self.sock.read_buf(&mut buf).await.context(IO_SNAFU)?;
+
+            // The shortest complete response has three bytes. If the final byte in `buf' is not a
+            // newline, then don't bother looking further.
+            if cb > 2 && char::from(buf[cb - 1]) == '\n' {
+                // If we're here, `buf' *may* contain a complete response. Search backward for the
+                // previous newline. It may not exist: many responses are of the form "OK\n".
+                let mut idx = cb - 2;
+                while idx > 0 {
+                    if char::from(buf[idx]) == '\n' {
+                        idx += 1;
+                        break;
+                    }
+                    idx -= 1;
+                }
+
+                if (idx + 2 < cb && char::from(buf[idx]) == 'O' && char::from(buf[idx + 1]) == 'K')
+                    || (idx + 3 < cb
+                        && char::from(buf[idx]) == 'A'
+                        && char::from(buf[idx + 1]) == 'C'
+                        && char::from(buf[idx + 2]) == 'K')
+                {
+                    more = false;
+                }
+            }
+        }
+
+        // Only doing this to trouble-shoot issue 11
+        String::from_utf8(buf.clone()).context(ENCODING_SNAFU)
+    }
+}
+
+/// Utility function to parse the initial response to a connection from mpd
+async fn parse_connect_rsp<T>(sock: &mut T) -> Result<String>
+where
+    T: AsyncReadExt + AsyncWriteExt + Send + Unpin,
+{
+    let mut buf = Vec::with_capacity(32);
+    let _cb = sock.read_buf(&mut buf).await.context(IO_SNAFU)?;
+
+    // Only doing this to trouble-shoot issue 11
+    let text = String::from_utf8(buf.clone()).context(ENCODING_SNAFU)?;
+
+    ensure!(
+        text.starts_with("OK MPD "),
+        "failed to connect: {}",
+        text.trim()
+    );
+    info!("Connected {}.", text[7..].trim());
+    Ok(text[7..].trim().to_string())
+}
+
+impl MpdConnection<TcpStream> {
+    pub async fn connect<A: ToSocketAddrs>(addr: A) -> Result<Box<dyn RequestResponse>> {
+        let mut sock = TcpStream::connect(addr).await.context(IO_SNAFU)?;
+        let proto_ver = parse_connect_rsp(&mut sock).await?;
+        Ok(Box::new(MpdConnection::<TcpStream> {
+            sock,
+            _protocol_ver: proto_ver,
+        }))
+    }
+}
+
+impl MpdConnection<UnixStream> {
+    // NTS: we have to box the return value because a `dyn RequestResponse` isn't Sized.
+    pub async fn connect<P: AsRef<Path>>(pth: P) -> Result<Box<dyn RequestResponse>> {
+        let mut sock = UnixStream::connect(pth).await.context(IO_SNAFU)?;
+        let proto_ver = parse_connect_rsp(&mut sock).await?;
+        Ok(Box::new(MpdConnection::<UnixStream> {
+            sock,
+            _protocol_ver: proto_ver,
+        }))
+    }
+}
+
+/// Quote an argument by backslash-escaping " & \ characters
+pub fn quote(text: &str) -> String {
+    if text.contains(&[' ', '\t', '\'', '"'][..]) {
+        let mut s = String::from("\"");
+        for c in text.chars() {
+            if c == '"' || c == '\\' {
+                s.push('\\');
+            }
+            s.push(c);
+        }
+        s.push('"');
+        s
+    } else {
+        text.to_string()
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                               Client                                           //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// General-purpose [mpd](https://www.musicpd.org)
+/// [client](https://www.musicpd.org/doc/html/protocol.html): "general-purpose" in the sense that we
+/// send commands through it; the interface is narrowly scoped to this program's needs.
+///
+/// # Introduction
+///
+/// This is the primary abstraction of the MPD client protocol, written for the convenience of
+/// [mpdpopm](crate). Construct instances with a TCP socket, a Unix socket, or any [RequestResponse]
+/// implementation. You can then carry out assorted operations in the MPD client protocol by
+/// invoking its methods.
+///
+/// ```no_run
+/// use std::path::Path;
+/// use mpdpopm::clients::Client;
+/// let client = Client::open(Path::new("/var/run/mpd.sock"));
+/// ```
+///
+/// `client` is now a [Future](https://doc.rust-lang.org/stable/std/future/trait.Future.html) that
+/// resolves to a [Client] instance talking to `/var/run/mpd.sock`.
+///
+/// ```no_run
+/// use mpdpopm::clients::Client;
+/// let client = Client::connect("localhost:6600");
+/// ```
+///
+/// `client` is now a [Future](https://doc.rust-lang.org/stable/std/future/trait.Future.html) that
+/// resolves to a [Client] instance talking TCP to the MPD server on localhost at port 6600.
+pub struct Client {
+    stream: Box<dyn RequestResponse>,
+}
+
+// Thanks to <https://stackoverflow.com/questions/35169259/how-to-make-a-compiled-regexp-a-global-variable>
+lazy_static! {
+    static ref RE_STATE: regex::Regex = Regex::new(r"(?m)^state: (play|pause|stop)$").unwrap();
+    static ref RE_SONGID: regex::Regex = Regex::new(r"(?m)^songid: ([0-9]+)$").unwrap();
+    static ref RE_ELAPSED: regex::Regex = Regex::new(r"(?m)^elapsed: ([.0-9]+)$").unwrap();
+    static ref RE_FILE: regex::Regex = Regex::new(r"(?m)^file: (.*)$").unwrap();
+    static ref RE_DURATION: regex::Regex = Regex::new(r"(?m)^duration: (.*)$").unwrap();
+}
+
+impl Client {
+    pub async fn connect<A: ToSocketAddrs>(addrs: A) -> Result<Client> {
+        Self::new(MpdConnection::<TcpStream>::connect(addrs).await?)
+    }
+
+    pub async fn open<P: AsRef<Path>>(pth: P) -> Result<Client> {
+        Self::new(MpdConnection::<UnixStream>::connect(pth).await?)
+    }
+
+    pub fn new(stream: Box<dyn RequestResponse>) -> Result<Client> {
+        Ok(Client { stream })
+    }
+}
+
+impl Client {
+    /// Retrieve the current server status.
+    pub async fn status(&mut self) -> Result<PlayerStatus> {
+        // We begin with sending the "status" command: "Reports the current status of the player and
+        // the volume level." Per the docs, "MPD may omit lines which have no (known) value", so I
+        // can't really count on particular lines being there. Tho nothing is said in the docs, I
+        // also don't want to depend on the order.
+        let text = self.stream.req("status").await?;
+
+        let proto = || -> Error { anyhow!("Failed to parse mpd status output (with regexes)") };
+
+        // I first thought to avoid the use (and cost) of regular expressions by just doing
+        // sub-string searching on "state: ", but when I realized I needed to only match at the
+        // beginning of a line I bailed & just went ahead. This makes for more succinct code, since
+        // I can't count on order, either.
+        let state = RE_STATE
+            .captures(&text)
+            .ok_or_else(proto)?
+            .get(1)
+            .ok_or_else(proto)?
+            .as_str();
+
+        match state {
+            "stop" => Ok(PlayerStatus::Stopped),
+            "play" | "pause" => {
+                let songid = RE_SONGID
+                    .captures(&text)
+                    .ok_or_else(proto)?
+                    .get(1)
+                    .ok_or_else(proto)?
+                    .as_str()
+                    .parse::<u64>()
+                    .context("Failed to parse songid as u64")?;
+
+                let elapsed = RE_ELAPSED
+                    .captures(&text)
+                    .ok_or_else(proto)?
+                    .get(1)
+                    .ok_or_else(proto)?
+                    .as_str()
+                    .parse::<f64>()
+                    .context("failed to parse `elapsed` as f64")?;
+
+                // navigate from `songid'-- don't send a "currentsong" message-- the current song
+                // could have changed
+                let text = self.stream.req(&format!("playlistid {}", songid)).await?;
+
+                let file = RE_FILE
+                    .captures(&text)
+                    .ok_or_else(proto)?
+                    .get(1)
+                    .ok_or_else(proto)?
+                    .as_str();
+                let duration = RE_DURATION
+                    .captures(&text)
+                    .ok_or_else(proto)?
+                    .get(1)
+                    .ok_or_else(proto)?
+                    .as_str()
+                    .parse::<f64>()
+                    .context("Failed to parse `duration` as f64")?;
+
+                let curr = CurrentSong::new(songid, PathBuf::from(file), elapsed, duration);
+
+                if state == "play" {
+                    Ok(PlayerStatus::Play(curr))
+                } else {
+                    Ok(PlayerStatus::Pause(curr))
+                }
+            }
+            _ => bail!("Encountered unknow state `{}`", state),
+        }
+    }
+
+    /// Retrieve a song sticker by name
+    pub async fn get_sticker<T: FromStr>(
+        &mut self,
+        file: &str,
+        sticker_name: &str,
+    ) -> Result<Option<T>>
+    where
+        <T as FromStr>::Err: std::error::Error + Sync + Send + 'static,
+    {
+        let msg = format!("sticker get song {} {}", quote(file), quote(sticker_name));
+        let text = self.stream.req(&msg).await?;
+        debug!("Sent message `{}'; got `{}'", &msg, &text);
+
+        let prefix = format!("sticker: {}=", sticker_name);
+        if text.starts_with(&prefix) {
+            let s = text[prefix.len()..]
+                .split('\n')
+                .next()
+                .with_context(|| format!("Failed to parse `{}` as get_sticker response", text))?;
+            Ok(Some(T::from_str(s).with_context(|| {
+                format!(
+                    "Failed to parse sticker value as correct type: `{}`",
+                    sticker_name
+                )
+            })?))
+        } else {
+            // ACK_ERROR_NO_EXIST = 50 (Ack.hxx:17)
+            ensure!(
+                text.starts_with("ACK [50@0]"),
+                "Missing no sticker response"
+            );
+            Ok(None)
+        }
+    }
+
+    /// Set a song sticker by name
+    pub async fn set_sticker<T: std::fmt::Display>(
+        &mut self,
+        file: &str,
+        sticker_name: &str,
+        sticker_value: &T,
+    ) -> Result<()> {
+        let value_as_str = format!("{}", sticker_value);
+        let msg = format!(
+            "sticker set song {} {} {}",
+            quote(file),
+            quote(sticker_name),
+            quote(&value_as_str)
+        );
+        let text = self.stream.req(&msg).await?;
+        debug!("Sent `{}'; got `{}'", &msg, &text);
+
+        ensure!(text.starts_with("OK"), "Set sticker, not acknowledged");
+        Ok(())
+    }
+
+    /// Send a file to a playlist
+    pub async fn send_to_playlist(&mut self, file: &str, pl: &str) -> Result<()> {
+        let msg = format!("playlistadd {} {}", quote(pl), quote(file));
+        let text = self.stream.req(&msg).await?;
+        debug!("Sent `{}'; got `{}'.", &msg, &text);
+        ensure!(text.starts_with("OK"), "send_to_playlist not acknowledged");
+        Ok(())
+    }
+
+    /// Send an arbitrary message
+    pub async fn send_message(&mut self, chan: &str, msg: &str) -> Result<()> {
+        let msg = format!("sendmessage {} {}", chan, quote(msg));
+        let text = self.stream.req(&msg).await?;
+        debug!("Sent `{}'; got `{}'.", &msg, &text);
+
+        ensure!(text.starts_with("OK"), "Send_message not acknowledged");
+        Ok(())
+    }
+
+    /// Update a URI
+    pub async fn update(&mut self, uri: &str) -> Result<u64> {
+        let msg = format!("update \"{}\"", uri);
+        let text = self.stream.req(&msg).await?;
+        debug!("Sent `{}'; got `{}'.", &msg, &text);
+
+        // We expect a response of the form:
+        //   updating_db: JOBID
+        //   OK
+        // on success, and
+        //   ACK ERR
+        // on failure.
+
+        let prefix = "updating_db: ";
+        ensure!(
+            text.starts_with(prefix),
+            "update response doesn't start with correct prefix"
+        );
+        text[prefix.len()..].split('\n').collect::<Vec<&str>>()[0]
+            .to_string()
+            .parse::<u64>()
+            .context("Failed to treat update job id as u64")
+    }
+
+    /// Get the list of stored playlists
+    pub async fn get_stored_playlists(&mut self) -> Result<std::vec::Vec<String>> {
+        let text = self.stream.req("listplaylists").await?;
+        debug!("Sent listplaylists; got `{}'.", &text);
+
+        // We expect a response of the form:
+        // playlist: a
+        // Last-Modified: 2020-03-13T17:20:16Z
+        // playlsit: b
+        // Last-Modified: 2020-03-13T17:20:16Z
+        // ...
+        // OK
+        //
+        // or
+        //
+        // ACK...
+        ensure!(
+            !text.starts_with("ACK"),
+            "get_stored_playlists response not acknowledged"
+        );
+        Ok(text
+            .lines()
+            .filter_map(|x| x.strip_prefix("playlist: ").map(String::from))
+            .collect::<Vec<String>>())
+    }
+
+    /// Process a search (either find or search) response
+    fn search_rsp_to_uris(&self, text: &str) -> Result<std::vec::Vec<String>> {
+        // We expect a response of the form:
+        // file: P/Pogues, The - A Pistol For Paddy Garcia.mp3
+        // Last-Modified: 2007-12-26T19:18:00Z
+        // Format: 44100:24:2
+        // ...
+        // file: P/Pogues, The - Billy's Bones.mp3
+        // ...
+        // OK
+        //
+        // or
+        //
+        // ACK...
+        ensure!(!text.starts_with("ACK"), "rsp_to_uris not acknowledged");
+        Ok(text
+            .lines()
+            .filter_map(|x| x.strip_prefix("file: ").map(String::from))
+            .collect::<Vec<String>>())
+    }
+
+    /// Search the database for songs matching filter (unary operator)
+    ///
+    /// Set `case` to true to request a case-sensitive search (false yields case-insensitive)
+    pub async fn find1(
+        &mut self,
+        cond: &str,
+        val: &str,
+        case: bool,
+    ) -> Result<std::vec::Vec<String>> {
+        let cmd = format!(
+            "{} {}",
+            if case { "find" } else { "search" },
+            quote(&format!("({} {})", cond, val))
+        );
+        let text = self.stream.req(&cmd).await?;
+        self.search_rsp_to_uris(&text)
+    }
+
+    /// Search the database for songs matching filter (case-sensitive, binary operator)
+    ///
+    /// Set `case` to true to request a case-sensitive search (false yields case-insensitive)
+    pub async fn find2(
+        &mut self,
+        attr: &str,
+        op: &str,
+        val: &str,
+        case: bool,
+    ) -> Result<std::vec::Vec<String>> {
+        let cmd = format!(
+            "{} {}",
+            if case { "find" } else { "search" },
+            quote(&format!("({} {} {})", attr, op, val))
+        );
+        debug!("find2 sending ``{}''", cmd);
+        let text = self.stream.req(&cmd).await?;
+        self.search_rsp_to_uris(&text)
+    }
+
+    /// Retrieve all instances of a given sticker under the music directory
+    ///
+    /// Return a mapping from song URI to textual sticker value
+    pub async fn get_stickers(&mut self, sticker: &str) -> Result<HashMap<String, String>> {
+        let text = self
+            .stream
+            .req(&format!("sticker find song \"\" {}", sticker))
+            .await?;
+
+        // We expect a response of the form:
+        //
+        // file: U-Z/Zafari - Addis Adaba.mp3
+        // sticker: unwoundstack.com:rating=64
+        // ...
+        // file: U-Z/Zero 7 - In Time (Album Version).mp3
+        // sticker: unwoundstack.com:rating=255
+        // OK
+        //
+        // or
+        //
+        // ACK ...
+        ensure!(!text.starts_with("ACK"), "get_stickers not ACKed");
+        let mut m = HashMap::new();
+        let mut lines = text.lines();
+        loop {
+            let file = lines.next().context("get_stickers no new line")?;
+            if "OK" == file {
+                break;
+            }
+            let val = lines.next().context("get_stickers no val")?;
+
+            m.insert(
+                String::from(&file[6..]),
+                String::from(&val[10 + sticker.len()..]),
+            );
+        }
+        Ok(m)
+    }
+
+    /// Retrieve the song URIs of all songs in the database
+    ///
+    /// Returns a vector of String
+    pub async fn get_all_songs(&mut self) -> Result<std::vec::Vec<String>> {
+        let text = self.stream.req("find \"(base '')\"").await?;
+        // We expect a response of the form:
+        // file: 0-A/A Positive Life - Lighten Up!.mp3
+        // Last-Modified: 2020-11-18T22:47:07Z
+        // Format: 44100:24:2
+        // Time: 399
+        // duration: 398.550
+        // Artist: A Positive Life
+        // Title: Lighten Up!
+        // Genre: Electronic
+        // file: 0-A/A Positive Life - Pleidean Communication.mp3
+        // ...
+        // OK
+        //
+        // or "ACK..."
+        ensure!(!text.starts_with("ACK"), "get_all_songs not ACKed");
+        Ok(text
+            .lines()
+            .filter_map(|x| x.strip_prefix("file: ").map(String::from))
+            .collect::<Vec<String>>())
+    }
+
+    pub async fn add(&mut self, uri: &str) -> Result<()> {
+        let msg = format!("add {}", quote(uri));
+        let text = self.stream.req(&msg).await?;
+        debug!("Sent `{}'; got `{}'.", &msg, &text);
+
+        ensure!(text.starts_with("OK"), "add not Oked");
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod client_tests {
+    use super::test_mock::Mock;
+    use super::*;
+
+    /// Some basic "smoke" tests
+    #[tokio::test]
+    async fn client_smoke_test() {
+        let mock = Box::new(Mock::new(&[(
+            "sticker get song foo.mp3 stick",
+            "sticker: stick=splat\nOK\n",
+        )]));
+        let mut cli = Client::new(mock).unwrap();
+        let val = cli
+            .get_sticker::<String>("foo.mp3", "stick")
+            .await
+            .unwrap()
+            .unwrap();
+        assert_eq!(val, "splat");
+    }
+
+    /// Test the `status' method
+    #[tokio::test]
+    async fn test_status() {
+        let mock = Box::new(Mock::new(&[
+            (
+                "status",
+                // When the server is playing or paused, the response will look something like this:
+                "volume: -1
+repeat: 0
+random: 0
+single: 0
+consume: 0
+playlist: 3
+playlistlength: 87
+mixrampdb: 0.000000
+state: play
+song: 14
+songid: 15
+time: 141:250
+bitrate: 128
+audio: 44100:24:2
+nextsong: 15
+nextsongid: 16
+elapsed: 140.585
+OK",
+            ),
+            // Should respond with a playlist id request
+            (
+                "playlistid 15",
+                // Should look something like this:
+                "file: U-Z/U2 - Who's Gonna RIDE Your WILD HORSES.mp3
+Last-Modified: 2004-12-24T19:26:13Z
+Artist: U2
+Title: Who's Gonna RIDE Your WILD HOR
+Genre: Pop
+Time: 316
+Pos: 41
+Id: 42
+duration: 249.994
+OK",
+            ),
+            (
+                "status",
+                // But if the state is "stop", much of that will be missing; it will look more like:
+                "volume: -1
+repeat: 0
+random: 0
+single: 0
+consume: 0
+playlist: 84
+playlistlength: 27
+mixrampdb: 0.000000
+state: stop
+OK",
+            ),
+            // Finally, let's simulate something being really wrong
+            (
+                "status",
+                "volume: -1
+repeat: 0
+state: no-idea!?",
+            ),
+        ]));
+        let mut cli = Client::new(mock).unwrap();
+        let stat = cli.status().await.unwrap();
+        match stat {
+            PlayerStatus::Play(curr) => {
+                assert_eq!(curr.songid, 15);
+                assert_eq!(
+                    curr.file.to_str().unwrap(),
+                    "U-Z/U2 - Who's Gonna RIDE Your WILD HORSES.mp3"
+                );
+                assert_eq!(curr.elapsed, 140.585);
+                assert_eq!(curr.duration, 249.994);
+            }
+            _ => panic!(),
+        }
+
+        let stat = cli.status().await.unwrap();
+        match stat {
+            PlayerStatus::Stopped => (),
+            _ => panic!(),
+        }
+
+        let stat = cli.status().await;
+        match stat {
+            Err(_) => (),
+            Ok(_) => panic!(),
+        }
+    }
+
+    /// Test the `get_sticker' method
+    #[tokio::test]
+    async fn test_get_sticker() {
+        let mock = Box::new(Mock::new(&[
+            (
+                "sticker get song foo.mp3 stick",
+                // On success, should get something like this...
+                "sticker: stick=2\nOK\n",
+            ),
+            (
+                "sticker get song foo.mp3 stick",
+                // and on failure, something like this:
+                "ACK [50@0] {sticker} no such sticker\n",
+            ),
+            (
+                "sticker get song foo.mp3 stick",
+                // Finally, let's try something nuts
+                "",
+            ),
+            (
+                "sticker get song \"filename_with\\\"doublequotes\\\".flac\" unwoundstack.com:playcount",
+                "sticker: unwoundstack.com:playcount=11\nOK\n",
+            ),
+        ]));
+        let mut cli = Client::new(mock).unwrap();
+        let val = cli
+            .get_sticker::<String>("foo.mp3", "stick")
+            .await
+            .unwrap()
+            .unwrap();
+        assert_eq!(val, "2");
+        let _val = cli
+            .get_sticker::<String>("foo.mp3", "stick")
+            .await
+            .unwrap()
+            .is_none();
+        let _val = cli
+            .get_sticker::<String>("foo.mp3", "stick")
+            .await
+            .unwrap_err();
+        let val = cli
+            .get_sticker::<String>(
+                "filename_with\"doublequotes\".flac",
+                "unwoundstack.com:playcount",
+            )
+            .await
+            .unwrap()
+            .unwrap();
+        assert_eq!(val, "11");
+    }
+
+    /// Test the `set_sticker' method
+    #[tokio::test]
+    async fn test_set_sticker() {
+        let mock = Box::new(Mock::new(&[
+            ("sticker set song foo.mp3 stick 2", "OK\n"),
+            (
+                "sticker set song foo.mp3 stick 2",
+                "ACK [50@0] {sticker} some error",
+            ),
+            (
+                "sticker set song foo.mp3 stick 2",
+                "this makes no sense as a response",
+            ),
+        ]));
+        let mut cli = Client::new(mock).unwrap();
+        let () = cli.set_sticker("foo.mp3", "stick", &"2").await.unwrap();
+        let _val = cli.set_sticker("foo.mp3", "stick", &"2").await.unwrap_err();
+        let _val = cli.set_sticker("foo.mp3", "stick", &"2").await.unwrap_err();
+    }
+
+    /// Test the `send_to_playlist' method
+    #[tokio::test]
+    async fn test_send_to_playlist() {
+        let mock = Box::new(Mock::new(&[
+            ("playlistadd foo.m3u foo.mp3", "OK\n"),
+            (
+                "playlistadd foo.m3u foo.mp3",
+                "ACK [101@0] {playlist} some error\n",
+            ),
+        ]));
+        let mut cli = Client::new(mock).unwrap();
+        let () = cli.send_to_playlist("foo.mp3", "foo.m3u").await.unwrap();
+        let _val = cli
+            .send_to_playlist("foo.mp3", "foo.m3u")
+            .await
+            .unwrap_err();
+    }
+
+    /// Test the `update' method
+    #[tokio::test]
+    async fn test_update() {
+        let mock = Box::new(Mock::new(&[
+            ("update \"foo.mp3\"", "updating_db: 2\nOK\n"),
+            ("update \"foo.mp3\"", "ACK [50@0] {update} blahblahblah"),
+            ("update \"foo.mp3\"", "this makes no sense as a response"),
+        ]));
+        let mut cli = Client::new(mock).unwrap();
+        let _val = cli.update("foo.mp3").await.unwrap();
+        let _val = cli.update("foo.mp3").await.unwrap_err();
+        let _val = cli.update("foo.mp3").await.unwrap_err();
+    }
+
+    /// Test retrieving stored playlists
+    #[tokio::test]
+    async fn test_get_stored_playlists() {
+        let mock = Box::new(Mock::new(&[
+            (
+                "listplaylists",
+                "playlist: saturday-afternoons-in-santa-cruz
+Last-Modified: 2020-03-13T17:20:16Z
+playlist: gaelic-punk
+Last-Modified: 2020-05-24T00:36:02Z
+playlist: morning-coffee
+Last-Modified: 2020-03-13T17:20:16Z
+OK
+",
+            ),
+            ("listplaylists", "ACK [1@0] {listplaylists} blahblahblah"),
+        ]));
+
+        let mut cli = Client::new(mock).unwrap();
+        let val = cli.get_stored_playlists().await.unwrap();
+        assert_eq!(
+            val,
+            vec![
+                String::from("saturday-afternoons-in-santa-cruz"),
+                String::from("gaelic-punk"),
+                String::from("morning-coffee")
+            ]
+        );
+        let _val = cli.get_stored_playlists().await.unwrap_err();
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+//                                           IdleClient                                           //
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+#[non_exhaustive]
+#[derive(Debug, PartialEq, Eq)]
+pub enum IdleSubSystem {
+    Player,
+    Message,
+}
+
+impl TryFrom<&str> for IdleSubSystem {
+    type Error = Error;
+    fn try_from(text: &str) -> std::result::Result<Self, Self::Error> {
+        let x = text.to_lowercase();
+        if x == "player" {
+            Ok(IdleSubSystem::Player)
+        } else if x == "message" {
+            Ok(IdleSubSystem::Message)
+        } else {
+            bail!("{}", text)
+        }
+    }
+}
+
+impl fmt::Display for IdleSubSystem {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            IdleSubSystem::Player => write!(f, "Player"),
+            IdleSubSystem::Message => write!(f, "Message"),
+        }
+    }
+}
+
+/// [MPD](https://www.musicpd.org) client for "idle" connections.
+///
+/// # Introduction
+///
+/// This is an MPD client designed to "idle": it opens a long-lived connection to the MPD server and
+/// waits for MPD to respond with a message indicating that there's been a change to a subsystem of
+/// interest. At present, there are only two subsystems in which [mpdpopm](crate) is interested: the player
+/// & messages (cf. [IdleSubSystem]).
+///
+/// ```no_run
+/// use std::path::Path;
+/// use tokio::runtime::Runtime;
+/// use mpdpopm::clients::IdleClient;
+///
+/// let mut rt = Runtime::new().unwrap();
+/// rt.block_on( async {
+///     let mut client = IdleClient::open(Path::new("/var/run/mpd.sock")).await.unwrap();
+///     client.subscribe("player").await.unwrap();
+///     client.idle().await.unwrap();
+///     // Arrives here when the player's state changes
+/// })
+/// ```
+///
+/// `client` is now a [Future](https://doc.rust-lang.org/stable/std/future/trait.Future.html) that
+/// resolves to an [IdleClient] instance talking to `/var/run/mpd.sock`.
+///
+pub struct IdleClient {
+    conn: Box<dyn RequestResponse>,
+}
+
+impl IdleClient {
+    /// Create a new [mpdpopm::client::IdleClient][IdleClient] instance from something that
+    /// implements [ToSocketAddrs]
+    pub async fn connect<A: ToSocketAddrs>(addr: A) -> Result<IdleClient> {
+        Self::new(MpdConnection::<TcpStream>::connect(addr).await?)
+    }
+
+    pub async fn open<P: AsRef<Path>>(pth: P) -> Result<IdleClient> {
+        Self::new(MpdConnection::<UnixStream>::connect(pth).await?)
+    }
+
+    pub fn new(stream: Box<dyn RequestResponse>) -> Result<IdleClient> {
+        Ok(IdleClient { conn: stream })
+    }
+
+    /// Subscribe to an mpd channel
+    pub async fn subscribe(&mut self, chan: &str) -> Result<()> {
+        let text = self.conn.req(&format!("subscribe {}", chan)).await?;
+        debug!("Sent subscribe message for {}; got `{}'.", chan, text);
+        ensure!(text.starts_with("OK"), "subscribe not Ok: `{}`", text);
+        debug!("Subscribed to {}.", chan);
+        Ok(())
+    }
+
+    /// Enter idle state-- return the subsystem that changed, causing the connection to return. NB
+    /// this may block for some time.
+    pub async fn idle(&mut self) -> Result<IdleSubSystem> {
+        let text = self.conn.req("idle player message").await?;
+        debug!("Sent idle message; got `{}'.", text);
+
+        // If the player state changes, we'll get: "changed: player\nOK\n"
+        //
+        // If a ratings message is sent, we'll get: "changed: message\nOK\n", to which we respond
+        // "readmessages", which should give us something like:
+        //
+        //     channel: ratings
+        //     message: 255
+        //     OK
+        //
+        // We remain subscribed, but we need to send a new idle message.
+
+        ensure!(text.starts_with("changed: "), "idle not OK: `{}`", text);
+        let idx = text.find('\n').context("idle has no newline")?;
+
+        let result = IdleSubSystem::try_from(&text[9..idx])?;
+        let text = text[idx + 1..].to_string();
+        ensure!(text.starts_with("OK"), "idle not OKed");
+
+        Ok(result)
+    }
+
+    /// This method simply returns the results of a "readmessages" as a HashMap of channel name to
+    /// Vec of (String) messages for that channel
+    pub async fn get_messages(&mut self) -> Result<HashMap<String, Vec<String>>> {
+        let text = self.conn.req("readmessages").await?;
+        debug!("Sent readmessages; got `{}'.", text);
+
+        // We expect something like:
+        //
+        //     channel: ratings
+        //     message: 255
+        //     OK
+        //
+        // We remain subscribed, but we need to send a new idle message.
+
+        let mut m: HashMap<String, Vec<String>> = HashMap::new();
+
+        // Populate `m' with a little state machine:
+        enum State {
+            Init,
+            Running,
+            Finished,
+        }
+        let mut state = State::Init;
+        let mut chan = String::new();
+        let mut msgs: Vec<String> = Vec::new();
+        for line in text.lines() {
+            match state {
+                State::Init => {
+                    ensure!(line.starts_with("channel: "), "no `channel: ` given");
+                    chan = String::from(&line[9..]);
+                    state = State::Running;
+                }
+                State::Running => {
+                    if let Some(stripped) = line.strip_prefix("message: ") {
+                        msgs.push(String::from(stripped));
+                    } else if let Some(stripped) = line.strip_prefix("channel: ") {
+                        match m.get_mut(&chan) {
+                            Some(v) => v.append(&mut msgs),
+                            None => {
+                                m.insert(chan.clone(), msgs.clone());
+                            }
+                        }
+                        chan = String::from(stripped);
+                        msgs = Vec::new();
+                    } else if line == "OK" {
+                        match m.get_mut(&chan) {
+                            Some(v) => v.append(&mut msgs),
+                            None => {
+                                m.insert(chan.clone(), msgs.clone());
+                            }
+                        }
+                        state = State::Finished;
+                    } else {
+                        bail!("Failed to get messages: `{}`", text)
+                    }
+                }
+                State::Finished => {
+                    // Should never be here!
+                    bail!("Failed to get messages: `{}`", text)
+                }
+            }
+        }
+
+        Ok(m)
+    }
+}
+
+#[cfg(test)]
+/// Let's test IdleClient!
+mod idle_client_tests {
+
+    use super::test_mock::Mock;
+    use super::*;
+
+    /// Some basic "smoke" tests
+    #[tokio::test]
+    async fn test_get_messages() {
+        let mock = Box::new(Mock::new(&[(
+            "readmessages",
+            // If a ratings message is sent, we'll get: "changed: message\nOK\n", to which we
+            // respond "readmessages", which should give us something like:
+            //
+            //     channel: ratings
+            //     message: 255
+            //     OK
+            //
+            // We remain subscribed, but we need to send a new idle message.
+            "channel: ratings
+message: 255
+message: 128
+channel: send-to-playlist
+message: foo.m3u
+OK
+",
+        )]));
+        let mut cli = IdleClient::new(mock).unwrap();
+        let hm = cli.get_messages().await.unwrap();
+        let val = hm.get("ratings").unwrap();
+        assert_eq!(val.len(), 2);
+        let val = hm.get("send-to-playlist").unwrap();
+        assert!(val.len() == 1);
+    }
+
+    /// Test issue #1
+    #[tokio::test]
+    async fn test_issue_1() {
+        let mock = Box::new(Mock::new(&[(
+            "readmessages",
+            "channel: playcounts
+message: a
+channel: playcounts
+message: b
+OK
+",
+        )]));
+        let mut cli = IdleClient::new(mock).unwrap();
+        let hm = cli.get_messages().await.unwrap();
+        let val = hm.get("playcounts").unwrap();
+        assert_eq!(val.len(), 2);
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/config.rs b/pkgs/by-name/mp/mpdpopm/src/config.rs
new file mode 100644
index 00000000..b4fe3c53
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/config.rs
@@ -0,0 +1,286 @@
+// Copyright (C) 2021-2025 Michael herstine <sp1ff@pobox.com>
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+//! # mpdpopm Configuration
+//!
+//! ## Introduction
+//!
+//! This module defines the configuration struct & handles deserialization thereof.
+//!
+//! ## Discussion
+//!
+//! In the first releases of [mpdpopm](crate) I foolishly forgot to add a version field to the
+//! configuration structure. I am now paying for my sin by having to attempt serializing two
+//! versions until one succeeds.
+//!
+//! The idiomatic approach to versioning [serde](https://docs.serde.rs/serde/) structs seems to be
+//! using an
+//! [enumeration](https://www.reddit.com/r/rust/comments/44dds3/handling_multiple_file_versions_with_serde_or/). This
+//! implementation *now* uses that, but that leaves us with the problem of handling the initial,
+//! un-tagged version. I proceed as follows:
+//!
+//!    1. attempt to deserialize as a member of the modern enumeration
+//!    2. if that succeeds, with the most-recent version, we're good
+//!    3. if that succeeds with an archaic version, convert to the most recent and warn the user
+//!    4. if that fails, attempt to deserialize as the initial struct version
+//!    5. if that succeeds, convert to the most recent & warn the user
+//!    6. if that fails, I'm kind of stuck because I don't know what the user was trying to express;
+//!       bundle-up all the errors, report 'em & urge the user to use the most recent version
+use crate::vars::{LOCALSTATEDIR, PREFIX};
+
+use anyhow::{Result, bail};
+use serde::{Deserialize, Serialize};
+
+use std::{env, path::PathBuf};
+
+/// [mpdpopm](crate) can communicate with MPD over either a local Unix socket, or over regular TCP
+#[derive(Debug, Deserialize, PartialEq, Serialize)]
+pub enum Connection {
+    /// Local Unix socket-- payload is the path to the socket
+    Local { path: PathBuf },
+    /// TCP-- payload is the hostname & port number
+    TCP { host: String, port: u16 },
+}
+
+impl Connection {
+    pub fn new() -> Result<Self> {
+        let env = match env::var("MPD_HOST") {
+            Ok(env) => Some(env),
+            Err(err) => match err {
+                env::VarError::NotPresent => None,
+                env::VarError::NotUnicode(_) => {
+                    bail!("Failed to get `MPD_HOST` env var: {err}")
+                }
+            },
+        }
+        .unwrap_or("/run/mpd/socket".to_owned());
+
+        if env.starts_with("/") {
+            // We assume that this is a path to a local socket
+            Ok(Self::Local {
+                path: PathBuf::from(env),
+            })
+        } else {
+            todo!("Not yet able to auto-parse, MPD_HOST for remote connection")
+        }
+    }
+}
+
+impl Default for Connection {
+    fn default() -> Self {
+        Self::new().expect("Could not generate default connection")
+    }
+}
+
+#[cfg(test)]
+mod test_connection {
+    use super::Connection;
+
+    #[test]
+    fn test_serde() {
+        use serde_json::to_string;
+
+        use std::path::PathBuf;
+
+        let text = to_string(&Connection::Local {
+            path: PathBuf::from("/var/run/mpd.sock"),
+        })
+        .unwrap();
+
+        assert_eq!(
+            text,
+            String::from(r#"{"Local":{"path":"/var/run/mpd.sock"}}"#)
+        );
+
+        let text = to_string(&Connection::TCP {
+            host: String::from("localhost"),
+            port: 6600,
+        })
+        .unwrap();
+        assert_eq!(
+            text,
+            String::from(r#"{"TCP":{"host":"localhost","port":6600}}"#)
+        );
+    }
+}
+
+/// This is the most recent `mppopmd` configuration struct.
+#[derive(Deserialize, Debug, Serialize)]
+#[serde(default)]
+pub struct Config {
+    /// Configuration format version-- must be "1"
+    // Workaround to https://github.com/rotty/lexpr-rs/issues/77
+    // When this gets fixed, I can remove this element from the struct & deserialize as
+    // a Configurations element-- the on-disk format will be the same.
+    #[serde(rename = "version")]
+    _version: String,
+
+    /// Location of log file
+    pub log: PathBuf,
+
+    /// How to connect to mpd
+    pub conn: Connection,
+
+    /// The `mpd' root music directory, relative to the host on which *this* daemon is running
+    pub local_music_dir: PathBuf,
+
+    /// Percentage threshold, expressed as a number between zero & one, for considering a song to
+    /// have been played
+    pub played_thresh: f64,
+
+    /// The interval, in milliseconds, at which to poll `mpd' for the current state
+    pub poll_interval_ms: u64,
+
+    /// Channel to setup for assorted commands-- channel names must satisfy "[-a-zA-Z-9_.:]+"
+    pub commands_chan: String,
+}
+
+impl Default for Config {
+    fn default() -> Self {
+        Self::new().unwrap()
+    }
+}
+
+impl Config {
+    fn new() -> Result<Self> {
+        Ok(Self {
+            _version: String::from("1"),
+            log: [LOCALSTATEDIR, "log", "mppopmd.log"].iter().collect(),
+            conn: Connection::new()?,
+            local_music_dir: [PREFIX, "Music"].iter().collect(),
+            played_thresh: 0.6,
+            poll_interval_ms: 5000,
+            commands_chan: String::from("unwoundstack.com:commands"),
+        })
+    }
+}
+
+pub fn from_str(text: &str) -> Result<Config> {
+    let cfg: Config = match serde_json::from_str(text) {
+        Ok(cfg) => cfg,
+        Err(err_outer) => {
+            bail!("Failed to parse config: `{}`", err_outer)
+        }
+    };
+    Ok(cfg)
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    #[ignore = "We changed the config format to json"]
+    fn test_from_str() {
+        let cfg = Config::default();
+        assert_eq!(cfg.commands_chan, String::from("unwoundstack.com:commands"));
+
+        assert_eq!(
+            serde_json::to_string(&cfg).unwrap(),
+            format!(
+                r#"((version . "1") (log . "{}/log/mppopmd.log") (conn TCP (host . "localhost") (port . 6600)) (local_music_dir . "{}/Music") (playcount_sticker . "unwoundstack.com:playcount") (lastplayed_sticker . "unwoundstack.com:lastplayed") (played_thresh . 0.6) (poll_interval_ms . 5000) (commands_chan . "unwoundstack.com:commands") (playcount_command . "") (playcount_command_args) (rating_sticker . "unwoundstack.com:rating") (ratings_command . "") (ratings_command_args) (gen_cmds))"#,
+                LOCALSTATEDIR, PREFIX
+            )
+        );
+
+        let cfg: Config = serde_json::from_str(
+            r#"
+((version . "1")
+ (log . "/usr/local/var/log/mppopmd.log")
+ (conn TCP (host . "localhost") (port . 6600))
+ (local_music_dir . "/usr/local/Music")
+ (playcount_sticker . "unwoundstack.com:playcount")
+ (lastplayed_sticker . "unwoundstack.com:lastplayed")
+ (played_thresh . 0.6)
+ (poll_interval_ms . 5000)
+ (commands_chan . "unwoundstack.com:commands")
+ (playcount_command . "")
+ (playcount_command_args)
+ (rating_sticker . "unwoundstack.com:rating")
+ (ratings_command . "")
+ (ratings_command_args)
+ (gen_cmds))
+"#,
+        )
+        .unwrap();
+        assert_eq!(cfg._version, String::from("1"));
+
+        let cfg: Config = serde_json::from_str(
+            r#"
+((version . "1")
+ (log . "/usr/local/var/log/mppopmd.log")
+ (conn Local (path . "/home/mgh/var/run/mpd/mpd.sock"))
+ (local_music_dir . "/usr/local/Music")
+ (playcount_sticker . "unwoundstack.com:playcount")
+ (lastplayed_sticker . "unwoundstack.com:lastplayed")
+ (played_thresh . 0.6)
+ (poll_interval_ms . 5000)
+ (commands_chan . "unwoundstack.com:commands")
+ (playcount_command . "")
+ (playcount_command_args)
+ (rating_sticker . "unwoundstack.com:rating")
+ (ratings_command . "")
+ (ratings_command_args)
+ (gen_cmds))
+"#,
+        )
+        .unwrap();
+        assert_eq!(cfg._version, String::from("1"));
+        assert_eq!(
+            cfg.conn,
+            Connection::Local {
+                path: PathBuf::from("/home/mgh/var/run/mpd/mpd.sock")
+            }
+        );
+
+        // Test fallback to "v0" of the config struct
+        let cfg = from_str(r#"
+((log . "/home/mgh/var/log/mppopmd.log")
+ (host . "192.168.1.14")
+ (port . 6600)
+ (local_music_dir . "/space/mp3")
+ (playcount_sticker . "unwoundstack.com:playcount")
+ (lastplayed_sticker . "unwoundstack.com:lastplayed")
+ (played_thresh . 0.6)
+ (poll_interval_ms . 5000)
+ (playcount_command . "/usr/local/bin/scribbu")
+ (playcount_command_args . ("popm" "-v" "-a" "-f" "-o" "sp1ff@pobox.com" "-C" "%playcount" "%full-file"))
+ (commands_chan . "unwoundstack.com:commands")
+ (rating_sticker . "unwoundstack.com:rating")
+ (ratings_command . "/usr/local/bin/scribbu")
+ (ratings_command_args . ("popm" "-v" "-a" "-f" "-o" "sp1ff@pobox.com" "-r" "%rating" "%full-file"))
+ (gen_cmds .
+	   (((name . "set-genre")
+	     (formal_parameters . (Literal Track))
+	     (default_after . 1)
+	     (cmd . "/usr/local/bin/scribbu")
+	     (args . ("genre" "-a" "-C" "-g" "%1" "%full-file"))
+	     (update . TrackOnly))
+	    ((name . "set-xtag")
+	     (formal_parameters . (Literal Track))
+	     (default_after . 1)
+	     (cmd . "/usr/local/bin/scribbu")
+	     (args . ("xtag" "-A" "-o" "sp1ff@pobox.com" "-T" "%1" "%full-file"))
+	     (update . TrackOnly))
+	    ((name . "merge-xtag")
+	     (formal_parameters . (Literal Track))
+	     (default_after . 1)
+	     (cmd . "/usr/local/bin/scribbu")
+	     (args . ("xtag" "-m" "-o" "sp1ff@pobox.com" "-T" "%1" "%full-file"))
+	     (update . TrackOnly)))))
+"#).unwrap();
+        assert_eq!(cfg.log, PathBuf::from("/home/mgh/var/log/mppopmd.log"));
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/dj/algorithms.rs b/pkgs/by-name/mp/mpdpopm/src/dj/algorithms.rs
new file mode 100644
index 00000000..5ddfc7cb
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/dj/algorithms.rs
@@ -0,0 +1,155 @@
+use std::collections::HashSet;
+
+use anyhow::{Context, Result};
+use rand::{Rng, distr, seq::SliceRandom};
+use tracing::info;
+
+use crate::{clients::Client, storage};
+
+pub(crate) trait Algorithm {
+    async fn next_track(&mut self, client: &mut Client) -> Result<String>;
+}
+
+/// Generates generic discovery playlist, that fulfills following requirements:
+///  - Will (eventually) include every not-played song. (So it can be used to rank a library)
+///  - Returns liked songs more often then not-played or negative songs.
+pub(crate) struct Discovery {
+    already_done: HashSet<String>,
+}
+
+impl Algorithm for Discovery {
+    async fn next_track(&mut self, client: &mut Client) -> Result<String> {
+        macro_rules! take {
+            ($first:expr, $second:expr, $third:expr) => {{
+                $first.pop().map_or_else(
+                    || {
+                        $second.pop().map_or_else(
+                            || {
+                                $third.pop().map_or_else(
+                                    || {
+                                        unreachable!(
+                                            "This means that there are no songs in the libary"
+                                        )
+                                    },
+                                    |val| {
+                                        tracing::info!(
+                                            "Selecting a `{}` track for the next entry in the queue",
+                                            stringify!($third)
+                                        );
+                                        Ok::<_, anyhow::Error>(val)
+                                    },
+                                )
+                            },
+                            |val| {
+                                tracing::info!(
+                                    "Selecting a `{}` track for the next entry in the queue",
+                                    stringify!($second)
+                                );
+                                Ok::<_, anyhow::Error>(val)
+                            },
+                        )
+                    },
+                    |val| {
+                        tracing::info!(
+                            "Selecting a `{}` track for the next entry in the queue",
+                            stringify!($first)
+                        );
+                        Ok::<_, anyhow::Error>(val)
+                    },
+                )
+            }};
+        }
+
+        let mut rng = rand::rng();
+        let (mut positive, mut neutral, mut negative) = {
+            let tracks = {
+                let mut base = client
+                    .get_all_songs()
+                    .await?
+                    .into_iter()
+                    .filter(|song| !self.already_done.contains(song))
+                    .collect::<Vec<_>>();
+
+                if base.is_empty() {
+                    // We could either have no tracks in the library,
+                    // or we actually already listed to everything.
+                    self.already_done = HashSet::new();
+
+                    info!("Resetting already done songs, as we have no more to choose from");
+
+                    base = client.get_all_songs().await?;
+                }
+
+                base
+            };
+
+            let mut positive = vec![];
+            let mut neutral = vec![];
+            let mut negative = vec![];
+
+            for track in tracks {
+                let weight = Self::weight_track(client, &track).await?;
+
+                match weight {
+                    1..=i64::MAX => positive.push(track),
+                    0 => neutral.push(track),
+                    i64::MIN..0 => negative.push(track),
+                }
+            }
+
+            // Avoid an inherit ordering, that might be returned by the `Client::get_all_songs()` function.
+            positive.shuffle(&mut rng);
+            neutral.shuffle(&mut rng);
+            negative.shuffle(&mut rng);
+
+            (positive, neutral, negative)
+        };
+
+        let pick = rng.sample(
+            distr::weighted::WeightedIndex::new([0.65, 0.5, 0.2].iter())
+                .expect("to be valid, as hardcoded"),
+        );
+
+        let next = match pick {
+            0 => take!(positive, neutral, negative),
+            1 => take!(neutral, positive, negative),
+            2 => take!(negative, neutral, positive),
+            _ => unreachable!("These indexes are not possible"),
+        }?;
+
+        self.already_done.insert(next.clone());
+
+        Ok(next)
+    }
+}
+
+impl Discovery {
+    pub(crate) fn new() -> Self {
+        Self {
+            already_done: HashSet::new(),
+        }
+    }
+
+    /// Calculate a recommendation score for a track.
+    ///
+    /// The algorithm maps tracks, that the user likes to a high score and songs that the user
+    /// dislikes to a lower number.
+    /// Currently, only the rating, skip count and play count are considered. Similarity scores,
+    /// fetched from e.g. last.fm should be included in the future.
+    async fn weight_track(client: &mut Client, track: &str) -> Result<i64> {
+        let rating = i32::from(storage::rating::get(client, track).await?.unwrap_or(0));
+        let play_count = i32::try_from(storage::play_count::get(client, track).await?.unwrap_or(0))
+            .context("`play_count` too big")?;
+        let skip_count = i32::try_from(storage::skip_count::get(client, track).await?.unwrap_or(0))
+            .context("`skip_count` too big")?;
+
+        let output: f64 =
+            1.0 * f64::from(rating) + 0.3 * f64::from(play_count) + -0.6 * f64::from(skip_count);
+
+        let weight = output.round() as i64;
+
+        // info!("`{track}`: {weight}");
+
+        Ok(weight)
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/dj/mod.rs b/pkgs/by-name/mp/mpdpopm/src/dj/mod.rs
new file mode 100644
index 00000000..a211a571
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/dj/mod.rs
@@ -0,0 +1,28 @@
+use anyhow::Result;
+use tracing::info;
+
+use crate::{clients::Client, dj::algorithms::Algorithm};
+
+pub(crate) mod algorithms;
+
+pub(crate) struct Dj<A: Algorithm> {
+    algo: A,
+}
+
+impl<A: Algorithm> Dj<A> {
+    pub(crate) fn new(algo: A) -> Self {
+        Self { algo }
+    }
+
+    /// Add the next track to the playlist.
+    ///
+    /// This should be called after the previous track is finished, to avoid unbounded growth.
+    pub(crate) async fn add_track(&mut self, client: &mut Client) -> Result<()> {
+        let next = self.algo.next_track(client).await?;
+
+        info!("Adding `{next}`, due to active dj mode");
+        client.add(&next).await?;
+
+        Ok(())
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/filters.lalrpop b/pkgs/by-name/mp/mpdpopm/src/filters.lalrpop
new file mode 100644
index 00000000..970fc040
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/filters.lalrpop
@@ -0,0 +1,160 @@
+// Copyright (C) 2020-2025 Michael Herstine <sp1ff@pobox.com>  -*- mode: rust; rust-format-on-save: nil -*-
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+use lalrpop_util::ParseError;
+
+use crate::filters_ast::{
+    Conjunction,
+    Disjunction,
+    Expression,
+    OpCode,
+    Selector,
+    Term,
+    Value,
+    expect_quoted,
+    parse_iso_8601
+};
+use tracing::debug;
+
+grammar;
+
+pub ExprOp: OpCode = {
+    "=="       => OpCode::Equality,
+    "!="       => OpCode::Inequality,
+    "contains" => OpCode::Contains,
+    "=~"       => OpCode::RegexMatch,
+    "!~"       => OpCode::RegexExclude,
+    ">"        => OpCode::GreaterThan,
+    "<"        => OpCode::LessThan,
+    ">="       => OpCode::GreaterThanEqual,
+    "<="       => OpCode::LessThanEqual,
+};
+
+pub ExprSel: Selector = {
+    r"(?i)artist"                     => Selector::Artist,
+    r"(?i)album"                      => Selector::Album,
+    r"(?i)albumartist"                => Selector::AlbumArtist,
+    r"(?i)title"                      => Selector::Title,
+    r"(?i)track"                      => Selector::Track,
+    r"(?i)name"                       => Selector::Name,
+    r"(?i)genre"                      => Selector::Genre,
+    r"(?i)date"                       => Selector::Date,
+    r"(?i)originaldate"               => Selector::OriginalDate,
+    r"(?i)composer"                   => Selector::Composer,
+    r"(?i)performer"                  => Selector::Performer,
+    r"(?i)conductor"                  => Selector::Conductor,
+    r"(?i)work"                       => Selector::Work,
+    r"(?i)grouping"                   => Selector::Grouping,
+    r"(?i)comment"                    => Selector::Comment,
+    r"(?i)disc"                       => Selector::Disc,
+    r"(?i)label"                      => Selector::Label,
+    r"(?i)musicbrainz_aristid"        => Selector::MusicbrainzAristID,
+    r"(?i)musicbrainz_albumid"        => Selector::MusicbrainzAlbumID,
+    r"(?i)musicbrainz_albumartistid"  => Selector::MusicbrainzAlbumArtistID,
+    r"(?i)musicbrainz_trackid"        => Selector::MusicbrainzTrackID,
+    r"(?i)musicbrainz_releasetrackid" => Selector::MusicbrainzReleaseTrackID,
+    r"(?i)musicbrainz_workid"         => Selector::MusicbrainzWorkID,
+    r"(?i)file"                       => Selector::File,
+    r"(?i)base"                       => Selector::Base,
+    r"(?i)modified-since"             => Selector::ModifiedSince,
+    r"(?i)audioformat"                => Selector::AudioFormat,
+    r"(?i)rating"                     => Selector::Rating,
+    r"(?i)playcount"                  => Selector::PlayCount,
+    r"(?i)lastplayed"                 => Selector::LastPlayed,
+    r"(?i)skipped"                    => Selector::Skipped,
+};
+
+pub Token: Value = {
+    <s:r"(-)?[0-9]+"> =>? {
+        debug!("matched token: ``{}''.", s);
+        // We need to yield a Result<Value, ParseError>
+        match s.parse::<usize>() {
+            Ok(n) => Ok(Value::Uint(n)),
+            Err(_) => match s.parse::<i64>() {
+                Ok(n) => Ok(Value::Int(n)),
+                Err(_) => Err(
+                    ParseError::User {
+                        error: "Internal parse error while parsing unsigned int"
+                    }
+                )
+            }
+        }
+    },
+    <s:r#""([ \t'a-zA-Z0-9~!@#$%^&*()-=_+\[\]{}|;:<>,./?]|\\\\|\\"|\\')+""#> => {
+        debug!("matched token: ``{}''.", s);
+        let s = expect_quoted(s).unwrap();
+        match parse_iso_8601(&mut s.as_bytes()) {
+            Ok(x) => Value::UnixEpoch(x),
+            Err(_) => Value::Text(s),
+        }
+    },
+    <s:r#"'([ \t"a-zA-Z0-9~!@#$%^&*()-=_+\[\]{}|;:<>,./?]|\\\\|\\'|\\")+'"#> => {
+        debug!("matched token: ``{}''.", s);
+        let s = expect_quoted(s).unwrap();
+        match parse_iso_8601(&mut s.as_bytes()) {
+            Ok(x) => Value::UnixEpoch(x),
+            Err(_) => Value::Text(s),
+        }
+    },
+};
+
+pub Term: Box<Term> = {
+    <t:ExprSel> <o:ExprOp> <u:Token> => {
+        debug!("matched binary condition: ``({}, {:#?}, {:#?})''", t, o, u);
+        Box::new(Term::BinaryCondition(t, o, u))
+    },
+    <t:ExprSel> <u:Token> => {
+        debug!("matched unary condition: ``({}, {:#?})''", t, u);
+        Box::new(Term::UnaryCondition(t, u))
+    },
+}
+
+pub Conjunction: Box<Conjunction> = {
+    <e1:Expression> "AND" <e2:Expression> => {
+        debug!("matched conjunction: ``({:#?}, {:#?})''", e1, e2);
+        Box::new(Conjunction::Simple(e1, e2))
+    },
+    <c:Conjunction> "AND" <e:Expression> => {
+        debug!("matched conjunction: ``({:#?}, {:#?})''", c, e);
+        Box::new(Conjunction::Compound(c, e))
+    },
+}
+
+pub Disjunction: Box<Disjunction> = {
+    <e1:Expression> "OR" <e2:Expression> => {
+        debug!("matched disjunction: ``({:#?}, {:#?})''", e1, e2);
+        Box::new(Disjunction::Simple(e1, e2))
+    },
+    <c:Disjunction> "OR" <e:Expression> => {
+        debug!("matched disjunction: ``({:#?}, {:#?})''", c, e);
+        Box::new(Disjunction::Compound(c, e))
+    },
+}
+
+pub Expression: Box<Expression> = {
+    "(" <t:Term> ")" => {
+        debug!("matched parenthesized term: ``({:#?})''", t);
+        Box::new(Expression::Simple(t))
+    },
+    "(" "!" <e:Expression> ")" => Box::new(Expression::Negation(e)),
+    "(" <c:Conjunction> ")" => {
+        debug!("matched parenthesized conjunction: ``({:#?})''", c);
+        Box::new(Expression::Conjunction(c))
+    },
+    "(" <c:Disjunction>  ")" => {
+        debug!("matched parenthesized disjunction: ``({:#?})''", c);
+        Box::new(Expression::Disjunction(c))
+    },
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/filters_ast.rs b/pkgs/by-name/mp/mpdpopm/src/filters_ast.rs
new file mode 100644
index 00000000..9c68d329
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/filters_ast.rs
@@ -0,0 +1,1022 @@
+// Copyright (C) 2020-2025 Michael herstine <sp1ff@pobox.com>
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+//! Types for building the Abstract Syntax Tree when parsing filters
+//!
+//! This module provides support for our [lalrpop](https://github.com/lalrpop/lalrpop) grammar.
+
+use crate::clients::Client;
+use crate::storage::{last_played, play_count, rating, skip_count};
+
+use anyhow::{Context, Error, Result, anyhow, bail};
+use boolinator::Boolinator;
+use chrono::prelude::*;
+use tracing::debug;
+
+use std::collections::{HashMap, HashSet};
+use std::str::FromStr;
+
+/// The operations that can appear in a filter term
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum OpCode {
+    Equality,
+    Inequality,
+    Contains,
+    RegexMatch,
+    RegexExclude,
+    GreaterThan,
+    LessThan,
+    GreaterThanEqual,
+    LessThanEqual,
+}
+
+impl std::fmt::Display for OpCode {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                OpCode::Equality => "==",
+                OpCode::Inequality => "!=",
+                OpCode::Contains => "contains",
+                OpCode::RegexMatch => "=~",
+                OpCode::RegexExclude => "!~",
+                OpCode::GreaterThan => ">",
+                OpCode::LessThan => "<",
+                OpCode::GreaterThanEqual => ">=",
+                OpCode::LessThanEqual => "<=",
+            }
+        )
+    }
+}
+
+/// The song attributes that can appear on the LHS of a filter term
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum Selector {
+    Artist,
+    Album,
+    AlbumArtist,
+    Title,
+    Track,
+    Name,
+    Genre,
+    Date,
+    OriginalDate,
+    Composer,
+    Performer,
+    Conductor,
+    Work,
+    Grouping,
+    Comment,
+    Disc,
+    Label,
+    MusicbrainzAristID,
+    MusicbrainzAlbumID,
+    MusicbrainzAlbumArtistID,
+    MusicbrainzTrackID,
+    MusicbrainzReleaseTrackID,
+    MusicbrainzWorkID,
+    File,
+    Base,
+    ModifiedSince,
+    AudioFormat,
+    Rating,
+    PlayCount,
+    LastPlayed,
+    Skipped,
+}
+
+impl std::fmt::Display for Selector {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(
+            f,
+            "{}",
+            match self {
+                Selector::Artist => "artist",
+                Selector::Album => "album",
+                Selector::AlbumArtist => "albumartist",
+                Selector::Title => "title",
+                Selector::Track => "track",
+                Selector::Name => "name",
+                Selector::Genre => "genre",
+                Selector::Date => "date",
+                Selector::OriginalDate => "originaldate",
+                Selector::Composer => "composer",
+                Selector::Performer => "performer",
+                Selector::Conductor => "conductor",
+                Selector::Work => "work",
+                Selector::Grouping => "grouping",
+                Selector::Comment => "comment",
+                Selector::Disc => "disc",
+                Selector::Label => "label",
+                Selector::MusicbrainzAristID => "musicbrainz_aristid",
+                Selector::MusicbrainzAlbumID => "musicbrainz_albumid",
+                Selector::MusicbrainzAlbumArtistID => "musicbrainz_albumartistid",
+                Selector::MusicbrainzTrackID => "musicbrainz_trackid",
+                Selector::MusicbrainzReleaseTrackID => "musicbrainz_releasetrackid",
+                Selector::MusicbrainzWorkID => "musicbrainz_workid",
+                Selector::File => "file",
+                Selector::Base => "base",
+                Selector::ModifiedSince => "modified-since",
+                Selector::AudioFormat => "AudioFormat",
+                Selector::Rating => "rating",
+                Selector::PlayCount => "playcount",
+                Selector::LastPlayed => "lastplayed",
+                Selector::Skipped => "skipped",
+            }
+        )
+    }
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Value {
+    Text(String),
+    UnixEpoch(i64),
+    Uint(usize),
+    Int(i64),
+}
+
+fn quote_value(x: &Value) -> String {
+    match x {
+        Value::Text(s) => {
+            let mut ret = String::new();
+
+            ret.push('"');
+            for c in s.chars() {
+                if c == '"' || c == '\\' {
+                    ret.push('\\');
+                }
+                ret.push(c);
+            }
+            ret.push('"');
+            ret
+        }
+        Value::UnixEpoch(n) => {
+            format!("'{}'", n)
+        }
+        Value::Uint(n) => {
+            format!("'{}'", n)
+        }
+        Value::Int(n) => {
+            format!("'{}'", n)
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum Term {
+    UnaryCondition(Selector, Value),
+    BinaryCondition(Selector, OpCode, Value),
+}
+
+#[derive(Clone, Debug)]
+pub enum Conjunction {
+    Simple(Box<Expression>, Box<Expression>),
+    Compound(Box<Conjunction>, Box<Expression>),
+}
+
+#[derive(Clone, Debug)]
+pub enum Disjunction {
+    Simple(Box<Expression>, Box<Expression>),
+    Compound(Box<Disjunction>, Box<Expression>),
+}
+
+#[derive(Clone, Debug)]
+pub enum Expression {
+    Simple(Box<Term>),
+    Negation(Box<Expression>),
+    Conjunction(Box<Conjunction>),
+    Disjunction(Box<Disjunction>),
+}
+
+#[cfg(test)]
+mod smoke_tests {
+    use super::*;
+    use crate::filters::*;
+
+    #[test]
+    fn test_opcodes() {
+        assert!(ExprOpParser::new().parse("==").unwrap() == OpCode::Equality);
+        assert!(ExprOpParser::new().parse("!=").unwrap() == OpCode::Inequality);
+        assert!(ExprOpParser::new().parse("contains").unwrap() == OpCode::Contains);
+        assert!(ExprOpParser::new().parse("=~").unwrap() == OpCode::RegexMatch);
+        assert!(ExprOpParser::new().parse("!~").unwrap() == OpCode::RegexExclude);
+        assert!(ExprOpParser::new().parse(">").unwrap() == OpCode::GreaterThan);
+        assert!(ExprOpParser::new().parse("<").unwrap() == OpCode::LessThan);
+        assert!(ExprOpParser::new().parse(">=").unwrap() == OpCode::GreaterThanEqual);
+        assert!(ExprOpParser::new().parse("<=").unwrap() == OpCode::LessThanEqual);
+    }
+
+    #[test]
+    fn test_conditions() {
+        assert!(TermParser::new().parse("base 'foo'").is_ok());
+        assert!(TermParser::new().parse("artist == 'foo'").is_ok());
+        assert!(
+            TermParser::new()
+                .parse(r#"artist =~ "foo bar \"splat\"!""#)
+                .is_ok()
+        );
+        assert!(TermParser::new().parse("artist =~ 'Pogues'").is_ok());
+
+        match *TermParser::new()
+            .parse(r#"base "/Users/me/My Music""#)
+            .unwrap()
+        {
+            Term::UnaryCondition(a, b) => {
+                assert!(a == Selector::Base);
+                assert!(b == Value::Text(String::from(r#"/Users/me/My Music"#)));
+            }
+            _ => {
+                unreachable!();
+            }
+        }
+
+        match *TermParser::new()
+            .parse(r#"artist =~ "foo bar \"splat\"!""#)
+            .unwrap()
+        {
+            Term::BinaryCondition(t, op, s) => {
+                assert!(t == Selector::Artist);
+                assert!(op == OpCode::RegexMatch);
+                assert!(s == Value::Text(String::from(r#"foo bar "splat"!"#)));
+            }
+            _ => {
+                unreachable!();
+            }
+        }
+    }
+
+    #[test]
+    fn test_expressions() {
+        assert!(ExpressionParser::new().parse("( base 'foo' )").is_ok());
+        assert!(ExpressionParser::new().parse("(base \"foo\")").is_ok());
+        assert!(
+            ExpressionParser::new()
+                .parse("(!(artist == 'value'))")
+                .is_ok()
+        );
+        assert!(
+            ExpressionParser::new()
+                .parse(r#"((!(artist == "foo bar")) AND (base "/My Music"))"#)
+                .is_ok()
+        );
+    }
+
+    #[test]
+    fn test_quoted_expr() {
+        eprintln!("test_quoted_expr");
+        assert!(
+            ExpressionParser::new()
+                .parse(r#"(artist =~ "foo\\bar\"")"#)
+                .is_ok()
+        );
+    }
+
+    #[test]
+    fn test_real_expression() {
+        let result = ExpressionParser::new()
+            .parse(r#"(((Artist =~ 'Flogging Molly') OR (artist =~ 'Dropkick Murphys') OR (artist =~ 'Pogues')) AND ((rating > 128) OR (rating == 0)))"#);
+        eprintln!("{:#?}", result);
+        assert!(result.is_ok());
+    }
+
+    #[test]
+    fn test_conjunction() {
+        assert!(ExpressionParser::new()
+            .parse(
+                r#"((base "foo") AND (artist == "foo bar") AND (!(file == '/net/mp3/A/a.mp3')))"#
+            )
+            .is_ok());
+
+        eprintln!("==============================================================================");
+        eprintln!("{:#?}", ExpressionParser::new()
+            .parse(
+                r#"((base 'foo') AND (artist == "foo bar") AND ((!(file == "/net/mp3/A/a.mp3")) OR (file == "/pub/mp3/A/a.mp3")))"#
+            ));
+        assert!(ExpressionParser::new()
+            .parse(
+                r#"((base 'foo') AND (artist == "foo bar") AND ((!(file == '/net/mp3/A/a.mp3')) OR (file == '/pub/mp3/A/a.mp3')))"#
+            )
+            .is_ok());
+    }
+
+    #[test]
+    fn test_disjunction() {
+        assert!(ExpressionParser::new().
+                parse(r#"((artist =~ 'Flogging Molly') OR (artist =~ 'Dropkick Murphys') OR (artist =~ 'Pogues'))"#)
+                .is_ok());
+    }
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum EvalOp {
+    And,
+    Or,
+    Not,
+}
+
+impl std::fmt::Display for EvalOp {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        match self {
+            EvalOp::And => write!(f, "And"),
+            EvalOp::Or => write!(f, "Or"),
+            EvalOp::Not => write!(f, "Not"),
+        }
+    }
+}
+
+fn peek(buf: &[u8]) -> Option<char> {
+    match buf.len() {
+        0 => None,
+        _ => Some(buf[0] as char),
+    }
+}
+
+// advancing a slice by `i` indicies can *not* be this difficult
+/// Pop a single byte off of `buf`
+fn take1(buf: &mut &[u8], i: usize) -> Result<()> {
+    if i > buf.len() {
+        bail!("Bad iso-8601 string: `{:#?}`", buf);
+    }
+    let (_first, second) = buf.split_at(i);
+    *buf = second;
+    Ok(())
+}
+
+/// Pop `i` bytes off of `buf` & parse them as a T
+fn take2<T>(buf: &mut &[u8], i: usize) -> Result<T>
+where
+    T: FromStr,
+    <T as std::str::FromStr>::Err: std::error::Error + Send + Sync + 'static,
+{
+    // 1. check len
+    if i > buf.len() {
+        bail!("Bad iso-8601 string: `{:#?}`", buf);
+    }
+
+    let (first, second) = buf.split_at(i);
+    *buf = second;
+    // 2. convert to a string
+    let s = std::str::from_utf8(first).context("Bad iso-8601 string")?;
+    // 3. parse as a T
+    s.parse::<T>()
+        .context("Failed to parse iso-8601 string as T")
+}
+
+/// Parse a timestamp in ISO 8601 format to a chrono DateTime instance
+///
+/// Surprisingly, I was unable to find an ISO 8601 parser in Rust. I *did* find a crate named
+/// iso-8601 that promised to do this, but it seemed derelict & I couldn't see what to do with the
+/// parse output in any event. The ISO 8601 format is simple enough that I've chosen to simply
+/// hand-parse it.
+pub fn parse_iso_8601(buf: &mut &[u8]) -> Result<i64> {
+    // I wonder if `nom` would be a better choice?
+
+    // The first four characters must be the year (expanded year representation is not supported by
+    // this parser).
+
+    let year: i32 = take2(buf, 4)?;
+
+    // Now at this point:
+    //   1. we may be done (i.e. buf.len() == 0)
+    //   2. we may have the timestamp (peek(buf) => Some('T'))
+    //      - day & month := 0, consume the 'T', move on to parsing the time
+    //   3. we may have a month in extended format (i.e. peek(buf) => Some('-')
+    //      - consume the '-', parse the month & move on to parsing the day
+    //   4. we may have a month in basic format (take(buf, 2) => Some('\d\d')
+    //      - parse the month & move on to parsing the day
+    let mut month = 1;
+    let mut day = 1;
+    let mut hour = 0;
+    let mut minute = 0;
+    let mut second = 0;
+    if !buf.is_empty() {
+        let next = peek(buf);
+        if next != Some('T') {
+            let mut ext_fmt = false;
+            if next == Some('-') {
+                take1(buf, 1)?;
+                ext_fmt = true;
+            }
+            month = take2(buf, 2)?;
+
+            // At this point:
+            //   1. we may be done (i.e. buf.len() == 0)
+            //   2. we may have the timestamp (peek(buf) => Some('T'))
+            //   3. we may have the day (in basic or extended format)
+            if !buf.is_empty() && peek(buf) != Some('T') {
+                if ext_fmt {
+                    take1(buf, 1)?;
+                }
+                day = take2(buf, 2)?;
+            }
+        }
+
+        // Parse time: at this point, buf will either be empty or begin with 'T'
+        if !buf.is_empty() {
+            take1(buf, 1)?;
+            // If there's a T, there must at least be an hour
+            hour = take2(buf, 2)?;
+            if !buf.is_empty() {
+                let mut ext_fmt = false;
+                if peek(buf) == Some(':') {
+                    take1(buf, 1)?;
+                    ext_fmt = true;
+                }
+                minute = take2(buf, 2)?;
+                if !buf.is_empty() {
+                    if ext_fmt {
+                        take1(buf, 1)?;
+                    }
+                    second = take2(buf, 2)?;
+                }
+            }
+        }
+
+        // At this point, there may be a timezone
+        if !buf.is_empty() {
+            if peek(buf) == Some('Z') {
+                return Ok(Utc
+                    .with_ymd_and_hms(year, month, day, hour, minute, second)
+                    .single()
+                    .ok_or(anyhow!("bad iso-8601 string"))?
+                    .timestamp());
+            } else {
+                let next = peek(buf);
+                if next != Some('-') && next != Some('+') {
+                    bail!("bad iso-8601 string")
+                }
+                let west = next == Some('-');
+                take1(buf, 1)?;
+
+                let hours: i32 = take2(buf, 2)?;
+                let mut minutes = 0;
+
+                if !buf.is_empty() {
+                    if peek(buf) == Some(':') {
+                        take1(buf, 1)?;
+                    }
+                    minutes = take2(buf, 2)?;
+                }
+
+                if west {
+                    return Ok(FixedOffset::west_opt(hours * 3600 + minutes * 60)
+                        .ok_or(anyhow!("Bad iso-8601 string"))?
+                        .with_ymd_and_hms(year, month, day, hour, minute, second)
+                        .single()
+                        .ok_or(anyhow!("Bad iso-8601 string"))?
+                        .timestamp());
+                } else {
+                    return Ok(FixedOffset::east_opt(hours * 3600 + minutes * 60)
+                        .ok_or(anyhow!("Bad iso-8601 string"))?
+                        .with_ymd_and_hms(year, month, day, hour, minute, second)
+                        .single()
+                        .ok_or(anyhow!("Bad iso-8601 string"))?
+                        .timestamp());
+                }
+            }
+        }
+    }
+    Ok(Local
+        .with_ymd_and_hms(year, month, day, hour, minute, second)
+        .single()
+        .ok_or(anyhow!("Bad iso-8601 string"))?
+        .timestamp())
+}
+
+#[cfg(test)]
+mod iso_8601_tests {
+
+    use super::*;
+
+    #[test]
+    fn smoke_tests() {
+        let mut b = "19700101T00:00:00Z".as_bytes();
+        let t = parse_iso_8601(&mut b).unwrap();
+        assert!(t == 0);
+
+        let mut b = "19700101T00:00:01Z".as_bytes();
+        let t = parse_iso_8601(&mut b).unwrap();
+        assert!(t == 1);
+
+        let mut b = "20210327T02:26:53Z".as_bytes();
+        let t = parse_iso_8601(&mut b).unwrap();
+        assert_eq!(t, 1616812013);
+
+        let mut b = "20210327T07:29:05-07:00".as_bytes();
+        let t = parse_iso_8601(&mut b).unwrap();
+        assert_eq!(t, 1616855345);
+
+        let mut b = "2021".as_bytes();
+        // Should resolve to midnight, Jan 1 2021 in local time; don't want to test against the
+        // timestamp; just make sure it parses
+        parse_iso_8601(&mut b).unwrap();
+    }
+}
+
+/// "Un-quote" a token
+///
+/// Textual tokens must be quoted, and double-quote & backslashes within backslash-escaped. If the
+/// string is quoted with single-quotes, then any single-quotes inside the string will also need
+/// to be escaped.
+///
+/// In fact, *any* characters within may be harmlessly backslash escaped; the MPD implementation
+/// walks the the string, skipping backslashes as it goes, so this implementation will do the same.
+/// I have named this method in imitation of the corresponding MPD function.
+pub fn expect_quoted(qtext: &str) -> Result<String> {
+    let mut iter = qtext.chars();
+    let quote = iter.next();
+    if quote.is_none() {
+        return Ok(String::new());
+    }
+
+    if quote != Some('\'') && quote != Some('"') {
+        bail!("Expected text to be quoted: `{}`", qtext);
+    }
+
+    let mut ret = String::new();
+
+    // Walk qtext[1..]; copying characters to `ret'. If a '\' is found, skip to the next character
+    // (even if that is a '\'). The last character in qtext should be the closing quote.
+    let mut this = iter.next();
+    while this != quote {
+        if this == Some('\\') {
+            this = iter.next();
+        }
+        match this {
+            Some(c) => ret.push(c),
+            None => {
+                bail!("Expected text to be quoted: `{}`", qtext);
+            }
+        }
+        this = iter.next();
+    }
+
+    Ok(ret)
+}
+
+#[cfg(test)]
+mod quoted_tests {
+
+    use super::*;
+
+    #[test]
+    fn smoke_tests() {
+        let b = r#""foo bar \"splat!\"""#;
+        let s = expect_quoted(b).unwrap();
+        assert!(s == r#"foo bar "splat!""#);
+    }
+}
+
+/// Create a closure that will carry out an operator on its argument
+///
+/// Call this function with an [OpCode] and a value of type `T`. `T` must be [PartialEq],
+/// [`PartialOrd`] and [`Copy`]-- an integral type will do. It will return a closure that will carry
+/// out the given [OpCode] against the given value. For instance,
+/// `make_numeric_closure::<u8>(OpCode::Equality, 11)` will return a closure that takes a `u8` &
+/// will return true if its argument is 11 (and false otherwise).
+///
+/// If [OpCode] is not pertinent to a numeric type, then this function will return Err.
+fn make_numeric_closure<'a, T: 'a + PartialEq + PartialOrd + Copy>(
+    op: OpCode,
+    val: T,
+) -> Result<impl Fn(T) -> bool + 'a> {
+    // Rust closures each have their own type, so this was the only way I could find to
+    // return them from match arms. This seems ugly; perhaps there's something I'm
+    // missing.
+    //
+    // I have no idea why I have to make these `move` closures; T is constrained to by Copy-able,
+    // so I would have expected the closure to just take a copy.
+    match op {
+        OpCode::Equality => Ok(Box::new(move |x: T| x == val) as Box<dyn Fn(T) -> bool>),
+        OpCode::Inequality => Ok(Box::new(move |x: T| x != val) as Box<dyn Fn(T) -> bool>),
+        OpCode::GreaterThan => Ok(Box::new(move |x: T| x > val) as Box<dyn Fn(T) -> bool>),
+        OpCode::LessThan => Ok(Box::new(move |x: T| x < val) as Box<dyn Fn(T) -> bool>),
+        OpCode::GreaterThanEqual => Ok(Box::new(move |x: T| x >= val) as Box<dyn Fn(T) -> bool>),
+        OpCode::LessThanEqual => Ok(Box::new(move |x: T| x <= val) as Box<dyn Fn(T) -> bool>),
+        _ => bail!("Invalid operant: `{op}`"),
+    }
+}
+
+async fn eval_numeric_sticker_term<
+    // The `FromStr' trait bound is really weird, but if I don't constrain the associated
+    // Err type to be `ParseIntError' the compiler complains about not being able to convert
+    // it to type `Error'. I'm probably still "thinking in C++" and imagining the compiler
+    // instantiating this function for each type (u8, usize, &c) instead of realizing that the Rust
+    // compiler is processing this as a first-class function.
+    //
+    // For instance, I can do the conversion manually, so long as I constrain the Err type
+    // to implement std::error::Error. I should probably be doing that, but it clutters the
+    // code. I'll figure it out when I need to extend this function to handle non-integral types
+    // :)
+    T: PartialEq + PartialOrd + Copy + FromStr<Err = std::num::ParseIntError> + std::fmt::Display,
+>(
+    sticker: &str,
+    client: &mut Client,
+    op: OpCode,
+    numeric_val: T,
+    default_val: T,
+) -> Result<HashSet<String>> {
+    let cmp = make_numeric_closure(op, numeric_val)?;
+    // It would be better to idle on the sticker DB & just update our collection on change, but for
+    // a first impl. this will do.
+    //
+    // Call `get_stickers'; this will return a HashMap from song URIs to ratings expressed as text
+    // (as all stickers are). This stanza will drain that collection into a new one with the ratings
+    // expressed as T.
+    //
+    // The point is that conversion from text to rating, lastplayed, or whatever can fail; the
+    // invocation of `collect' will call `from_iter' to convert a collection of Result-s to a Result
+    // of a collection.
+    let mut m = client
+        .get_stickers(sticker)
+        .await
+        .context("Failed to get stickers from client")?
+        .drain()
+        .map(|(k, v)| v.parse::<T>().map(|x| (k, x)))
+        .collect::<std::result::Result<HashMap<String, T>, _>>()
+        .context("Failed to parse sticker as T")?;
+    // `m' is now a map of song URI to rating/playcount/wathever (expressed as a T)... for all songs
+    // that have the salient sticker.
+    //
+    // This seems horribly inefficient, but I'm going to fetch all the song URIs in the music DB,
+    // and augment `m' with entries of `default_val' for any that are not already there.
+    client
+        .get_all_songs()
+        .await
+        .context("Failed to get all songs from client")?
+        .drain(..)
+        .for_each(|song| {
+            m.entry(song).or_insert(default_val);
+        });
+
+    // Now that we don't have to worry about operations that can fail, we can use
+    // `filter_map'.
+    Ok(m.drain()
+        .filter_map(|(k, v)| cmp(v).as_some(k))
+        .collect::<HashSet<String>>())
+}
+
+/// Convenience struct collecting the names for assorted stickers on which one may search
+///
+/// While the search terms 'rating', 'playcount' &c are fixed & part of the filter grammar offered
+/// by mpdpopm, the precise names of the corresponding stickers are configurable & hence must be
+/// passed in. Three references to str is already unweildy IMO, and since I expect the number of
+/// stickers on which one can search to grow further, I decided to wrap 'em up in a struct. The
+/// lifetime is there to support the caller just using a reference to an existing string rather than
+/// making a copy.
+pub struct FilterStickerNames<'a> {
+    rating: &'a str,
+    playcount: &'a str,
+    lastplayed: &'a str,
+    skipped: &'a str,
+}
+
+impl FilterStickerNames<'static> {
+    pub fn new() -> FilterStickerNames<'static> {
+        Self::default()
+    }
+}
+
+impl Default for FilterStickerNames<'static> {
+    fn default() -> Self {
+        Self {
+            rating: rating::STICKER,
+            playcount: play_count::STICKER,
+            lastplayed: last_played::STICKER,
+            skipped: skip_count::STICKER,
+        }
+    }
+}
+
+/// Evaluate a Term
+///
+/// Take a Term from the Abstract Syntax tree & resolve it to a collection of song URIs. Set `case`
+/// to `true` to search case-sensitively & `false` to make the search case-insensitive.
+async fn eval_term<'a>(
+    term: &Term,
+    case: bool,
+    client: &mut Client,
+    stickers: &FilterStickerNames<'a>,
+) -> Result<HashSet<String>> {
+    match term {
+        Term::UnaryCondition(op, val) => Ok(client
+            .find1(&format!("{}", op), &quote_value(val), case)
+            .await
+            .context("Failed to find1 on client")?
+            .drain(..)
+            .collect()),
+        Term::BinaryCondition(attr, op, val) => {
+            if *attr == Selector::Rating {
+                let value = match val {
+                    Value::Int(n) => *n as i128,
+                    Value::Uint(n) => *n as i128,
+                    _ => bail!("filter ratings expect an int; got {:#?}", val),
+                };
+
+                let val: i8 = value.try_into().with_context(|| {
+                    format!(
+                        "Failed to convert `{}` into a number from -128 to 128!",
+                        value
+                    )
+                })?;
+                Ok(eval_numeric_sticker_term(stickers.rating, client, *op, val, 0).await?)
+            } else if *attr == Selector::PlayCount {
+                match val {
+                    Value::Uint(n) => {
+                        Ok(
+                            eval_numeric_sticker_term(stickers.playcount, client, *op, *n, 0)
+                                .await?,
+                        )
+                    }
+                    _ => bail!("filter play_count expect an unsigned int; got {:#?}", val),
+                }
+            } else if *attr == Selector::LastPlayed {
+                match val {
+                    Value::UnixEpoch(t) => {
+                        Ok(
+                            eval_numeric_sticker_term(stickers.lastplayed, client, *op, *t, 0)
+                                .await?,
+                        )
+                    }
+                    _ => bail!("filter last_played expect an unix epoch; got {:#?}", val),
+                }
+            } else if *attr == Selector::Skipped {
+                match val {
+                    Value::Uint(t) => {
+                        Ok(eval_numeric_sticker_term(stickers.skipped, client, *op, *t, 0).await?)
+                    }
+                    _ => bail!("filter skipped expect an unsigned int; got {:#?}", val),
+                }
+            } else {
+                Ok(client
+                    .find2(
+                        &format!("{}", attr),
+                        &format!("{}", op),
+                        &quote_value(val),
+                        case,
+                    )
+                    .await
+                    .context("Failed to `find2` on client")?
+                    .drain(..)
+                    .collect())
+            }
+        }
+    }
+}
+
+/// The evaluation stack contains logical operators & sets of song URIs
+#[derive(Debug)]
+enum EvalStackNode {
+    Op(EvalOp),
+    Result(HashSet<String>),
+}
+
+async fn negate_result(
+    res: &HashSet<String>,
+    client: &mut Client,
+) -> std::result::Result<HashSet<String>, Error> {
+    Ok(client
+        .get_all_songs()
+        .await
+        .context("Failed to get all songs from client")?
+        .drain(..)
+        .filter_map(|song| {
+            // Some(thing) adds thing, None elides it
+            if !res.contains(&song) {
+                Some(song)
+            } else {
+                None
+            }
+        })
+        .collect::<HashSet<String>>())
+}
+
+/// Reduce the evaluation stack as far as possible.
+///
+/// We can pop the stack in two cases:
+///
+/// 1. S.len() > 2 and S[-3] is either And or Or, and both S[-1] & S[-2] are Result-s
+/// 2. S.len() > 1, S[-2] is Not, and S[-1] is a Result
+async fn reduce(stack: &mut Vec<EvalStackNode>, client: &mut Client) -> Result<()> {
+    loop {
+        let mut reduced = false;
+        let n = stack.len();
+        if n > 1 {
+            // Take care to compute the reduction *before* popping the stack-- thank you, borrow
+            // checker!
+            let reduction = if let (EvalStackNode::Op(EvalOp::Not), EvalStackNode::Result(r)) =
+                (&stack[n - 2], &stack[n - 1])
+            {
+                Some(negate_result(r, client).await?)
+            } else {
+                None
+            };
+
+            if let Some(res) = reduction {
+                stack.pop();
+                stack.pop();
+                stack.push(EvalStackNode::Result(res));
+                reduced = true;
+            }
+        }
+        let n = stack.len();
+        if n > 2 {
+            // Take care to compute the reduction *before* popping the stack-- thank you, borrow
+            // checker!
+            let and_reduction = if let (
+                EvalStackNode::Op(EvalOp::And),
+                EvalStackNode::Result(r1),
+                EvalStackNode::Result(r2),
+            ) = (&stack[n - 3], &stack[n - 2], &stack[n - 1])
+            {
+                Some(r1.intersection(r2).cloned().collect())
+            } else {
+                None
+            };
+
+            if let Some(res) = and_reduction {
+                stack.pop();
+                stack.pop();
+                stack.pop();
+                stack.push(EvalStackNode::Result(res));
+                reduced = true;
+            }
+        }
+        let n = stack.len();
+        if n > 2 {
+            let or_reduction = if let (
+                EvalStackNode::Op(EvalOp::Or),
+                EvalStackNode::Result(r1),
+                EvalStackNode::Result(r2),
+            ) = (&stack[n - 3], &stack[n - 2], &stack[n - 1])
+            {
+                Some(r1.union(r2).cloned().collect())
+            } else {
+                None
+            };
+
+            if let Some(res) = or_reduction {
+                stack.pop();
+                stack.pop();
+                stack.pop();
+                stack.push(EvalStackNode::Result(res));
+                reduced = true;
+            }
+        }
+
+        if !reduced {
+            break;
+        }
+    }
+
+    Ok(())
+}
+
+/// Evaluate an abstract syntax tree (AST)
+pub async fn evaluate<'a>(
+    expr: &Expression,
+    case: bool,
+    client: &mut Client,
+    stickers: &FilterStickerNames<'a>,
+) -> Result<HashSet<String>> {
+    // We maintain *two* stacks, one for parsing & one for evaluation.  Let sp (for "stack(parse)")
+    // be a stack of references to nodes in the parse tree.
+    let mut sp = Vec::new();
+    // Initialize it with the root; as we walk the tree, we'll pop the "most recent" node, and push
+    // children.
+    sp.push(expr);
+
+    // Let se (for "stack(eval)") be a stack of operators & URIs.
+    let mut se = Vec::new();
+
+    // Simple DFS traversal of the AST:
+    while let Some(node) = sp.pop() {
+        // and dispatch based on what we've got:
+        match node {
+            // 1. we have a simple term: this can be immediately resolved to a set of song URIs. Do
+            // so & push the resulting set onto the evaluation stack.
+            Expression::Simple(bt) => se.push(EvalStackNode::Result(
+                eval_term(bt, case, client, stickers).await?,
+            )),
+            // 2. we have a negation: push the "not" operator onto the evaluation stack & the child
+            // onto the parse stack.
+            Expression::Negation(be) => {
+                se.push(EvalStackNode::Op(EvalOp::Not));
+                sp.push(be);
+            }
+            // 3. conjunction-- push the "and" operator onto the evaluation stack & the children
+            // onto the parse stack (be sure to push the right-hand child first, so it will be
+            // popped second)
+            // bc is &Box<Conjunction<'a>>, so &**bc is &Conjunction<'a>
+            Expression::Conjunction(bc) => {
+                let mut conj = &**bc;
+                loop {
+                    match conj {
+                        Conjunction::Simple(bel, ber) => {
+                            se.push(EvalStackNode::Op(EvalOp::And));
+                            sp.push(&**ber);
+                            sp.push(&**bel);
+                            break;
+                        }
+                        Conjunction::Compound(bc, be) => {
+                            se.push(EvalStackNode::Op(EvalOp::And));
+                            sp.push(&**be);
+                            conj = bc;
+                        }
+                    }
+                }
+            }
+            Expression::Disjunction(bt) => {
+                let mut disj = &**bt;
+                loop {
+                    match disj {
+                        Disjunction::Simple(bel, ber) => {
+                            se.push(EvalStackNode::Op(EvalOp::Or));
+                            sp.push(ber);
+                            sp.push(bel);
+                            break;
+                        }
+                        Disjunction::Compound(bd, be) => {
+                            se.push(EvalStackNode::Op(EvalOp::Or));
+                            sp.push(&**be);
+                            disj = bd;
+                        }
+                    }
+                }
+            }
+        }
+
+        reduce(&mut se, client).await?;
+    }
+
+    // At this point, sp is empty, but there had better be something on se. Keep reducing the stack
+    // until either we can't any further (in which case we error) or there is only one element left
+    // (in which case we return that).
+    reduce(&mut se, client).await?;
+
+    // Now, se had better have one element, and that element had better be a Result.
+    if 1 != se.len() {
+        debug!("Too many ({}) operands left on stack:", se.len());
+        se.iter()
+            .enumerate()
+            .for_each(|(i, x)| debug!("    {}: {:#?}", i, x));
+        bail!("The number of operants is too big `{}`", se.len());
+    }
+
+    let ret = se.pop().unwrap();
+    match ret {
+        EvalStackNode::Result(result) => Ok(result),
+        EvalStackNode::Op(op) => {
+            debug!("Operator left on stack (!?): {:#?}", op);
+            bail!("Operator left on stack: {op}")
+        }
+    }
+}
+
+#[cfg(test)]
+mod evaluation_tests {
+
+    use super::*;
+    use crate::filters::*;
+
+    use crate::clients::Client;
+    use crate::clients::test_mock::Mock;
+
+    #[tokio::test]
+    async fn smoke() {
+        let mock = Box::new(Mock::new(&[(
+            r#"find "(base \"foo\")""#,
+            "file: foo/a.mp3
+Artist: The Foobars
+file: foo/b.mp3
+Title: b!
+OK",
+        )]));
+        let mut cli = Client::new(mock).unwrap();
+
+        let stickers = FilterStickerNames::new();
+
+        let expr = ExpressionParser::new().parse(r#"(base "foo")"#).unwrap();
+        let result = evaluate(&expr, true, &mut cli, &stickers).await;
+        assert!(result.is_ok());
+
+        let g: HashSet<String> = ["foo/a.mp3", "foo/b.mp3"]
+            .iter()
+            .map(|x| x.to_string())
+            .collect();
+        assert!(result.unwrap() == g);
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/lib.rs b/pkgs/by-name/mp/mpdpopm/src/lib.rs
new file mode 100644
index 00000000..cc2765dc
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/lib.rs
@@ -0,0 +1,185 @@
+// Copyright (C) 2020-2025 Michael herstine <sp1ff@pobox.com>
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+//! # mpdpopm
+//!
+//! Maintain ratings & playcounts for your mpd server.
+//!
+//! # Introduction
+//!
+//! This is a companion daemon for [mpd](https://www.musicpd.org/) that maintains play counts &
+//! ratings. Similar to [mpdfav](https://github.com/vincent-petithory/mpdfav), but written in Rust
+//! (which I prefer to Go), it will allow you to maintain that information in your tags, as well as
+//! the sticker database, by invoking external commands to keep your tags up-to-date (something
+//! along the lines of [mpdcron](https://alip.github.io/mpdcron)).
+//!
+//! # Commands
+//!
+//! I'm currently sending all commands over one (configurable) channel.
+//!
+
+#![recursion_limit = "512"] // for the `select!' macro
+
+pub mod clients;
+pub mod config;
+pub mod dj;
+pub mod filters_ast;
+pub mod messanges;
+pub mod playcounts;
+pub mod storage;
+pub mod vars;
+
+#[rustfmt::skip]
+#[allow(clippy::extra_unused_lifetimes)]
+#[allow(clippy::needless_lifetimes)]
+#[allow(clippy::let_unit_value)]
+#[allow(clippy::just_underscores_and_digits)]
+pub mod filters {
+    include!(concat!(env!("OUT_DIR"), "/src/filters.rs"));
+}
+
+use crate::{
+    clients::{Client, IdleClient, IdleSubSystem},
+    config::{Config, Connection},
+    messanges::MessageQueue,
+    playcounts::PlayState,
+};
+
+use anyhow::{Context, Error};
+use futures::{future::FutureExt, pin_mut, select};
+use tokio::{
+    signal,
+    signal::unix::{SignalKind, signal},
+    time::{Duration, sleep},
+};
+use tracing::{debug, error, info};
+
+/// Core `mppopmd' logic
+pub async fn mpdpopm(cfg: Config) -> std::result::Result<(), Error> {
+    info!("mpdpopm {} beginning.", vars::VERSION);
+
+    let mut client =
+        match cfg.conn {
+            Connection::Local { ref path } => Client::open(path)
+                .await
+                .with_context(|| format!("Failed to open socket at `{}`", path.display()))?,
+            Connection::TCP { ref host, port } => Client::connect(format!("{}:{}", host, port))
+                .await
+                .with_context(|| format!("Failed to connect to client at `{}:{}`", host, port))?,
+        };
+
+    let mut state = PlayState::new(&mut client, cfg.played_thresh)
+        .await
+        .context("Failed to construct PlayState")?;
+
+    let mut idle_client = match cfg.conn {
+        Connection::Local { ref path } => IdleClient::open(path)
+            .await
+            .context("Failed to open idle client")?,
+        Connection::TCP { ref host, port } => IdleClient::connect(format!("{}:{}", host, port))
+            .await
+            .context("Failed to connect to TCP idle client")?,
+    };
+
+    let mut mqueue = MessageQueue::new();
+
+    idle_client
+        .subscribe(&cfg.commands_chan)
+        .await
+        .context("Failed to subscribe to idle_client")?;
+
+    let mut hup = signal(SignalKind::hangup()).unwrap();
+    let mut kill = signal(SignalKind::terminate()).unwrap();
+    let ctrl_c = signal::ctrl_c().fuse();
+
+    let sighup = hup.recv().fuse();
+    let sigkill = kill.recv().fuse();
+
+    let tick = sleep(Duration::from_millis(cfg.poll_interval_ms)).fuse();
+    pin_mut!(ctrl_c, sighup, sigkill, tick);
+
+    let mut done = false;
+    let mut msg_check_needed = false;
+    while !done {
+        debug!("selecting...");
+        {
+            // `idle_client' mutably borrowed here
+            let mut idle = Box::pin(idle_client.idle().fuse());
+            loop {
+                select! {
+                    _ = ctrl_c => {
+                        info!("got ctrl-C");
+                        done = true;
+                        break;
+                    },
+                    _ = sighup => {
+                        info!("got SIGHUP");
+                        done = true;
+                        break;
+                    },
+                    _ = sigkill => {
+                        info!("got SIGKILL");
+                        done = true;
+                        break;
+                    },
+                    _ = tick => {
+                        tick.set(sleep(Duration::from_millis(cfg.poll_interval_ms)).fuse());
+                        state.update(&mut client)
+                                .await
+                                .context("PlayState update failed")?;
+                    },
+                    res = idle => match res {
+                        Ok(subsys) => {
+                            debug!("subsystem {} changed", subsys);
+                            if subsys == IdleSubSystem::Player {
+                                state.update(&mut client)
+                                    .await
+                                    .context("PlayState update failed")?;
+
+                                mqueue
+                                    .advance_dj(&mut client)
+                                    .await
+                                    .context("MessageQueue tick failed")?;
+                            } else if subsys == IdleSubSystem::Message {
+                                msg_check_needed = true;
+                            }
+                            break;
+                        },
+                        Err(err) => {
+                            debug!("error {err:#?} on idle");
+                            done = true;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        if msg_check_needed {
+            msg_check_needed = false;
+
+            // Check for any messages that have come in; if there's an error there's not a lot we
+            // can do about it (suppose some client fat-fingers a command name, e.g.)-- just log it
+            // & move on.
+            if let Err(err) = mqueue.check_messages(&mut client, &mut idle_client).await {
+                error!("Error while processing messages: {err:#?}");
+            }
+        }
+    }
+
+    info!("mpdpopm exiting.");
+
+    Ok(())
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/messanges/mod.rs b/pkgs/by-name/mp/mpdpopm/src/messanges/mod.rs
new file mode 100644
index 00000000..c5320dd9
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/messanges/mod.rs
@@ -0,0 +1,110 @@
+use anyhow::{Context, Result, anyhow, bail, ensure};
+use clap::{Parser, Subcommand};
+use shlex::Shlex;
+use tracing::info;
+
+use crate::{
+    clients::{Client, IdleClient},
+    dj::{Dj, algorithms::Discovery},
+};
+
+pub const COMMAND_CHANNEL: &str = "unwoundstack.com:commands";
+
+#[derive(Parser)]
+struct Commands {
+    #[command(subcommand)]
+    command: SubCommand,
+}
+
+#[derive(Parser)]
+enum SubCommand {
+    Dj {
+        #[command(subcommand)]
+        command: DjCommand,
+    },
+}
+
+#[derive(Subcommand)]
+enum DjCommand {
+    Start {},
+    Stop {},
+}
+
+pub(crate) struct MessageQueue {
+    dj: Option<Dj<Discovery>>,
+}
+
+impl MessageQueue {
+    pub(crate) fn new() -> Self {
+        Self { dj: None }
+    }
+
+    pub(crate) async fn advance_dj(&mut self, client: &mut Client) -> Result<()> {
+        if let Some(dj) = self.dj.as_mut() {
+            dj.add_track(client).await?;
+        }
+
+        Ok(())
+    }
+
+    /// Read messages off the commands channel & dispatch 'em
+    pub(crate) async fn check_messages(
+        &mut self,
+        client: &mut Client,
+        idle_client: &mut IdleClient,
+    ) -> Result<()> {
+        let m = idle_client
+            .get_messages()
+            .await
+            .context("Failed to `get_messages` from client")?;
+
+        for (chan, msgs) in m {
+            ensure!(chan == COMMAND_CHANNEL, "Unknown channel: `{}`", chan);
+
+            for msg in msgs {
+                self.process(client, msg).await?;
+            }
+        }
+
+        Ok(())
+    }
+
+    /// Process a single command
+    pub(crate) async fn process(&mut self, client: &mut Client, msg: String) -> Result<()> {
+        let split = {
+            let mut shl = Shlex::new(&msg);
+            let res: Vec<_> = shl.by_ref().collect();
+
+            if shl.had_error {
+                bail!("Failed to parse command '{msg}'")
+            }
+
+            assert_eq!(shl.line_no, 1, "A unexpected newline appeared");
+            assert!(!res.is_empty());
+
+            let mut base = vec!["base".to_owned()];
+            base.extend(res);
+            base
+        };
+
+        let args = Commands::parse_from(split);
+
+        match args.command {
+            SubCommand::Dj { command } => match command {
+                DjCommand::Start {} => {
+                    info!("Dj started");
+                    self.dj = Some(Dj::new(Discovery::new()));
+                    self.advance_dj(client).await?;
+                }
+                DjCommand::Stop {} => {
+                    self.dj
+                        .take()
+                        .ok_or_else(|| anyhow!("Tried to disable already disabled dj mode"))?;
+                    info!("Dj stopped");
+                }
+            },
+        }
+
+        Ok(())
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/playcounts.rs b/pkgs/by-name/mp/mpdpopm/src/playcounts.rs
new file mode 100644
index 00000000..417b3e7e
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/playcounts.rs
@@ -0,0 +1,313 @@
+// Copyright (C) 2020-2025 Michael herstine <sp1ff@pobox.com>
+//
+// This file is part of mpdpopm.
+//
+// mpdpopm is free software: you can redistribute it and/or modify it under the terms of the GNU
+// General Public License as published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// mpdpopm is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+// Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along with mpdpopm.  If not,
+// see <http://www.gnu.org/licenses/>.
+
+//! playcounts -- managing play counts & lastplayed times
+//!
+//! # Introduction
+//!
+//! Play counts & last played timestamps are maintained so long as [PlayState::update] is called
+//! regularly (every few seconds, say). For purposes of library maintenance, however, they can be
+//! set explicitly:
+//!
+//! - `setpc PLAYCOUNT( TRACK)?`
+//! - `setlp LASTPLAYED( TRACK)?`
+//!
+
+use crate::clients::{Client, PlayerStatus};
+use crate::storage::{last_played, play_count, skip_count};
+
+use anyhow::{Context, Error, Result, anyhow};
+use tracing::{debug, info};
+
+use std::time::SystemTime;
+
+/// Current server state in terms of the play status (stopped/paused/playing, current track, elapsed
+/// time in current track, &c)
+#[derive(Debug)]
+pub struct PlayState {
+    /// Last known server status
+    last_server_stat: PlayerStatus,
+
+    /// true if we have already incremented the last known track's playcount
+    have_incr_play_count: bool,
+
+    /// Percentage threshold, expressed as a number between zero & one, for considering a song to
+    /// have been played
+    played_thresh: f64,
+    last_song_was_skipped: bool,
+}
+
+impl PlayState {
+    /// Create a new PlayState instance; async because it will reach out to the mpd server
+    /// to get current status.
+    pub async fn new(
+        client: &mut Client,
+        played_thresh: f64,
+    ) -> std::result::Result<PlayState, Error> {
+        Ok(PlayState {
+            last_server_stat: client.status().await?,
+            have_incr_play_count: false,
+            last_song_was_skipped: false,
+            played_thresh,
+        })
+    }
+
+    /// Retrieve a copy of the last known player status
+    pub fn last_status(&self) -> PlayerStatus {
+        self.last_server_stat.clone()
+    }
+
+    /// Poll the server-- update our status; maybe increment the current track's play count; the
+    /// caller must arrange to have this method invoked periodically to keep our state fresh
+    pub async fn update(&mut self, client: &mut Client) -> Result<()> {
+        let new_stat = client
+            .status()
+            .await
+            .context("Failed to get client status")?;
+
+        match (&self.last_server_stat, &new_stat) {
+            (PlayerStatus::Play(last), PlayerStatus::Play(curr))
+            | (PlayerStatus::Pause(last), PlayerStatus::Play(curr))
+            | (PlayerStatus::Play(last), PlayerStatus::Pause(curr))
+            | (PlayerStatus::Pause(last), PlayerStatus::Pause(curr)) => {
+                // Last we knew, we were playing, and we're playing now.
+                if last.songid != curr.songid {
+                    debug!("New songid-- resetting PC incremented flag.");
+
+                    if !self.have_incr_play_count {
+                        // We didn't mark the previous song as played.
+                        // As such, the user must have skipped it :(
+                        self.last_song_was_skipped = true;
+                    }
+
+                    self.have_incr_play_count = false;
+                } else if last.elapsed > curr.elapsed
+                    && self.have_incr_play_count
+                    && curr.elapsed / curr.duration <= 0.1
+                {
+                    debug!("Re-play-- resetting PC incremented flag.");
+                    self.have_incr_play_count = false;
+                }
+            }
+            (PlayerStatus::Stopped, PlayerStatus::Play(_))
+            | (PlayerStatus::Stopped, PlayerStatus::Pause(_))
+            | (PlayerStatus::Pause(_), PlayerStatus::Stopped)
+            | (PlayerStatus::Play(_), PlayerStatus::Stopped) => {
+                self.have_incr_play_count = false;
+            }
+            (PlayerStatus::Stopped, PlayerStatus::Stopped) => (),
+        }
+
+        match &new_stat {
+            PlayerStatus::Play(curr) => {
+                let pct = curr.played_pct();
+                debug!("Updating status: {:.3}% complete.", 100.0 * pct);
+                if !self.have_incr_play_count && pct >= self.played_thresh {
+                    info!(
+                        "Increment play count for '{}' (songid: {}) at {} played.",
+                        curr.file.display(),
+                        curr.songid,
+                        curr.elapsed / curr.duration
+                    );
+
+                    let file = curr.file.to_str().ok_or_else(|| {
+                        anyhow!("Failed to parse path as utf8: `{}`", curr.file.display())
+                    })?;
+
+                    let curr_pc = play_count::get(client, file).await?.unwrap_or_default();
+
+                    debug!("Current PC is {}.", curr_pc);
+
+                    last_played::set(
+                        client,
+                        file,
+                        SystemTime::now()
+                            .duration_since(SystemTime::UNIX_EPOCH)
+                            .context("Failed to get system time")?
+                            .as_secs(),
+                    )
+                    .await?;
+                    self.have_incr_play_count = true;
+
+                    play_count::set(client, file, curr_pc + 1).await?;
+                } else if self.last_song_was_skipped {
+                    self.last_song_was_skipped = false;
+                    let last = self
+                        .last_server_stat
+                        .current_song()
+                        .expect("To exist, as it was skipped");
+
+                    info!(
+                        "Marking '{}' (songid: {}) as skipped at {}.",
+                        last.file.display(),
+                        last.songid,
+                        last.elapsed / last.duration
+                    );
+
+                    let file = last.file.to_str().ok_or_else(|| {
+                        anyhow!("Failed to parse path as utf8: `{}`", last.file.display())
+                    })?;
+
+                    let skip_count = skip_count::get(client, file).await?.unwrap_or_default();
+                    skip_count::set(client, file, skip_count + 1).await?;
+                }
+            }
+            PlayerStatus::Pause(_) | PlayerStatus::Stopped => (),
+        };
+
+        self.last_server_stat = new_stat;
+        Ok(()) // No need to update the DB
+    }
+}
+
+#[cfg(test)]
+mod player_state_tests {
+    use super::*;
+    use crate::clients::test_mock::Mock;
+
+    /// "Smoke" tests for player state
+    #[tokio::test]
+    async fn player_state_smoke() {
+        let mock = Box::new(Mock::new(&[
+            (
+                "status",
+                "repeat: 0
+random: 1
+single: 0
+consume: 1
+playlist: 2
+playlistlength: 66
+mixrampdb: 0.000000
+state: stop
+xfade: 5
+song: 51
+songid: 52
+nextsong: 11
+nextsongid: 12
+OK
+",
+            ),
+            (
+                "status",
+                "volume: 100
+repeat: 0
+random: 1
+single: 0
+consume: 1
+playlist: 2
+playlistlength: 66
+mixrampdb: 0.000000
+state: play
+xfade: 5
+song: 51
+songid: 52
+time: 5:228
+elapsed: 5.337
+bitrate: 192
+duration: 227.637
+audio: 44100:24:2
+nextsong: 11
+nextsongid: 12
+OK
+",
+            ),
+            (
+                "playlistid 52",
+                "file: E/Enya - Wild Child.mp3
+Last-Modified: 2008-11-09T00:06:30Z
+Artist: Enya
+Title: Wild Child
+Album: A Day Without Rain (Japanese Retail)
+Date: 2000
+Genre: Celtic
+Time: 228
+duration: 227.637
+Pos: 51
+Id: 52
+OK
+",
+            ),
+            (
+                "status",
+                "volume: 100
+repeat: 0
+random: 1
+single: 0
+consume: 1
+playlist: 2
+playlistlength: 66
+mixrampdb: 0.000000
+state: play
+xfade: 5
+song: 51
+songid: 52
+time: 5:228
+elapsed: 200
+bitrate: 192
+duration: 227.637
+audio: 44100:24:2
+nextsong: 11
+nextsongid: 12
+OK
+",
+            ),
+            (
+                "playlistid 52",
+                "file: E/Enya - Wild Child.mp3
+Last-Modified: 2008-11-09T00:06:30Z
+Artist: Enya
+Title: Wild Child
+Album: A Day Without Rain (Japanese Retail)
+Date: 2000
+Genre: Celtic
+Time: 228
+duration: 227.637
+Pos: 51
+Id: 52
+OK
+",
+            ),
+            (
+                "sticker get song \"E/Enya - Wild Child.mp3\" unwoundstack.com:playcount",
+                "sticker: unwoundstack.com:playcount=11\nOK\n",
+            ),
+            (
+                &format!(
+                    "sticker set song \"E/Enya - Wild Child.mp3\" unwoundstack.com:lastplayed {}",
+                    SystemTime::now()
+                        .duration_since(SystemTime::UNIX_EPOCH)
+                        .unwrap()
+                        .as_secs()
+                ),
+                "OK\n",
+            ),
+            (
+                "sticker set song \"E/Enya - Wild Child.mp3\" unwoundstack.com:playcount 12",
+                "OK\n",
+            ),
+        ]));
+
+        let mut cli = Client::new(mock).unwrap();
+        let mut ps = PlayState::new(&mut cli, 0.6).await.unwrap();
+        let check = match ps.last_status() {
+            PlayerStatus::Play(_) | PlayerStatus::Pause(_) => false,
+            PlayerStatus::Stopped => true,
+        };
+        assert!(check);
+
+        ps.update(&mut cli).await.unwrap();
+        ps.update(&mut cli).await.unwrap()
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs b/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs
new file mode 100644
index 00000000..a6f20d5b
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/storage/mod.rs
@@ -0,0 +1,145 @@
+use anyhow::Result;
+
+pub mod play_count {
+    use anyhow::Context;
+
+    use crate::clients::Client;
+
+    use super::Result;
+
+    pub const STICKER: &str = "unwoundstack.com:playcount";
+
+    /// Retrieve the play count for a track
+    pub async fn get(client: &mut Client, file: &str) -> Result<Option<usize>> {
+        match client
+            .get_sticker::<usize>(file, STICKER)
+            .await
+            .context("Failed to get sticker from client")?
+        {
+            Some(n) => Ok(Some(n)),
+            None => Ok(None),
+        }
+    }
+
+    /// Set the play count for a track-- this will run the associated command, if any
+    pub async fn set(client: &mut Client, file: &str, play_count: usize) -> Result<()> {
+        client
+            .set_sticker(file, STICKER, &format!("{}", play_count))
+            .await
+            .context("Failed to set_sticker on client")?;
+
+        Ok(())
+    }
+
+    #[cfg(test)]
+    mod pc_lp_tests {
+        use super::*;
+        use crate::{clients::test_mock::Mock, storage::play_count};
+
+        /// "Smoke" tests for play counts & last played times
+        #[tokio::test]
+        async fn pc_smoke() {
+            let mock = Box::new(Mock::new(&[
+                (
+                    "sticker get song a unwoundstack.com:playcount",
+                    "sticker: unwoundstack.com:playcount=11\nOK\n",
+                ),
+                (
+                    "sticker get song a unwoundstack.com:playcount",
+                    "ACK [50@0] {sticker} no such sticker\n",
+                ),
+                ("sticker get song a unwoundstack.com:playcount", "splat!"),
+            ]));
+            let mut cli = Client::new(mock).unwrap();
+
+            assert_eq!(play_count::get(&mut cli, "a").await.unwrap().unwrap(), 11);
+            let val = play_count::get(&mut cli, "a").await.unwrap();
+            assert!(val.is_none());
+            play_count::get(&mut cli, "a").await.unwrap_err();
+        }
+    }
+}
+
+pub mod skip_count {
+    use anyhow::Context;
+
+    use crate::clients::Client;
+
+    use super::Result;
+
+    pub(crate) const STICKER: &str = "unwoundstack.com:skipped_count";
+
+    /// Retrieve the skip count for a track
+    pub async fn get(client: &mut Client, file: &str) -> Result<Option<usize>> {
+        match client
+            .get_sticker::<usize>(file, STICKER)
+            .await
+            .context("Failed to get_sticker on client")?
+        {
+            Some(n) => Ok(Some(n)),
+            None => Ok(None),
+        }
+    }
+
+    /// Set the skip count for a track
+    pub async fn set(client: &mut Client, file: &str, skip_count: usize) -> Result<()> {
+        client
+            .set_sticker(file, STICKER, &format!("{}", skip_count))
+            .await
+            .context("Failed to set_sticker on client")
+    }
+}
+
+pub mod last_played {
+    use anyhow::Context;
+
+    use crate::clients::Client;
+
+    use super::Result;
+
+    pub const STICKER: &str = "unwoundstack.com:lastplayed";
+
+    /// Retrieve the last played timestamp for a track (seconds since Unix epoch)
+    pub async fn get(client: &mut Client, file: &str) -> Result<Option<u64>> {
+        client
+            .get_sticker::<u64>(file, STICKER)
+            .await
+            .context("Falied to get_sticker on client")
+    }
+
+    /// Set the last played for a track
+    pub async fn set(client: &mut Client, file: &str, last_played: u64) -> Result<()> {
+        client
+            .set_sticker(file, STICKER, &format!("{}", last_played))
+            .await
+            .context("Failed to set_sticker on client")?;
+        Ok(())
+    }
+}
+
+pub mod rating {
+    use anyhow::Context;
+
+    use crate::clients::Client;
+
+    use super::Result;
+
+    pub const STICKER: &str = "unwoundstack.com:ratings_count";
+
+    /// Retrieve the rating count for a track
+    pub async fn get(client: &mut Client, file: &str) -> Result<Option<i8>> {
+        client
+            .get_sticker::<i8>(file, STICKER)
+            .await
+            .context("Failed to get_sticker on client")
+    }
+
+    /// Set the rating count for a track
+    pub async fn set(client: &mut Client, file: &str, rating_count: i8) -> Result<()> {
+        client
+            .set_sticker(file, STICKER, &format!("{}", rating_count))
+            .await
+            .context("Failed to set_sticker on client")?;
+        Ok(())
+    }
+}
diff --git a/pkgs/by-name/mp/mpdpopm/src/vars.rs b/pkgs/by-name/mp/mpdpopm/src/vars.rs
new file mode 100644
index 00000000..7cacec66
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/src/vars.rs
@@ -0,0 +1,4 @@
+pub static VERSION: &str = env!("CARGO_PKG_VERSION");
+pub static AUTHOR: &str = env!("CARGO_PKG_AUTHORS");
+pub static LOCALSTATEDIR: &str = "/home/soispha/.local/state";
+pub static PREFIX: &str = "/home/soispha/.local/share/mpdpopm";
diff --git a/pkgs/by-name/mp/mpdpopm/update.sh b/pkgs/by-name/mp/mpdpopm/update.sh
new file mode 100755
index 00000000..e0c0821b
--- /dev/null
+++ b/pkgs/by-name/mp/mpdpopm/update.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env sh
+
+# Mpdpopm - A mpd rating tracker
+#
+# Copyright (C) 2026 Benedikt Peetz, Michael Herstine <sp1ff@pobox.com> <benedikt.peetz@b-peetz.de, sp1ff@pobox.com>
+# SPDX-License-Identifier: AGPL-3.0-or-later
+#
+# This file is part of Mpdpopm.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/agpl.txt>.
+
+[ "$1" = "upgrade" ] && cargo upgrade
+cargo update
diff --git a/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh b/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh
index e1e929b5..6c96a9d9 100755
--- a/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh
+++ b/pkgs/by-name/mp/mpp-lyrics/mpp-lyrics.sh
@@ -15,7 +15,7 @@ die() {
     exit 1
 }
 
-cd "$XDG_MUSIC_DIR" || die "No music dir!"
-exiftool "$(mpc --format '%file%' current)" -json | jq '.[0].Lyrics' --raw-output | less
+cd "$XDG_MUSIC_DIR/beets" || die "No music dir!"
+exiftool "$(mpc --format '%file%' current)" -json | jq '.[0] | if has("Lyrics") then .Lyrics elif has("Lyrics-xxx") then ."Lyrics-xxx" else "<No lyrics key>" end' --raw-output | less
 
 # vim: ft=sh
diff --git a/pkgs/by-name/mp/mpp/mpp.sh b/pkgs/by-name/mp/mpp/mpp.sh
index 1507d5cc..e52bfcdc 100755
--- a/pkgs/by-name/mp/mpp/mpp.sh
+++ b/pkgs/by-name/mp/mpp/mpp.sh
@@ -10,7 +10,7 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-case "$1" in
+case "${1-}" in
 "searchadd")
     shift 1
     mpp-searchadd "$@"
@@ -23,6 +23,10 @@ case "$1" in
     shift 1
     mpp-beetrm "$@"
     ;;
+"popm")
+    shift 1
+    mpdpopm "$@"
+    ;;
 *)
     mpc "$@"
     ;;
diff --git a/pkgs/by-name/mp/mpp/package.nix b/pkgs/by-name/mp/mpp/package.nix
index 0d2f6c8d..fe08ba46 100644
--- a/pkgs/by-name/mp/mpp/package.nix
+++ b/pkgs/by-name/mp/mpp/package.nix
@@ -16,6 +16,7 @@
   mpp-searchadd,
   mpp-lyrics,
   mpp-beetrm,
+  mpdpopm,
   # Build dependencies
   fd,
   zsh,
@@ -30,6 +31,7 @@
       mpp-searchadd
       mpp-lyrics
       mpp-beetrm
+      mpdpopm
     ];
   };
 
@@ -70,6 +72,8 @@
       fd "." --hidden --type file | while read -r file_path; do
         sed --in-place 's/mpc/mpp/g' "$file_path"
       done
+
+      # TODO(@bpeetz): Also change this in man-pages. <2025-05-20>
     '';
 
     installPhase = ''
@@ -79,6 +83,8 @@
   };
 in
   symlinkJoin {
-    name = "mpp-merged";
+    name = "mpp";
     paths = [script mpcShare];
+
+    inherit (script) meta;
   }
diff --git a/pkgs/by-name/ge/generate_moz_extension/.envrc b/pkgs/by-name/no/notify-run/.envrc
index 294de504..880b1809 100644
--- a/pkgs/by-name/ge/generate_moz_extension/.envrc
+++ b/pkgs/by-name/no/notify-run/.envrc
@@ -10,4 +10,13 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-use flake
+use flake || use nix
+watch_file flake.nix
+
+PATH_add ./target/debug
+PATH_add ./target/release
+PATH_add ./scripts
+
+if on_git_branch; then
+    echo && git status --short --branch
+fi
diff --git a/pkgs/by-name/ge/generate_moz_extension/.gitignore b/pkgs/by-name/no/notify-run/.gitignore
index cc03ebd7..8f29eabf 100644
--- a/pkgs/by-name/ge/generate_moz_extension/.gitignore
+++ b/pkgs/by-name/no/notify-run/.gitignore
@@ -8,6 +8,9 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
+# build
 /target
 /result
+
+# dev env
 .direnv
diff --git a/pkgs/by-name/no/notify-run/Cargo.lock b/pkgs/by-name/no/notify-run/Cargo.lock
new file mode 100644
index 00000000..1e065d25
--- /dev/null
+++ b/pkgs/by-name/no/notify-run/Cargo.lock
@@ -0,0 +1,25 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+version = 4
+
+[[package]]
+name = "anyhow"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "notify-run"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+]
diff --git a/pkgs/by-name/ya/yambar-modules/Cargo.toml b/pkgs/by-name/no/notify-run/Cargo.toml
index 45078170..c4b9a659 100644
--- a/pkgs/by-name/ya/yambar-modules/Cargo.toml
+++ b/pkgs/by-name/no/notify-run/Cargo.toml
@@ -9,11 +9,12 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
 [package]
-name = "yambar-modules"
+name = "notify-run"
+description = "An safe way to run applications that might fail"
 version = "0.1.0"
-edition = "2021"
+edition = "2024"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-sysinfo = "0.28.4"
+anyhow = "1.0.100"
diff --git a/pkgs/by-name/no/notify-run/flake.lock b/pkgs/by-name/no/notify-run/flake.lock
new file mode 100644
index 00000000..1e997998
--- /dev/null
+++ b/pkgs/by-name/no/notify-run/flake.lock
@@ -0,0 +1,27 @@
+{
+  "nodes": {
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1768661221,
+        "narHash": "sha256-MJwOjrIISfOpdI9x4C+5WFQXvHtOuj5mqLZ4TMEtk1M=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "3327b113f2ef698d380df83fbccefad7e83d7769",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixpkgs-unstable",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/pkgs/by-name/ge/generate_moz_extension/flake.lock.license b/pkgs/by-name/no/notify-run/flake.lock.license
index eae6a84c..eae6a84c 100644
--- a/pkgs/by-name/ge/generate_moz_extension/flake.lock.license
+++ b/pkgs/by-name/no/notify-run/flake.lock.license
diff --git a/pkgs/by-name/no/notify-run/flake.nix b/pkgs/by-name/no/notify-run/flake.nix
new file mode 100644
index 00000000..07be3258
--- /dev/null
+++ b/pkgs/by-name/no/notify-run/flake.nix
@@ -0,0 +1,34 @@
+# nixos-config - My current NixOS configuration
+#
+# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This file is part of my nixos-config.
+#
+# You should have received a copy of the License along with this program.
+# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  description = "An safe way to run applications, that might fail";
+
+  inputs = {
+    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+  };
+
+  outputs = {nixpkgs, ...}: let
+    system = "x86_64-linux";
+    pkgs = nixpkgs.legacyPackages."${system}";
+  in {
+    devShells."${system}".default = pkgs.mkShell {
+      packages = [
+        pkgs.cargo
+        pkgs.clippy
+        pkgs.rustc
+        pkgs.rustfmt
+
+        pkgs.cargo-edit
+      ];
+    };
+  };
+}
+# vim: ts=2
+
diff --git a/pkgs/by-name/ge/generate_moz_extension/package.nix b/pkgs/by-name/no/notify-run/package.nix
index aae5ea6c..1f9337be 100644
--- a/pkgs/by-name/ge/generate_moz_extension/package.nix
+++ b/pkgs/by-name/no/notify-run/package.nix
@@ -9,21 +9,33 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
   rustPlatform,
-  openssl,
-  pkg-config,
+  lib,
+  libnotify,
+  makeWrapper,
 }:
-rustPlatform.buildRustPackage {
-  pname = "generate_firefox_extensions";
+rustPlatform.buildRustPackage (finalAttrs: {
+  pname = "notify-run";
   version = "0.1.0";
 
-  src = ./.;
-  cargoLock = {
-    lockFile = ./Cargo.lock;
-  };
   buildInputs = [
-    openssl # needed for openssl-sys crate
+    libnotify
   ];
   nativeBuildInputs = [
-    pkg-config # needed for openssl dependency
+    makeWrapper
   ];
-}
+
+  src = ./.;
+  cargoLock = {
+    lockFile = ./Cargo.lock;
+  };
+
+  postInstall = ''
+    # NOTE: We cannot clear the path, because we need access to the programs to start. <2025-12-03>
+    wrapProgram $out/bin/notify-run \
+      --prefix PATH : ${lib.makeBinPath finalAttrs.buildInputs}
+  '';
+
+  meta = {
+    mainProgram = "notify-run";
+  };
+})
diff --git a/pkgs/by-name/no/notify-run/src/main.rs b/pkgs/by-name/no/notify-run/src/main.rs
new file mode 100644
index 00000000..a6a0165a
--- /dev/null
+++ b/pkgs/by-name/no/notify-run/src/main.rs
@@ -0,0 +1,65 @@
+// nixos-config - My current NixOS configuration
+//
+// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// This file is part of my nixos-config.
+//
+// You should have received a copy of the License along with this program.
+// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+
+use std::{env::args, path::PathBuf, process::Command};
+
+use anyhow::{Context, Result};
+
+fn main() -> Result<()> {
+    let args = args().skip(1).collect::<Vec<_>>();
+
+    let mut cmd = Command::new(&args[0]);
+    if let Some(arguments) = args.get(1) {
+        cmd.args(arguments.split(" ").collect::<Vec<_>>().as_slice());
+    }
+
+    eprintln!("Spawning {:?}", cmd);
+
+    let output = cmd
+        .output()
+        .with_context(|| format!("Failed to spawn and await output of {:?}", cmd))?;
+
+    if !output.status.success() {
+        let mut notify_send = Command::new("notify-send");
+        notify_send.args([
+            format!("Command {:?} failed", cmd).as_str(),
+            &String::from_utf8_lossy(output.stderr.as_slice()),
+        ]);
+
+        notify_send.status().with_context(|| {
+            format!(
+                "Failed to run `notify-send` to tell about failed command ({:?}).",
+                cmd
+            )
+        })?;
+    } else {
+        let name = PathBuf::from(&args[0])
+            .file_name()
+            .expect("this to be a command, and thus have a file_name")
+            .to_string_lossy()
+            .to_string();
+
+        print!("{}", append_name(&name, &output.stdout));
+        eprint!("{}", append_name(&name, &output.stderr));
+    }
+
+    Ok(())
+}
+
+fn append_name(name: &str, base: &[u8]) -> String {
+    let base = String::from_utf8_lossy(base).to_string();
+
+    let mut output = String::new();
+    for line in base.lines() {
+        output.push_str(format!("{name}> {line}\n").as_str());
+    }
+
+    output
+}
diff --git a/pkgs/by-name/ge/generate_moz_extension/update.sh b/pkgs/by-name/no/notify-run/update.sh
index c7c35d39..23d90a86 100755
--- a/pkgs/by-name/ge/generate_moz_extension/update.sh
+++ b/pkgs/by-name/no/notify-run/update.sh
@@ -12,5 +12,3 @@
 
 [ "$1" = "upgrade" ] && cargo upgrade
 cargo update
-
-# vim: ft=sh
diff --git a/pkgs/by-name/qu/qutebrowser-patched/0001-fix-standardpaths-Continue-to-work-with-xdg-while-ba.patch b/pkgs/by-name/qu/qutebrowser-patched/0001-fix-standardpaths-Continue-to-work-with-xdg-while-ba.patch
new file mode 100644
index 00000000..fa2e2482
--- /dev/null
+++ b/pkgs/by-name/qu/qutebrowser-patched/0001-fix-standardpaths-Continue-to-work-with-xdg-while-ba.patch
@@ -0,0 +1,54 @@
+From 8a0aa0e244fa565b8c55aab38cc5e84323c3b481 Mon Sep 17 00:00:00 2001
+From: Benedikt Peetz <benedikt.peetz@b-peetz.de>
+Date: Tue, 3 Jun 2025 12:43:44 +0200
+Subject: [PATCH] fix(standardpaths): Continue to work with xdg, while
+ `--basedir` is set
+
+This can be used to simulate firefox's profiles feature (i.e., completely separated
+data/runtime/cache dirs), while still keeping to the xdg basedir standard.
+---
+ qutebrowser/utils/standarddir.py | 19 +++++++++++--------
+ 1 file changed, 11 insertions(+), 8 deletions(-)
+
+diff --git a/qutebrowser/utils/standarddir.py b/qutebrowser/utils/standarddir.py
+index b82845a96..61319daed 100644
+--- a/qutebrowser/utils/standarddir.py
++++ b/qutebrowser/utils/standarddir.py
+@@ -285,12 +285,11 @@ def _from_args(
+         The overridden path, or None if there is no override.
+     """
+     basedir_suffix = {
+-        QStandardPaths.StandardLocation.ConfigLocation: 'config',
+-        QStandardPaths.StandardLocation.AppDataLocation: 'data',
+-        QStandardPaths.StandardLocation.AppLocalDataLocation: 'data',
+-        QStandardPaths.StandardLocation.CacheLocation: 'cache',
+-        QStandardPaths.StandardLocation.DownloadLocation: 'download',
+-        QStandardPaths.StandardLocation.RuntimeLocation: 'runtime',
++        QStandardPaths.StandardLocation.ConfigLocation: ('config', False),
++        QStandardPaths.StandardLocation.AppDataLocation: ('data', False),
++        QStandardPaths.StandardLocation.AppLocalDataLocation: ('data', False),
++        QStandardPaths.StandardLocation.CacheLocation: ('cache', True),
++        QStandardPaths.StandardLocation.RuntimeLocation: ('runtime', True),
+     }
+ 
+     if getattr(args, 'basedir', None) is None:
+@@ -298,10 +297,14 @@ def _from_args(
+     assert args is not None
+ 
+     try:
+-        suffix = basedir_suffix[typ]
++        (suffix, extend) = basedir_suffix[typ]
+     except KeyError:  # pragma: no cover
+         return None
+-    return os.path.abspath(os.path.join(args.basedir, suffix))
++
++    if extend:
++        return os.path.abspath(os.path.join(_writable_location(typ), os.path.basename(args.basedir)))
++    else:
++        return os.path.abspath(os.path.join(args.basedir, suffix))
+ 
+ 
+ def _create(path: str) -> None:
+-- 
+2.49.0
+
diff --git a/pkgs/by-name/qu/qutebrowser-patched/package.nix b/pkgs/by-name/qu/qutebrowser-patched/package.nix
new file mode 100644
index 00000000..1f2ea889
--- /dev/null
+++ b/pkgs/by-name/qu/qutebrowser-patched/package.nix
@@ -0,0 +1,6 @@
+{qutebrowser}:
+qutebrowser.overrideAttrs (final: prev: {
+  pname = "${prev.pname}-patched";
+
+  patches = (prev.patches or []) ++ [./0001-fix-standardpaths-Continue-to-work-with-xdg-while-ba.patch];
+})
diff --git a/pkgs/by-name/ri/river-mk-keymap/Cargo.lock b/pkgs/by-name/ri/river-mk-keymap/Cargo.lock
index d8328332..ef1ffbf7 100644
--- a/pkgs/by-name/ri/river-mk-keymap/Cargo.lock
+++ b/pkgs/by-name/ri/river-mk-keymap/Cargo.lock
@@ -1,3 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
 # nixos-config - My current NixOS configuration
 #
 # Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
@@ -7,16 +9,29 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
 version = 4
 
 [[package]]
+name = "ab_glyph"
+version = "0.2.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2"
+dependencies = [
+ "ab_glyph_rasterizer",
+ "owned_ttf_parser",
+]
+
+[[package]]
+name = "ab_glyph_rasterizer"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
+
+[[package]]
 name = "anstream"
-version = "0.6.18"
+version = "0.6.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -29,50 +44,90 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.10"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
 dependencies = [
  "anstyle",
- "once_cell",
+ "once_cell_polyfill",
  "windows-sys",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.98"
+version = "1.0.100"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cc"
+version = "1.2.53"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
 
 [[package]]
 name = "clap"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -80,9 +135,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
 dependencies = [
  "anstream",
  "anstyle",
@@ -92,9 +147,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.32"
+version = "4.5.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -104,15 +159,211 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.7.4"
+version = "0.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
+
+[[package]]
+name = "core-graphics"
+version = "0.23.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "core-graphics-types",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "libc",
+]
+
+[[package]]
+name = "core-text"
+version = "20.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5"
+dependencies = [
+ "core-foundation",
+ "core-graphics",
+ "foreign-types",
+ "libc",
+]
+
+[[package]]
+name = "dirs"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
+dependencies = [
+ "dirs-sys",
+]
+
+[[package]]
+name = "dirs-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
+dependencies = [
+ "libc",
+ "option-ext",
+ "redox_users",
+ "windows-sys",
+]
+
+[[package]]
+name = "dlib"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "downcast-rs"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
+
+[[package]]
+name = "dwrote"
+version = "0.11.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b35532432acc8b19ceed096e35dfa088d3ea037fe4f3c085f1f97f33b4d02"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "winapi",
+ "wio",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
+
+[[package]]
+name = "float-ord"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d"
+
+[[package]]
+name = "font-kit"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2c7e611d49285d4c4b2e1727b72cf05353558885cc5252f93707b845dfcaf3d3"
+dependencies = [
+ "bitflags 2.10.0",
+ "byteorder",
+ "core-foundation",
+ "core-graphics",
+ "core-text",
+ "dirs",
+ "dwrote",
+ "float-ord",
+ "freetype-sys",
+ "lazy_static",
+ "libc",
+ "log",
+ "pathfinder_geometry",
+ "pathfinder_simd",
+ "walkdir",
+ "winapi",
+ "yeslogic-fontconfig-sys",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
+dependencies = [
+ "foreign-types-macros",
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+
+[[package]]
+name = "freetype-sys"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134"
+dependencies = [
+ "cc",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
 
 [[package]]
 name = "heck"
@@ -122,31 +373,84 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "is_terminal_polyfill"
-version = "1.70.1"
+version = "1.70.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
 
 [[package]]
 name = "itoa"
-version = "1.0.15"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
 
 [[package]]
 name = "keymaps"
-version = "1.0.0"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6cec33e805ecc09c4e4f91ca26e536978ad1ae28f2e1dc02fadafeec6d2f8504"
+checksum = "ea59e8e461942cf1d6a7ad938848d6fd2e40eb43799c21192c09226ecc86710f"
 dependencies = [
  "serde",
  "thiserror",
 ]
 
 [[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.180"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
+
+[[package]]
+name = "libloading"
+version = "0.8.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
+dependencies = [
+ "cfg-if",
+ "windows-link",
+]
+
+[[package]]
+name = "libredox"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
+dependencies = [
+ "bitflags 2.10.0",
+ "libc",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
+
+[[package]]
+name = "log"
+version = "0.4.29"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
+
+[[package]]
 name = "memchr"
-version = "2.7.4"
+version = "2.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
+
+[[package]]
+name = "memmap2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "744133e4a0e0a658e1374cf3bf8e415c4052a15a111acd372764c55b4177d490"
+dependencies = [
+ "libc",
+]
 
 [[package]]
 name = "once_cell"
@@ -155,54 +459,171 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
+name = "option-ext"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "owned_ttf_parser"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b"
+dependencies = [
+ "ttf-parser",
+]
+
+[[package]]
+name = "pathfinder_geometry"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3"
+dependencies = [
+ "log",
+ "pathfinder_simd",
+]
+
+[[package]]
+name = "pathfinder_simd"
+version = "0.5.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf9027960355bf3afff9841918474a81a5f972ac6d226d518060bba758b5ad57"
+dependencies = [
+ "rustc_version",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
+
+[[package]]
 name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
+name = "quick-xml"
+version = "0.38.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
+name = "redox_users"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
 name = "river-mk-keymap"
 version = "0.1.0"
 dependencies = [
+ "ab_glyph",
  "anyhow",
  "clap",
+ "font-kit",
  "keymaps",
+ "memmap2",
+ "rustix",
  "serde",
  "serde_json",
+ "shlex",
+ "thiserror",
+ "vte",
+ "wayland-client",
+ "wayland-protocols-wlr",
+ "wayland-scanner",
 ]
 
 [[package]]
-name = "ryu"
-version = "1.0.20"
+name = "rustc_version"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
+dependencies = [
+ "bitflags 2.10.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
 
 [[package]]
 name = "serde"
-version = "1.0.219"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.219"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -211,17 +632,30 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.140"
+version = "1.0.149"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
 dependencies = [
  "itoa",
  "memchr",
- "ryu",
  "serde",
+ "serde_core",
+ "zmij",
 ]
 
 [[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "smallvec"
+version = "1.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
+
+[[package]]
 name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -229,9 +663,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -240,18 +674,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "2.0.12"
+version = "2.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "2.0.12"
+version = "2.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -259,10 +693,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "ttf-parser"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
+
+[[package]]
 name = "unicode-ident"
-version = "1.0.18"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
 
 [[package]]
 name = "utf8parse"
@@ -271,74 +711,169 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
-name = "windows-sys"
-version = "0.59.0"
+name = "vte"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"
 dependencies = [
- "windows-targets",
+ "arrayvec",
+ "memchr",
 ]
 
 [[package]]
-name = "windows-targets"
-version = "0.52.6"
+name = "walkdir"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "same-file",
+ "winapi-util",
 ]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.52.6"
+name = "wasi"
+version = "0.11.1+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.52.6"
+name = "wayland-backend"
+version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9"
+dependencies = [
+ "cc",
+ "downcast-rs",
+ "rustix",
+ "smallvec",
+ "wayland-sys",
+]
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.52.6"
+name = "wayland-client"
+version = "0.31.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec"
+dependencies = [
+ "bitflags 2.10.0",
+ "rustix",
+ "wayland-backend",
+ "wayland-scanner",
+]
 
 [[package]]
-name = "windows_i686_gnullvm"
-version = "0.52.6"
+name = "wayland-protocols"
+version = "0.32.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3"
+dependencies = [
+ "bitflags 2.10.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-scanner",
+]
 
 [[package]]
-name = "windows_i686_msvc"
-version = "0.52.6"
+name = "wayland-protocols-wlr"
+version = "0.3.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3"
+dependencies = [
+ "bitflags 2.10.0",
+ "wayland-backend",
+ "wayland-client",
+ "wayland-protocols",
+ "wayland-scanner",
+]
 
 [[package]]
-name = "windows_x86_64_gnu"
-version = "0.52.6"
+name = "wayland-scanner"
+version = "0.31.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3"
+dependencies = [
+ "proc-macro2",
+ "quick-xml",
+ "quote",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.31.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd"
+dependencies = [
+ "pkg-config",
+]
 
 [[package]]
-name = "windows_x86_64_gnullvm"
-version = "0.52.6"
+name = "winapi"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
 
 [[package]]
-name = "windows_x86_64_msvc"
-version = "0.52.6"
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "wio"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "yeslogic-fontconfig-sys"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd"
+dependencies = [
+ "dlib",
+ "once_cell",
+ "pkg-config",
+]
+
+[[package]]
+name = "zmij"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2"
diff --git a/pkgs/by-name/ri/river-mk-keymap/Cargo.toml b/pkgs/by-name/ri/river-mk-keymap/Cargo.toml
index 5e171508..31247cd7 100644
--- a/pkgs/by-name/ri/river-mk-keymap/Cargo.toml
+++ b/pkgs/by-name/ri/river-mk-keymap/Cargo.toml
@@ -16,11 +16,21 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-anyhow = "1.0.98"
-clap = { version = "4.5.37", features = ["derive"] }
-keymaps = { version = "1.0.0", features = ["serde", "mouse-keys"] }
-serde = { version = "1.0.219", features = ["derive"] }
-serde_json = "1.0.140"
+ab_glyph = "0.2.32"
+anyhow = "1.0.100"
+clap = { version = "4.5.54", features = ["derive"] }
+font-kit = "0.14.3"
+keymaps = { version = "1.2.0", features = ["serde", "mouse-keys", "modifier-keys"] }
+memmap2 = "0.9.9"
+rustix = { version = "1.1.3", features = ["fs", "shm"] }
+serde = { version = "1.0.228", features = ["derive"] }
+serde_json = "1.0.149"
+shlex = "1.3.0"
+thiserror = "2.0.17"
+vte = "0.15.0"
+wayland-client = {version = "0.31.12", default-features = false}
+wayland-protocols-wlr = { version = "0.3.10", features = ["client"] }
+wayland-scanner = {version = "0.31.8", default-features = false}
 
 [profile.release]
 lto = true
diff --git a/pkgs/by-name/ri/river-mk-keymap/TODO b/pkgs/by-name/ri/river-mk-keymap/TODO
deleted file mode 100644
index be77953e..00000000
--- a/pkgs/by-name/ri/river-mk-keymap/TODO
+++ /dev/null
@@ -1 +0,0 @@
-Look at https://github.com/stefur/flow for river wayland inclusion
diff --git a/pkgs/by-name/ri/river-mk-keymap/TODO.license b/pkgs/by-name/ri/river-mk-keymap/TODO.license
deleted file mode 100644
index eae6a84c..00000000
--- a/pkgs/by-name/ri/river-mk-keymap/TODO.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/pkgs/by-name/ri/river-mk-keymap/contrib/example.json b/pkgs/by-name/ri/river-mk-keymap/contrib/example.json
index c8673f9a..bddd61c0 100644
--- a/pkgs/by-name/ri/river-mk-keymap/contrib/example.json
+++ b/pkgs/by-name/ri/river-mk-keymap/contrib/example.json
@@ -1,5 +1,8 @@
 {
-    "<M-a>": {
-        "command": ["focus-view", "next"]
+    "Kbad": {
+        "command": ["spawn", "/nix/store/1xfyw9c5ala73y8sayrsf98vcrr3jrww-libnotify-0.8.6/bin/notify-send hi"]
+    },
+    "Kbae": {
+        "command": ["e"]
     }
 }
diff --git a/pkgs/by-name/ri/river-mk-keymap/contrib/init.json b/pkgs/by-name/ri/river-mk-keymap/contrib/init.json
new file mode 100644
index 00000000..a5f24307
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/contrib/init.json
@@ -0,0 +1,261 @@
+{
+  "<Alt+Ctrl+Super+Shift-Z>": [
+    "spawn",
+    "/nix/store/h71ca2rxlnlcyv4604ih2b2gla5ly27d-qmk-unicode-type-1.0.0/bin/qmk-unicode-type 106 65377"
+  ],
+  "<MEDIA_LOWERVOLUME>": {
+    "allow_locked": true,
+    "command": [
+      "spawn",
+      "/nix/store/7h9w2sycqj3i2lp61nibgv7qhvwy3pi9-wireplumber-0.5.10/bin/wpctl set-volume @DEFAULT_SINK@ 5%-"
+    ]
+  },
+  "<MEDIA_MUTEVOLUME>": {
+    "allow_locked": true,
+    "command": [
+      "spawn",
+      "/nix/store/08bgv5x7gfhkczf0lgrpim1rw51jlxvn-mpp/bin/mpp toggle"
+    ]
+  },
+  "<MEDIA_RAISEVOLUME>": {
+    "allow_locked": true,
+    "command": [
+      "spawn",
+      "/nix/store/7h9w2sycqj3i2lp61nibgv7qhvwy3pi9-wireplumber-0.5.10/bin/wpctl set-volume @DEFAULT_SINK@ 5%+"
+    ]
+  },
+  "<LEFT_SUPER>": {
+    "c": {
+      "<ENTER>": [
+        "zoom"
+      ],
+      " ": [
+        "toggle-float"
+      ],
+      "c": [
+        "close"
+      ],
+      "f": [
+        "toggle-fullscreen"
+      ],
+      "n": [
+        "swap",
+        "previous"
+      ],
+      "o": [
+        "send-to-output",
+        "next"
+      ],
+      "t": [
+        "swap",
+        "next"
+      ]
+    },
+    "f": {
+      "0": [
+        "set-focused-tags",
+        "4294967295"
+      ],
+      "1": [
+        "set-focused-tags",
+        "1"
+      ],
+      "2": [
+        "set-focused-tags",
+        "2"
+      ],
+      "3": [
+        "set-focused-tags",
+        "4"
+      ],
+      "4": [
+        "set-focused-tags",
+        "8"
+      ],
+      "5": [
+        "set-focused-tags",
+        "16"
+      ],
+      "6": [
+        "set-focused-tags",
+        "32"
+      ],
+      "7": [
+        "set-focused-tags",
+        "64"
+      ],
+      "8": [
+        "set-focused-tags",
+        "128"
+      ],
+      "9": [
+        "set-focused-tags",
+        "256"
+      ],
+      "<Ctrl-n>": [
+        "focus-output",
+        "previous"
+      ],
+      "<Ctrl-t>": [
+        "focus-output",
+        "next"
+      ],
+      "n": [
+        "focus-view",
+        "previous"
+      ],
+      "p": [
+        "focus-previous-tags"
+      ],
+      "t": [
+        "focus-view",
+        "next"
+      ]
+    },
+    "m": {
+      "l": {
+        "command": [
+        "spawn",
+        "/nix/store/7h9w2sycqj3i2lp61nibgv7qhvwy3pi9-wireplumber-0.5.10/bin/wpctl set-volume @DEFAULT_SINK@ 5%-"
+      ],
+        "description": "wpctl set-volume @DEFAULT_SINK@ 5%-"
+    },
+      "m": [
+        "spawn",
+        "/nix/store/08bgv5x7gfhkczf0lgrpim1rw51jlxvn-mpp/bin/mpp toggle"
+      ],
+      "r": [
+        "spawn",
+        "/nix/store/7h9w2sycqj3i2lp61nibgv7qhvwy3pi9-wireplumber-0.5.10/bin/wpctl set-volume @DEFAULT_SINK@ 5%+"
+      ]
+    },
+    "r": {
+      "a": [
+        "spawn",
+        "/nix/store/h601phmb09d9dwwziwsim6m0r31qajr3-alacritty-0.15.1/bin/alacritty"
+      ],
+      "b": [
+        "spawn",
+        "/nix/store/k8gfhk1lglwr8k6477ygkr9hh037a4kw-tskm-0.1.0/bin/tskm open select"
+      ],
+      "k": [
+        "spawn",
+        "/nix/store/xpinf75gxhl8aglw2z7631k89iiml7rz-keepassxc-2.7.10/bin/keepassxc"
+      ],
+      "p": [
+        "spawn",
+        "/nix/store/skgvjhmqp3jbmaw70xlz86a66lg13395-screenshot_persistent/bin/screenshot_persistent"
+      ],
+      "s": [
+        "spawn",
+        "/nix/store/zvzr8cj57jhxyrzjym2rv3w95w7zw901-signal-desktop-7.56.1/bin/signal-desktop"
+      ]
+    },
+    "v": {
+      "0": [
+        "set-view-tags",
+        "4294967295"
+      ],
+      "1": [
+        "set-view-tags",
+        "1"
+      ],
+      "2": [
+        "set-view-tags",
+        "2"
+      ],
+      "3": [
+        "set-view-tags",
+        "4"
+      ],
+      "4": [
+        "set-view-tags",
+        "8"
+      ],
+      "5": [
+        "set-view-tags",
+        "16"
+      ],
+      "6": [
+        "set-view-tags",
+        "32"
+      ],
+      "7": [
+        "set-view-tags",
+        "64"
+      ],
+      "8": [
+        "set-view-tags",
+        "128"
+      ],
+      "9": [
+        "set-view-tags",
+        "256"
+      ],
+      "a": {
+        "1": [
+          "toggle-view-tags",
+          "1"
+        ],
+        "2": [
+          "toggle-view-tags",
+          "2"
+        ],
+        "3": [
+          "toggle-view-tags",
+          "4"
+        ],
+        "4": [
+          "toggle-view-tags",
+          "8"
+        ],
+        "5": [
+          "toggle-view-tags",
+          "16"
+        ],
+        "6": [
+          "toggle-view-tags",
+          "32"
+        ],
+        "7": [
+          "toggle-view-tags",
+          "64"
+        ],
+        "8": [
+          "toggle-view-tags",
+          "128"
+        ],
+        "9": [
+          "toggle-view-tags",
+          "256"
+        ]
+      },
+      "p": [
+        "send-to-previous-tags"
+      ]
+    },
+    "x": {
+      "l": [
+        "spawn",
+        "/nix/store/4gp8yj8cz3d78hn01firv7dlqf4ap1fj-lock/bin/lock"
+      ],
+      "q": [
+        "exit"
+      ]
+    }
+  },
+  "<Super-<MOUSE_LEFT>>": [
+    "move-view"
+  ],
+  "<Super-<MOUSE_RIGHT>>": [
+    "resize-view"
+  ],
+  "<Super-L>": [
+    "spawn",
+    "/nix/store/4gp8yj8cz3d78hn01firv7dlqf4ap1fj-lock/bin/lock"
+  ],
+  "<PRINTSCREEN>": [
+    "spawn",
+    "/nix/store/skgvjhmqp3jbmaw70xlz86a66lg13395-screenshot_persistent/bin/screenshot_persistent"
+  ]
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/flake.lock b/pkgs/by-name/ri/river-mk-keymap/flake.lock
index 07eb6b21..1e997998 100644
--- a/pkgs/by-name/ri/river-mk-keymap/flake.lock
+++ b/pkgs/by-name/ri/river-mk-keymap/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1745377448,
-        "narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
+        "lastModified": 1768661221,
+        "narHash": "sha256-MJwOjrIISfOpdI9x4C+5WFQXvHtOuj5mqLZ4TMEtk1M=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
+        "rev": "3327b113f2ef698d380df83fbccefad7e83d7769",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/ri/river-mk-keymap/flake.nix b/pkgs/by-name/ri/river-mk-keymap/flake.nix
index e15e99fa..b338e4c9 100644
--- a/pkgs/by-name/ri/river-mk-keymap/flake.nix
+++ b/pkgs/by-name/ri/river-mk-keymap/flake.nix
@@ -17,15 +17,27 @@
   outputs = {nixpkgs, ...}: let
     system = "x86_64-linux";
     pkgs = nixpkgs.legacyPackages."${system}";
+
+    nativeBuildInputs = [
+      pkgs.pkg-config
+    ];
+
+    buildInputs = [
+      pkgs.wayland
+      pkgs.libxkbcommon
+      pkgs.fontconfig
+    ];
   in {
     devShells."${system}".default = pkgs.mkShell {
-      packages = with pkgs; [
-        cargo
-        clippy
-        rustc
-        rustfmt
+      inherit nativeBuildInputs buildInputs;
+
+      packages = [
+        pkgs.cargo
+        pkgs.clippy
+        pkgs.rustc
+        pkgs.rustfmt
 
-        cargo-edit
+        pkgs.cargo-edit
       ];
     };
   };
diff --git a/pkgs/by-name/ri/river-mk-keymap/package.nix b/pkgs/by-name/ri/river-mk-keymap/package.nix
index 7d6d4f3a..bb3dc285 100644
--- a/pkgs/by-name/ri/river-mk-keymap/package.nix
+++ b/pkgs/by-name/ri/river-mk-keymap/package.nix
@@ -7,7 +7,13 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{rustPlatform}:
+{
+  rustPlatform,
+  pkg-config,
+  wayland,
+  libxkbcommon,
+  fontconfig,
+}:
 rustPlatform.buildRustPackage {
   pname = "river-mk-keymap";
   version = "0.1.0";
@@ -17,6 +23,16 @@ rustPlatform.buildRustPackage {
     lockFile = ./Cargo.lock;
   };
 
+  nativeBuildInputs = [
+    pkg-config
+  ];
+
+  buildInputs = [
+    wayland
+    libxkbcommon
+    fontconfig
+  ];
+
   meta = {
     mainProgram = "river-mk-keymap";
   };
diff --git a/pkgs/by-name/ri/river-mk-keymap/resources/river-control-unstable-v1.xml b/pkgs/by-name/ri/river-mk-keymap/resources/river-control-unstable-v1.xml
new file mode 100644
index 00000000..aa5fc4dc
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/resources/river-control-unstable-v1.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="river_control_unstable_v1">
+  <copyright>
+    Copyright 2020 The River Developers
+
+    Permission to use, copy, modify, and/or distribute this software for any
+    purpose with or without fee is hereby granted, provided that the above
+    copyright notice and this permission notice appear in all copies.
+
+    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  </copyright>
+
+  <interface name="zriver_control_v1" version="1">
+    <description summary="run compositor commands">
+      This interface allows clients to run compositor commands and receive a
+      success/failure response with output or a failure message respectively.
+
+      Each command is built up in a series of add_argument requests and
+      executed with a run_command request. The first argument is the command
+      to be run.
+
+      A complete list of commands should be made available in the man page of
+      the compositor.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the river_control object">
+        This request indicates that the client will not use the
+        river_control object any more. Objects that have been created
+        through this instance are not affected.
+      </description>
+    </request>
+
+    <request name="add_argument">
+      <description summary="add an argument to the current command">
+        Arguments are stored by the server in the order they were sent until
+        the run_command request is made.
+      </description>
+      <arg name="argument" type="string" summary="the argument to add"/>
+    </request>
+
+    <request name="run_command">
+      <description summary="run the current command">
+        Execute the command built up using the add_argument request for the
+        given seat.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"/>
+      <arg name="callback" type="new_id" interface="zriver_command_callback_v1"
+        summary="callback object"/>
+    </request>
+  </interface>
+
+  <interface name="zriver_command_callback_v1" version="1">
+    <description summary="callback object">
+      This object is created by the run_command request. Exactly one of the
+      success or failure events will be sent. This object will be destroyed
+      by the compositor after one of the events is sent.
+    </description>
+
+    <event name="success" type="destructor">
+      <description summary="command successful">
+        Sent when the command has been successfully received and executed by
+        the compositor. Some commands may produce output, in which case the
+        output argument will be a non-empty string.
+      </description>
+      <arg name="output" type="string" summary="the output of the command"/>
+    </event>
+
+    <event name="failure" type="destructor">
+      <description summary="command failed">
+        Sent when the command could not be carried out. This could be due to
+        sending a non-existent command, no command, not enough arguments, too
+        many arguments, invalid arguments, etc.
+      </description>
+      <arg name="failure_message" type="string"
+        summary="a message explaining why failure occurred"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/pkgs/by-name/ri/river-mk-keymap/resources/river-status-unstable-v1.xml b/pkgs/by-name/ri/river-mk-keymap/resources/river-status-unstable-v1.xml
new file mode 100644
index 00000000..e9629dde
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/resources/river-status-unstable-v1.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="river_status_unstable_v1">
+  <copyright>
+    Copyright 2020 The River Developers
+
+    Permission to use, copy, modify, and/or distribute this software for any
+    purpose with or without fee is hereby granted, provided that the above
+    copyright notice and this permission notice appear in all copies.
+
+    THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+    WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+    MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+    ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+    ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+  </copyright>
+
+  <interface name="zriver_status_manager_v1" version="4">
+    <description summary="manage river status objects">
+      A global factory for objects that receive status information specific
+      to river. It could be used to implement, for example, a status bar.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the river_status_manager object">
+        This request indicates that the client will not use the
+        river_status_manager object any more. Objects that have been created
+        through this instance are not affected.
+      </description>
+    </request>
+
+    <request name="get_river_output_status">
+      <description summary="create an output status object">
+        This creates a new river_output_status object for the given wl_output.
+      </description>
+      <arg name="id" type="new_id" interface="zriver_output_status_v1"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
+
+    <request name="get_river_seat_status">
+      <description summary="create a seat status object">
+        This creates a new river_seat_status object for the given wl_seat.
+      </description>
+      <arg name="id" type="new_id" interface="zriver_seat_status_v1"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+  </interface>
+
+  <interface name="zriver_output_status_v1" version="4">
+    <description summary="track output tags and focus">
+      This interface allows clients to receive information about the current
+      windowing state of an output.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the river_output_status object">
+        This request indicates that the client will not use the
+        river_output_status object any more.
+      </description>
+    </request>
+
+    <event name="focused_tags">
+      <description summary="focused tags of the output">
+        Sent once binding the interface and again whenever the tag focus of
+        the output changes.
+      </description>
+      <arg name="tags" type="uint" summary="32-bit bitfield"/>
+    </event>
+
+    <event name="view_tags">
+      <description summary="tag state of an output's views">
+        Sent once on binding the interface and again whenever the tag state
+        of the output changes.
+      </description>
+      <arg name="tags" type="array" summary="array of 32-bit bitfields"/>
+    </event>
+
+    <event name="urgent_tags" since="2">
+      <description summary="tags of the output with an urgent view">
+        Sent once on binding the interface and again whenever the set of
+        tags with at least one urgent view changes.
+      </description>
+      <arg name="tags" type="uint" summary="32-bit bitfield"/>
+    </event>
+
+    <event name="layout_name" since="4">
+      <description summary="name of the layout">
+        Sent once on binding the interface should a layout name exist and again
+        whenever the name changes.
+      </description>
+      <arg name="name" type="string" summary="layout name"/>
+    </event>
+
+    <event name="layout_name_clear" since="4">
+      <description summary="name of the layout">
+        Sent when the current layout name has been removed without a new one
+        being set, for example when the active layout generator disconnects.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="zriver_seat_status_v1" version="3">
+    <description summary="track seat focus">
+      This interface allows clients to receive information about the current
+      focus of a seat. Note that (un)focused_output events will only be sent
+      if the client has bound the relevant wl_output globals.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the river_seat_status object">
+        This request indicates that the client will not use the
+        river_seat_status object any more.
+      </description>
+    </request>
+
+    <event name="focused_output">
+      <description summary="the seat focused an output">
+        Sent on binding the interface and again whenever an output gains focus.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <event name="unfocused_output">
+      <description summary="the seat unfocused an output">
+        Sent whenever an output loses focus.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <event name="focused_view">
+      <description summary="information on the focused view">
+        Sent once on binding the interface and again whenever the focused
+        view or a property thereof changes. The title may be an empty string
+        if no view is focused or the focused view did not set a title.
+      </description>
+      <arg name="title" type="string" summary="title of the focused view"/>
+    </event>
+
+    <event name="mode" since="3">
+      <description summary="the active mode changed">
+        Sent once on binding the interface and again whenever a new mode
+        is entered (e.g. with riverctl enter-mode foobar).
+      </description>
+      <arg name="name" type="string" summary="name of the mode"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/cli.rs b/pkgs/by-name/ri/river-mk-keymap/src/cli.rs
index e3c49310..ad872cc9 100644
--- a/pkgs/by-name/ri/river-mk-keymap/src/cli.rs
+++ b/pkgs/by-name/ri/river-mk-keymap/src/cli.rs
@@ -16,6 +16,20 @@ use clap::Parser;
 #[command(author, version, about, long_about = None)]
 /// A tool to manage your key mappings for the river window manager
 pub(super) struct Args {
-    /// Path to mappings JSON file
-    pub path: PathBuf,
+    #[command(subcommand)]
+    pub command: SubCommand,
+
+    #[arg(long, short)]
+    /// Path to mapping config JSON file
+    pub keymap: PathBuf,
+}
+
+#[derive(clap::Subcommand, Clone, Debug)]
+pub(super) enum SubCommand {
+    Init {
+        #[arg(short, long, default_value_t = false)]
+        /// Only show what would be done, don't actually perform the init.
+        dry_run: bool,
+    },
+    ShowHelp {},
 }
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/key_map/commands.rs b/pkgs/by-name/ri/river-mk-keymap/src/key_map/commands.rs
index e948ccfe..8372b61d 100644
--- a/pkgs/by-name/ri/river-mk-keymap/src/key_map/commands.rs
+++ b/pkgs/by-name/ri/river-mk-keymap/src/key_map/commands.rs
@@ -8,112 +8,306 @@
 // You should have received a copy of the License along with this program.
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-use std::process::Command;
+use std::{env::current_exe, path::Path, process::Command};
 
-use keymaps::key_repr::{KeyValue, MediaKeyCode, MouseKeyValue};
+use anyhow::{bail, Result};
+use keymaps::key_repr::{Key, KeyValue, Keys, MediaKeyCode, ModifierKeyCode, MouseKeyValue};
+use rustix::path::Arg;
 
-use super::{KeyMap, MapMode};
+use super::KeyMap;
 
 impl KeyMap {
-    #[must_use]
-    pub fn to_commands(self) -> Vec<Command> {
-        self.0
-            .iter()
-            .flat_map(|(key, value)| {
-                let key = key.last().expect("Will exist");
-                let mods = {
-                    let modifiers = key.modifiers();
-                    let mut output = vec![];
-
-                    if modifiers.alt() {
-                        output.push("Alt");
-                    }
-                    if modifiers.ctrl() {
-                        output.push("Control");
-                    }
-                    if modifiers.meta() {
-                        output.push("Super");
-                    }
-                    if modifiers.shift() {
-                        output.push("Shift");
-                    }
-                    if output.is_empty() {
-                        "None".to_owned()
-                    } else {
-                        output.join("+")
-                    }
-                };
-                let key_value = match key.value() {
-                    KeyValue::Backspace => "BackSpace".to_owned(),
-                    KeyValue::Enter => "Enter".to_owned(),
-                    KeyValue::Left => "Left".to_owned(),
-                    KeyValue::Right => "Right".to_owned(),
-                    KeyValue::Up => "Up".to_owned(),
-                    KeyValue::Down => "Down".to_owned(),
-                    KeyValue::Home => "Home".to_owned(),
-                    KeyValue::End => "End".to_owned(),
-                    KeyValue::PageUp => "Page_Up".to_owned(),
-                    KeyValue::PageDown => "Page_Down".to_owned(),
-                    KeyValue::Tab => "Tab".to_owned(),
-                    KeyValue::BackTab => "BackTab".to_owned(),
-                    KeyValue::Delete => "Delete".to_owned(),
-                    KeyValue::Insert => "Insert".to_owned(),
-                    KeyValue::F(num) => format!("F{num}"),
-                    KeyValue::Char(a) => a.to_string(),
-                    KeyValue::Null => "Null".to_owned(),
-                    KeyValue::Esc => "Esc".to_owned(),
-                    KeyValue::CapsLock => "CapsLock".to_owned(),
-                    KeyValue::ScrollLock => "ScrollLock".to_owned(),
-                    KeyValue::NumLock => "NumLock".to_owned(),
-                    KeyValue::PrintScreen => "Print".to_owned(),
-                    KeyValue::Pause => "Pause".to_owned(),
-                    KeyValue::Menu => "Menu".to_owned(),
-                    KeyValue::KeypadBegin => "KeypadBegin".to_owned(),
-                    KeyValue::Media(media_key_code) => match media_key_code {
-                        MediaKeyCode::Play => "XF86AudioPlay".to_owned(),
-                        MediaKeyCode::Pause => "XF86AudioPause".to_owned(),
-                        MediaKeyCode::PlayPause => "XF86AudioPlayPause".to_owned(),
-                        MediaKeyCode::Reverse => "XF86AudioReverse".to_owned(),
-                        MediaKeyCode::Stop => "XF86AudioStop".to_owned(),
-                        MediaKeyCode::FastForward => "XF86AudioFastForward".to_owned(),
-                        MediaKeyCode::Rewind => "XF86AudioRewind".to_owned(),
-                        MediaKeyCode::TrackNext => "XF86AudioTrackNext".to_owned(),
-                        MediaKeyCode::TrackPrevious => "XF86AudioTrackPrevious".to_owned(),
-                        MediaKeyCode::Record => "XF86AudioRecord".to_owned(),
-                        MediaKeyCode::LowerVolume => "XF86AudioLowerVolume".to_owned(),
-                        MediaKeyCode::RaiseVolume => "XF86AudioRaiseVolume".to_owned(),
-                        MediaKeyCode::MuteVolume => "XF86AudioMuteVolume".to_owned(),
-                    },
-                    KeyValue::MouseKey(mouse_key_value) => match mouse_key_value {
-                        MouseKeyValue::Left => "BTN_LEFT".to_owned(),
-                        MouseKeyValue::Right => "BTN_RIGHT".to_owned(),
-                        MouseKeyValue::Middle => "BTN_MIDDLE".to_owned(),
-                    },
-                    _ => todo!(),
+    /// # Errors
+    /// If impossible requests are made.
+    ///
+    /// # Panics
+    /// If internal assertions fail.
+    #[allow(clippy::too_many_lines)]
+    pub fn to_commands(self, keymap_path: &Path) -> Result<Vec<Command>> {
+        self.0.iter().try_for_each(|(keys, value)| {
+            let (prefix, last) = keys.split_at(keys.len() - 1);
+            let prefix = prefix.to_owned();
+
+            if value.allow_locked && !prefix.is_empty() {
+                bail!(
+                    "Only single key mappings can be used \
+                        in locked mode, but '{}' contains multiple ('{}').",
+                    Keys::from(keys),
+                    Keys::from(prefix),
+                )
+            }
+
+            if !prefix.is_empty()
+                && [
+                    "<ESC>".parse().expect("hardcoded"),
+                    "<BACKSPACE>".parse().expect("hardcoded"),
+                ]
+                .contains(&last[0])
+            {
+                bail!(
+                    "You cannot use <ESC> or <BACKSPACE> as the final part of a \
+                        prefixed mapping, as that is used to return \
+                        to 'normal' or the upper mode; found in '{}'",
+                    Keys::from(keys),
+                )
+            }
+
+            Ok(())
+        })?;
+
+        let mut output: Vec<_> = self
+            .0
+            .into_iter()
+            .flat_map(|(keys, value)| {
+                let (prefix, mapping) = keys.split_at(keys.len() - 1);
+
+                let (final_mode, mut base): (Option<String>, _) =
+                    prefix
+                        .iter()
+                        .fold((None, vec![]), |(acc_mode, mut acc_vec), key| {
+                            // Declare intermediate modes for each key.
+                            let mode_name: String = {
+                                let base = key.to_string_repr();
+
+                                if let Some(result) = &acc_mode {
+                                    result.to_owned() + base.as_str()
+                                } else {
+                                    base
+                                }
+                            };
+
+                            let mut riverctl = Command::new("riverctl");
+                            riverctl.args(["declare-mode", mode_name.as_str()]);
+
+                            let mut output = vec![riverctl];
+
+                            // Provide keymaps for entering and leaving the mode
+                            if let Some(acc_mode) = acc_mode.clone() {
+                                output.extend(key_to_command(
+                                    key.to_owned(),
+                                    &["enter-mode".to_owned(), mode_name.clone()],
+                                    &acc_mode,
+                                    false,
+                                ));
+                            } else {
+                                // Also spawn the help display if we start from the “normal” mode.
+                                output.extend(key_to_command(
+                                    key.to_owned(),
+                                    &[
+                                        "spawn".to_owned(),
+                                        format!(
+                                            "{} && sleep 1 && {}",
+                                            shlex::try_join([
+                                                "riverctl",
+                                                "enter-mode",
+                                                mode_name.as_str()
+                                            ])
+                                            .expect("Should work"),
+                                            shlex::try_join([
+                                                current_exe()
+                                                    .expect("Should have a current exe")
+                                                    .as_os_str()
+                                                    .as_str()
+                                                    .expect("Should be valid utf8"),
+                                                "--keymap",
+                                                keymap_path.to_str().expect("Should be valid utf8"),
+                                                "show-help",
+                                            ])
+                                            .expect("Should work"),
+                                        ),
+                                    ],
+                                    "normal",
+                                    false,
+                                ));
+                            }
+
+                            // Provide a mapping for going up a mode
+                            output.extend(key_to_command(
+                                "<BACKSPACE>".parse().expect("Hardcoded"),
+                                &[
+                                    "enter-mode".to_owned(),
+                                    acc_mode.unwrap_or("normal".to_owned()),
+                                ],
+                                &mode_name,
+                                false,
+                            ));
+
+                            // Another one for going back to normal.
+                            output.extend(key_to_command(
+                                "<ESC>".parse().expect("Hardcoded"),
+                                &["enter-mode".to_owned(), "normal".to_owned()],
+                                &mode_name,
+                                false,
+                            ));
+
+                            acc_vec.extend(output);
+
+                            (Some(mode_name), acc_vec)
+                        });
+
+                let command = if value.once {
+                    vec![
+                        "spawn".to_owned(),
+                        format!(
+                            "riverctl {} && {}",
+                            shlex::try_join(value.command.iter().map(String::as_str))
+                                .expect("Should work"),
+                            shlex::try_join(["riverctl", "enter-mode", "normal"])
+                                .expect("Should work"),
+                        ),
+                    ]
+                } else {
+                    value.command
                 };
+                base.extend(key_to_command(
+                    mapping[0],
+                    &command,
+                    final_mode.as_ref().map_or("normal", |v| v.as_str()),
+                    value.allow_locked,
+                ));
 
-                value
-                    .modes
-                    .iter()
-                    .map(|mode| {
-                        let mut riverctl = Command::new("riverctl");
-                        riverctl.args([value.map_mode.as_command(), mode, &mods, &key_value]);
-
-                        riverctl.args(value.command.iter().map(String::as_str));
-                        riverctl
-                    })
-                    .collect::<Vec<_>>()
+                base
             })
-            .collect()
+            .collect();
+
+        output.sort_by_cached_key(|cmd| format!("{cmd:?}"));
+        output.dedup_by_key(|cmd| format!("{cmd:?}"));
+
+        Ok(output)
     }
 }
 
-impl MapMode {
-    pub(crate) fn as_command(self) -> &'static str {
-        match self {
-            MapMode::Map => "map",
-            MapMode::MapMouse => "map-pointer",
-            MapMode::Unmap => "unmap",
+fn key_value_to_xkb_common_name(value: KeyValue) -> (String, Vec<&'static str>) {
+    let mut extra_modifiers = vec![];
+
+    let output = match value {
+        KeyValue::Backspace => "BackSpace".to_owned(),
+        KeyValue::Enter => "Return".to_owned(),
+        KeyValue::Left => "Left".to_owned(),
+        KeyValue::Right => "Right".to_owned(),
+        KeyValue::Up => "Up".to_owned(),
+        KeyValue::Down => "Down".to_owned(),
+        KeyValue::Home => "Home".to_owned(),
+        KeyValue::End => "End".to_owned(),
+        KeyValue::PageUp => "Page_Up".to_owned(),
+        KeyValue::PageDown => "Page_Down".to_owned(),
+        KeyValue::Tab => "Tab".to_owned(),
+        KeyValue::BackTab => "BackTab".to_owned(),
+        KeyValue::Delete => "Delete".to_owned(),
+        KeyValue::Insert => "Insert".to_owned(),
+        KeyValue::F(num) => format!("F{num}"),
+        KeyValue::Char(a) => {
+            // River does not differentiate between 'a' and 'A',
+            // so we need to do it beforehand.
+            if a.is_ascii_uppercase() {
+                extra_modifiers.push("Shift");
+            }
+
+            if a == ' ' {
+                "Space".to_string()
+            } else {
+                a.to_string()
+            }
         }
+        KeyValue::Null => "Null".to_owned(),
+        KeyValue::Esc => "Escape".to_owned(),
+        KeyValue::CapsLock => "CapsLock".to_owned(),
+        KeyValue::ScrollLock => "ScrollLock".to_owned(),
+        KeyValue::NumLock => "NumLock".to_owned(),
+        KeyValue::PrintScreen => "Print".to_owned(),
+        KeyValue::Pause => "Pause".to_owned(),
+        KeyValue::Menu => "Menu".to_owned(),
+        KeyValue::KeypadBegin => "KeypadBegin".to_owned(),
+        KeyValue::Media(media_key_code) => match media_key_code {
+            MediaKeyCode::Play => "XF86AudioPlay".to_owned(),
+            MediaKeyCode::Pause => "XF86AudioPause".to_owned(),
+            MediaKeyCode::PlayPause => "XF86AudioPlayPause".to_owned(),
+            MediaKeyCode::Reverse => "XF86AudioReverse".to_owned(),
+            MediaKeyCode::Stop => "XF86AudioStop".to_owned(),
+            MediaKeyCode::FastForward => "XF86AudioFastForward".to_owned(),
+            MediaKeyCode::Rewind => "XF86AudioRewind".to_owned(),
+            MediaKeyCode::TrackNext => "XF86AudioNext".to_owned(),
+            MediaKeyCode::TrackPrevious => "XF86AudioPrev".to_owned(),
+            MediaKeyCode::Record => "XF86AudioRecord".to_owned(),
+            MediaKeyCode::LowerVolume => "XF86AudioLowerVolume".to_owned(),
+            MediaKeyCode::RaiseVolume => "XF86AudioRaiseVolume".to_owned(),
+            MediaKeyCode::MuteVolume => "XF86AudioMute".to_owned(),
+        },
+        KeyValue::MouseKey(mouse_key_value) => match mouse_key_value {
+            MouseKeyValue::Left => "BTN_LEFT".to_owned(),
+            MouseKeyValue::Right => "BTN_RIGHT".to_owned(),
+            MouseKeyValue::Middle => "BTN_MIDDLE".to_owned(),
+        },
+        KeyValue::ModifierKey(modifier_key_code) => match modifier_key_code {
+            ModifierKeyCode::LeftAlt => "ALT_L".to_owned(),
+            ModifierKeyCode::RightAlt => "ALT_R".to_owned(),
+            ModifierKeyCode::LeftCtrl => "CTRL_L".to_owned(),
+            ModifierKeyCode::RightCtrl => "CTRL_R".to_owned(),
+            ModifierKeyCode::LeftMeta => "SUPER_L".to_owned(),
+            ModifierKeyCode::RightMeta => "SUPER_R".to_owned(),
+            ModifierKeyCode::LeftShift => "SHIFT_L".to_owned(),
+            ModifierKeyCode::RightShift => "SHIFT_R".to_owned(),
+        },
+        other => todo!("Key value: {other} not known."),
+    };
+
+    (output, extra_modifiers)
+}
+
+fn key_to_command(key: Key, command: &[String], mode: &str, allow_locked: bool) -> Vec<Command> {
+    let mut modifiers = {
+        let modifiers = key.modifiers();
+        let mut output = vec![];
+
+        if modifiers.alt() {
+            output.push("Alt");
+        }
+        if modifiers.ctrl() {
+            output.push("Control");
+        }
+        if modifiers.meta() {
+            output.push("Super");
+        }
+        if modifiers.shift() {
+            output.push("Shift");
+        }
+        output
+    };
+
+    let (key_value, extra_modifiers) = key_value_to_xkb_common_name(key.value());
+    modifiers.extend(extra_modifiers);
+
+    let map_mode = if let KeyValue::MouseKey(_) = key.value() {
+        "map-pointer"
+    } else {
+        "map"
+    };
+
+    let modifiers = if modifiers.is_empty() {
+        "None".to_owned()
+    } else {
+        modifiers.join("+")
+    };
+
+    let mut output = vec![{
+        let mut riverctl = Command::new("riverctl");
+        riverctl.args([map_mode, mode, &modifiers, &key_value]);
+
+        riverctl.args(command.iter().map(String::as_str));
+
+        riverctl
+    }];
+
+    if allow_locked {
+        output.push({
+            let mut riverctl = Command::new("riverctl");
+            riverctl.args([map_mode, "locked", &modifiers, &key_value]);
+
+            riverctl.args(command.iter().map(String::as_str));
+
+            riverctl
+        });
     }
+
+    output
 }
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/key_map/mod.rs b/pkgs/by-name/ri/river-mk-keymap/src/key_map/mod.rs
index 2c82ee05..16dc02f4 100644
--- a/pkgs/by-name/ri/river-mk-keymap/src/key_map/mod.rs
+++ b/pkgs/by-name/ri/river-mk-keymap/src/key_map/mod.rs
@@ -8,40 +8,100 @@
 // You should have received a copy of the License along with this program.
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-use std::{collections::HashMap, fmt::Display, ops::Deref, str::FromStr};
+use std::{fmt::Display, ops::Deref, str::FromStr};
 
-use anyhow::Context;
-use keymaps::{key_repr::Key, map_tree::MapTrie};
+use anyhow::{anyhow, bail, Context, Result};
+use keymaps::{
+    key_repr::{Key, Keys},
+    map_tree::MapTrie,
+};
 use serde::{Deserialize, Serialize};
+use serde_json::{Map, Value};
 
 pub mod commands;
 
-#[derive(Deserialize, Serialize, Debug)]
-#[allow(clippy::module_name_repetitions)]
-pub struct RawKeyMap(HashMap<Key, KeyConfig>);
-
 #[derive(Clone, Deserialize, Serialize, Debug, PartialEq, PartialOrd)]
-/// What values to use for: `riverctl <map_mode> <mode> <mods> <key> <command..>`
+/// What values to use for: `riverctl <command..>`
+#[serde(deny_unknown_fields)]
 pub struct KeyConfig {
     command: Vec<String>,
 
-    #[serde(default = "default_mode")]
-    modes: Vec<String>,
+    /// Whether to allow this key mapping in the “locked” mode.
+    #[serde(default)]
+    allow_locked: bool,
+
+    /// Whether to go back to the normal mode, after running this command.
+    #[serde(default)]
+    once: bool,
 
-    #[serde(default = "MapMode::default")]
-    map_mode: MapMode,
+    /// Use a different description to display this command, instead of the `command`.
+    description: Option<String>,
 }
 
 impl FromStr for KeyMap {
     type Err = anyhow::Error;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
-        let raw: RawKeyMap =
-            serde_json::from_str(s).context("Failed to parse the keymap config file as json.")?;
+        fn decode_value(
+            output: &mut MapTrie<KeyConfig>,
+            current_key: Vec<Key>,
+            value: &Value,
+        ) -> Result<()> {
+            let key_config = if let Some(value) = value.as_array() {
+                KeyConfig {
+                    command: value
+                        .iter()
+                        .map(|v| v.as_str().map(ToOwned::to_owned))
+                        .collect::<Option<_>>()
+                        .ok_or(anyhow!("A array contained a non-string value: {value:#?}"))?,
+                    allow_locked: false,
+                    once: false,
+                    description: None,
+                }
+            } else if let Some(object) = value.as_object() {
+                if object.contains_key("command") {
+                    serde_json::from_value(value.to_owned())
+                        .with_context(|| format!("Failed to parse key config: {value:#?}"))?
+                } else {
+                    for (key, value) in object {
+                        let mut local_current_key = current_key.clone();
+                        local_current_key.push(
+                            Key::from_str(key)
+                                .with_context(|| format!("Failed to parse key '{key}'"))?,
+                        );
+
+                        decode_value(output, local_current_key, value)?;
+                    }
+                    return Ok(());
+                }
+            } else {
+                bail!("Value ({}) is invalid (not array or object).", value)
+            };
+
+            output
+                .insert(&current_key, key_config.clone())
+                .with_context(|| {
+                    format!(
+                        "Failed to insert mapping {} -> {key_config}",
+                        Keys::from(current_key)
+                    )
+                })?;
+
+            Ok(())
+        }
+
         let mut out = MapTrie::<KeyConfig>::new();
-        for (key, value) in raw.0 {
-            out.insert(&[key], value.clone())
-                .with_context(|| format!("Failed to insert mapping {key} -> {value}"))?;
+
+        let raw: Map<String, Value> =
+            serde_json::from_str(s).context("Failed to parse the keymap config file as json.")?;
+
+        for (key, value) in raw {
+            decode_value(
+                &mut out,
+                vec![Key::from_str(&key)
+                    .with_context(|| format!("Failed to parse key ('{key}')"))?],
+                &value,
+            )?;
         }
 
         Ok(Self(out))
@@ -49,25 +109,11 @@ impl FromStr for KeyMap {
 }
 impl Display for KeyConfig {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.write_str(self.command.join(" ").as_str())
-    }
-}
-
-fn default_mode() -> Vec<String> {
-    vec!["normal".to_owned()]
-}
-
-#[derive(Copy, Deserialize, Serialize, Debug, Clone, Default, PartialEq, PartialOrd)]
-enum MapMode {
-    #[default]
-    Map,
-    MapMouse,
-    Unmap,
-}
-
-impl Display for MapMode {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        <Self as std::fmt::Debug>::fmt(self, f)
+        if let Some(desc) = &self.description {
+            f.write_str(desc)
+        } else {
+            f.write_str(self.command.join(" ").as_str())
+        }
     }
 }
 
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/main.rs b/pkgs/by-name/ri/river-mk-keymap/src/main.rs
index 63955f7f..18c291cf 100644
--- a/pkgs/by-name/ri/river-mk-keymap/src/main.rs
+++ b/pkgs/by-name/ri/river-mk-keymap/src/main.rs
@@ -13,31 +13,57 @@ use std::fs;
 use anyhow::Context;
 use clap::Parser;
 
-mod cli;
+pub mod cli;
 pub mod key_map;
+pub mod wayland;
 
 use crate::{cli::Args, key_map::KeyMap};
 
 fn main() -> Result<(), anyhow::Error> {
     let args = Args::parse();
-    let keymap_file = fs::read_to_string(&args.path)
-        .with_context(|| format!("Failed to open keymap file at: '{}'.", args.path.display()))?;
-
-    let keymap: KeyMap = keymap_file
-        .parse()
-        .with_context(|| format!("Failed to parse keymap file at: {}", args.path.display()))?;
-
-    // println!("{keymap}");
-    // println!("Commands:");
-    for mut command in keymap.to_commands() {
-        // println!("Executing {command:?}");
-        let status = command
-            .status()
-            .with_context(|| format!("Failed to run command: '{command:?}'"))?;
-
-        if !status.success() {
-            eprintln!("Command ('{command:?}') returned with non zero exit code: {status}");
+
+    let keymap_path = &args.keymap.canonicalize().with_context(|| {
+        format!(
+            "Failed to canonicalize kepmay path: '{}'",
+            args.keymap.display()
+        )
+    })?;
+
+    let config = {
+        let keymap_file = fs::read_to_string(keymap_path).with_context(|| {
+            format!(
+                "Failed to open keymap file at: '{}'.",
+                keymap_path.display()
+            )
+        })?;
+
+        let keymap: KeyMap = keymap_file.parse().with_context(|| {
+            format!("Failed to parse keymap file at: {}", keymap_path.display())
+        })?;
+
+        keymap
+    };
+
+    match args.command {
+        cli::SubCommand::Init { dry_run } => {
+            println!("{config}");
+            for mut command in config.to_commands(keymap_path)? {
+                if dry_run {
+                    println!("{command:?}");
+                } else {
+                    let status = command
+                        .status()
+                        .with_context(|| format!("Failed to run command: '{command:?}'"))?;
+
+                    if !status.success() {
+                        eprintln!(
+                            "Command ('{command:?}') returned with non zero exit code: {status}"
+                        );
+                    }
+                }
+            }
         }
+        cli::SubCommand::ShowHelp {} => wayland::main(config)?,
     }
 
     Ok(())
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs
new file mode 100644
index 00000000..0517ecf2
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/ansi/mod.rs
@@ -0,0 +1,173 @@
+use std::mem;
+
+use vte::{Params, Parser, Perform};
+
+#[derive(Debug, Clone, Copy)]
+pub(crate) enum Color {
+    Black,
+    Red,
+    Green,
+    Yellow,
+    Blue,
+    Purple,
+    Cyan,
+    White,
+}
+
+#[derive(Debug)]
+struct Cleaner {
+    current_color: Option<Color>,
+    styles: StyledString,
+    current: String,
+}
+
+#[derive(Debug)]
+struct StyledStringInner {
+    val: String,
+    color: Option<Color>,
+}
+
+pub(crate) struct StyledChar {
+    ch: char,
+    color: Option<Color>,
+}
+
+impl StyledChar {
+    pub(crate) fn as_char(&self) -> char {
+        self.ch
+    }
+
+    pub(crate) fn is_bold(&self) -> bool {
+        self.color.is_some()
+    }
+
+    pub(crate) fn color(&self) -> Option<Color> {
+        self.color
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct StyledString {
+    inner: Vec<StyledStringInner>,
+}
+
+impl StyledString {
+    fn push(&mut self, val: StyledStringInner) {
+        self.inner.push(val);
+    }
+
+    pub(crate) fn chars(&self) -> impl Iterator<Item = StyledChar> + use<'_> {
+        self.inner.iter().flat_map(|inner| {
+            inner.val.chars().map(|ch| StyledChar {
+                ch,
+                color: inner.color,
+            })
+        })
+    }
+}
+
+impl Cleaner {
+    fn reset_color(&mut self) {
+        self.styles.push(StyledStringInner {
+            val: mem::take(&mut self.current),
+            color: mem::take(&mut self.current_color),
+        });
+    }
+
+    fn set_color(&mut self, color: Color) {
+        self.current_color = Some(color);
+    }
+
+    fn add_char(&mut self, c: char) {
+        self.current.push(c);
+    }
+}
+
+impl Perform for Cleaner {
+    fn print(&mut self, c: char) {
+        self.add_char(c);
+    }
+
+    fn execute(&mut self, byte: u8) {
+        if byte == b'\n' {
+            self.reset_color();
+            self.add_char('\n');
+            self.reset_color();
+        } else {
+            eprintln!("Unknown [execute]: {byte:02x}");
+        }
+    }
+
+    fn hook(&mut self, params: &Params, intermediates: &[u8], ignore: bool, c: char) {
+        eprintln!(
+            "Unknown [hook] params={params:?}, intermediates={intermediates:?}, ignore={ignore:?}, char={c:?}"
+        );
+    }
+
+    fn put(&mut self, byte: u8) {
+        eprintln!("Unknonw [put] {byte:02x}");
+    }
+
+    fn unhook(&mut self) {
+        eprintln!("Unknown [unhook]");
+    }
+
+    fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
+        eprintln!("Unkown [osc_dispatch] params={params:?} bell_terminated={bell_terminated}");
+    }
+
+    fn csi_dispatch(&mut self, params: &Params, _: &[u8], _: bool, c: char) {
+        let params: Vec<u16> = params.iter().flatten().copied().collect();
+
+        if c != 'm' {
+            return;
+        }
+
+        // See: https://gist.github.com/JBlond/2fea43a3049b38287e5e9cefc87b2124
+        match params[..] {
+            [0] => self.reset_color(),
+            // [0, regular] if matches!(regular, 30..=37) => {}
+            [1, bold] if matches!(bold, 30..=37) => match bold {
+                30 => self.set_color(Color::Black),
+                31 => self.set_color(Color::Red),
+                32 => self.set_color(Color::Green),
+                36 => self.set_color(Color::Yellow),
+                34 => self.set_color(Color::Blue),
+                35 => self.set_color(Color::Purple),
+                33 => self.set_color(Color::Cyan),
+                37 => self.set_color(Color::White),
+                _ => unreachable!("Was filtered out"),
+            },
+            // [4, underline] if matches!(underline, 30..=37) => {}
+            // [background] if matches!(background, 40..=47) => {}
+            _ => todo!(),
+        }
+
+        // println!(
+        //     "[csi_dispatch] params={:#?}, intermediates={:?}, ignore={:?}, char={:?}",
+        //     params, intermediates, ignore, c
+        // );
+    }
+
+    fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) {
+        eprintln!(
+            "Unkown [esc_dispatch] intermediates={intermediates:?}, ignore={ignore:?}, byte={byte:02x}"
+        );
+    }
+}
+
+pub(crate) fn parse(input: &str) -> StyledString {
+    let mut statemachine = Parser::new();
+    let mut performer = Cleaner {
+        current_color: None,
+        styles: StyledString { inner: vec![] },
+        current: String::new(),
+    };
+
+    let buf: Vec<_> = input.bytes().collect();
+
+    statemachine.advance(&mut performer, &buf[..]);
+
+    assert!(performer.current.is_empty() && performer.current_color.is_none());
+    performer.styles
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/dispatches.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/dispatches.rs
new file mode 100644
index 00000000..c6e04fdf
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/dispatches.rs
@@ -0,0 +1,214 @@
+use std::num::NonZero;
+
+use keymaps::key_repr::Key;
+use wayland_client::{
+    globals::GlobalListContents,
+    protocol::{
+        wl_buffer::WlBuffer, wl_compositor::WlCompositor, wl_registry, wl_seat::WlSeat,
+        wl_shm::WlShm, wl_shm_pool::WlShmPool, wl_surface::WlSurface,
+    },
+    Connection, Dispatch, QueueHandle,
+};
+
+use wayland_protocols_wlr::layer_shell::v1::client::{
+    zwlr_layer_shell_v1::ZwlrLayerShellV1,
+    zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1},
+};
+
+use crate::wayland::{
+    ansi, render,
+    river::protocols::river_protocols::{
+        zriver_seat_status_v1::{self, ZriverSeatStatusV1},
+        zriver_status_manager_v1::ZriverStatusManagerV1,
+    },
+    AppData,
+};
+
+impl Dispatch<ZriverSeatStatusV1, ()> for AppData {
+    fn event(
+        state: &mut Self,
+        _: &ZriverSeatStatusV1,
+        event: <ZriverSeatStatusV1 as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+        if let zriver_seat_status_v1::Event::Mode { name } = event {
+            let new_text = {
+                if name == "normal" {
+                    // We are back at the normal mode.
+                    // There is no need to display the mappings anymore, exit.
+                    state.should_exit = true;
+                    return;
+                } else if let Ok(keys) = Key::parse_multiple(&name) {
+                    if let Some(val) = state.config.get(&keys) {
+                        ansi::parse(val.to_string().as_str())
+                    } else {
+                        // Mode name not know, do nothing.
+                        return;
+                    }
+                } else {
+                    // Mode name not valid, do nothing.
+                    return;
+                }
+            };
+
+            let px_height;
+            (state.pixel_data, (state.max_px_width, px_height)) =
+                render::text(&new_text).expect("Works?");
+
+            // We add the `5` here, so that our letters don't stop exactly at the border.
+            state
+                .window
+                .0
+                .set_size(state.max_px_width + 5, px_height + 5);
+            state.window.1.commit();
+
+            if state.configured {
+                state.draw();
+            }
+        }
+    }
+}
+
+impl Dispatch<ZwlrLayerSurfaceV1, ()> for AppData {
+    fn event(
+        state: &mut Self,
+        proxy: &ZwlrLayerSurfaceV1,
+        event: <ZwlrLayerSurfaceV1 as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+        match event {
+            zwlr_layer_surface_v1::Event::Configure {
+                serial,
+                width,
+                height,
+            } => {
+                state.buffer = None;
+
+                proxy.ack_configure(serial);
+
+                state.width = NonZero::new(width).map_or_else(|| state.width, NonZero::get);
+                state.height = NonZero::new(height).map_or_else(|| state.height, NonZero::get);
+
+                state.draw();
+
+                state.configured = true;
+            }
+            zwlr_layer_surface_v1::Event::Closed => {
+                state.should_exit = true;
+            }
+            _ => (),
+        }
+    }
+}
+
+impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for AppData {
+    fn event(
+        _: &mut AppData,
+        _: &wl_registry::WlRegistry,
+        _: wl_registry::Event,
+        _: &GlobalListContents,
+        _: &Connection,
+        _: &QueueHandle<AppData>,
+    ) {
+    }
+}
+
+impl Dispatch<WlShmPool, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &WlShmPool,
+        _: <WlShmPool as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
+
+impl Dispatch<WlShm, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &WlShm,
+        _: <WlShm as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
+
+impl Dispatch<WlSurface, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &WlSurface,
+        _: <WlSurface as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
+
+impl Dispatch<WlCompositor, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &WlCompositor,
+        _: <WlCompositor as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
+
+impl Dispatch<WlSeat, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &WlSeat,
+        _: <WlSeat as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
+
+impl Dispatch<WlBuffer, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &WlBuffer,
+        _: <WlBuffer as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
+
+impl Dispatch<ZriverStatusManagerV1, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &ZriverStatusManagerV1,
+        _: <ZriverStatusManagerV1 as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
+
+impl Dispatch<ZwlrLayerShellV1, ()> for AppData {
+    fn event(
+        _: &mut Self,
+        _: &ZwlrLayerShellV1,
+        _: <ZwlrLayerShellV1 as wayland_client::Proxy>::Event,
+        (): &(),
+        _: &Connection,
+        _: &QueueHandle<Self>,
+    ) {
+    }
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/mod.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/mod.rs
new file mode 100644
index 00000000..44c010d5
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/mod.rs
@@ -0,0 +1,272 @@
+#![allow(
+    clippy::cast_sign_loss,
+    clippy::cast_possible_wrap,
+    clippy::cast_precision_loss,
+    clippy::cast_possible_truncation
+)]
+
+use anyhow::Result;
+use wayland_client::{
+    globals::registry_queue_init,
+    protocol::{
+        wl_compositor::WlCompositor,
+        wl_seat::WlSeat,
+        wl_shm::{self, WlShm},
+        wl_surface::WlSurface,
+    },
+    Connection,
+};
+use wayland_protocols_wlr::layer_shell::v1::client::{
+    zwlr_layer_shell_v1::{self, ZwlrLayerShellV1},
+    zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1},
+};
+
+use crate::{
+    key_map::KeyMap,
+    wayland::{
+        ansi::Color,
+        river::protocols::river_protocols::zriver_status_manager_v1::ZriverStatusManagerV1,
+        shm::slot::{Buffer, SlotPool},
+    },
+};
+
+mod ansi;
+mod render;
+mod river;
+mod shm;
+
+mod dispatches;
+
+struct AppData {
+    pool: SlotPool,
+    window: (ZwlrLayerSurfaceV1, WlSurface),
+
+    configured: bool,
+    buffer: Option<Buffer>,
+
+    width: u32,
+    height: u32,
+
+    max_px_width: u32,
+    pixel_data: (Vec<f32>, Vec<Option<Color>>),
+
+    config: KeyMap,
+    should_exit: bool,
+}
+
+impl AppData {
+    #[allow(clippy::too_many_lines)]
+    fn draw(&mut self) {
+        let width = self.width;
+        let height = self.height;
+        let stride = self.width as i32 * 4;
+
+        let buffer = self.buffer.get_or_insert_with(|| {
+            self.pool
+                .create_buffer(
+                    width as i32,
+                    height as i32,
+                    stride,
+                    wl_shm::Format::Argb8888,
+                )
+                .expect("Works?")
+                .0
+        });
+
+        let canvas = if let Some(canvas) = self.pool.canvas(buffer) {
+            canvas
+        } else {
+            // This should be rare, but if the compositor has not released the previous
+            // buffer, we need double-buffering.
+            let (second_buffer, canvas) = self
+                .pool
+                .create_buffer(
+                    self.width as i32,
+                    self.height as i32,
+                    stride,
+                    wl_shm::Format::Argb8888,
+                )
+                .expect("create buffer");
+            *buffer = second_buffer;
+            canvas
+        };
+
+        // Draw to the window.
+        {
+            canvas
+                .chunks_exact_mut(stride as usize)
+                .enumerate()
+                .for_each(|(row_index, row)| {
+                    // let row_slice = row_slice(self.height, row_index as u32, 0.97);
+                    // let allowed_columns = (f64::from(self.width) * row_slice).ceil() as usize;
+
+                    row.chunks_exact_mut(4)
+                        .enumerate()
+                        .for_each(|(column_index, chunk)| {
+                            // const BACKGROUND_COLOR: u32 = 0xee58_5b70;
+                            const BACKGROUND_COLOR: u32 = 0xee00_0000;
+
+                            assert!(column_index as u32 <= self.width);
+
+                            // if column_index > allowed_columns
+                            //     || column_index < (self.width as usize - allowed_columns)
+                            // {
+                            //     let array: &mut [u8; 4] = chunk.try_into().unwrap();
+                            //     *array = 0u32.to_le_bytes();
+                            //     return;
+                            // }
+
+                            if column_index >= (self.max_px_width as usize) {
+                                let array: &mut [u8; 4] = chunk.try_into().unwrap();
+                                *array = BACKGROUND_COLOR.to_le_bytes();
+                            } else {
+                                assert!(column_index < self.max_px_width as usize);
+
+                                let position =
+                                    column_index + row_index * self.max_px_width as usize;
+
+                                if let Some(coverage) = &self.pixel_data.0.get(position) {
+                                    let a = (BACKGROUND_COLOR & (0xff << (6 * 4))) >> 24;
+
+                                    let (r, g, b) = if let Some(color) = self
+                                        .pixel_data
+                                        .1
+                                        .get(position)
+                                        .expect("If the pixel is set, the color will too")
+                                    {
+                                        let (r, g, b) = match color {
+                                            Color::Black => (0, 0, 0),
+                                            Color::Red => (0xff, 0, 0),
+                                            Color::Green => (0, 0xff, 0),
+                                            Color::Yellow => (0xff, 0xff, 0),
+                                            Color::Blue => (0, 0, 0xff),
+                                            Color::Purple => (0x80, 0, 0x80),
+                                            Color::Cyan => (0, 0xff, 0xff),
+                                            Color::White => (0xff, 0xff, 0xff),
+                                        };
+
+                                        let r = (r as f32 * **coverage).ceil() as u32;
+                                        let g = (g as f32 * **coverage).ceil() as u32;
+                                        let b = (b as f32 * **coverage).ceil() as u32;
+
+                                        (r, g, b)
+                                    } else {
+                                        let r = (255.0 * **coverage).ceil() as u32;
+                                        let g = (255.0 * **coverage).ceil() as u32;
+                                        let b = (255.0 * **coverage).ceil() as u32;
+
+                                        (r, g, b)
+                                    };
+
+                                    let color: u32 = (a << 24) + (r << 16) + (g << 8) + b;
+
+                                    let array: &mut [u8; 4] = chunk.try_into().unwrap();
+                                    *array = color.to_le_bytes();
+                                } else {
+                                    let array: &mut [u8; 4] = chunk.try_into().unwrap();
+                                    *array = BACKGROUND_COLOR.to_le_bytes();
+                                }
+                            }
+                        });
+                });
+        }
+
+        self.window
+            .1
+            .damage_buffer(0, 0, self.width as i32, self.height as i32);
+
+        buffer.attach_to(&self.window.1).expect("works");
+        self.window.1.commit();
+    }
+}
+
+/// # Errors
+/// If a protocol error arises.
+pub fn main(config: KeyMap) -> Result<()> {
+    let conn = Connection::connect_to_env()?;
+    let (globals, mut queue) = registry_queue_init::<AppData>(&conn)?;
+    let qh = queue.handle();
+
+    let seat: WlSeat = globals.bind(&qh, 9..=9, ())?;
+    let status_manager: ZriverStatusManagerV1 = globals.bind(&qh, 4..=4, ())?;
+    let _seat_status = status_manager.get_river_seat_status(&seat, &qh, ());
+
+    let compositor: WlCompositor = globals.bind(&qh, 6..=6, ())?;
+    let shm: WlShm = globals.bind(&qh, 1..=1, ())?;
+    // let xdg_wm: XdgWmBase = globals.bind(&qh, 5..=5, ())?;
+
+    let surface = compositor.create_surface(&qh, ());
+    let pool = SlotPool::new(1024 * 1024, &shm)?;
+
+    let zwlr_layer_shell: ZwlrLayerShellV1 = globals.bind(&qh, 4..=4, ())?;
+    let layer_surface = zwlr_layer_shell.get_layer_surface(
+        &surface,
+        None,
+        zwlr_layer_shell_v1::Layer::Overlay,
+        "river-mk-keymap which-key".to_owned(),
+        &qh,
+        (),
+    );
+
+    layer_surface.set_size(256, 256);
+    layer_surface
+        .set_anchor(zwlr_layer_surface_v1::Anchor::Left | zwlr_layer_surface_v1::Anchor::Top);
+
+    surface.commit();
+
+    let mut me = AppData {
+        config,
+        should_exit: false,
+
+        configured: false,
+        buffer: None,
+
+        width: 256,
+        height: 256,
+
+        max_px_width: 0,
+        pixel_data: (vec![], vec![]),
+
+        window: (layer_surface, surface),
+
+        pool,
+    };
+
+    loop {
+        queue.blocking_dispatch(&mut me)?;
+
+        if me.should_exit {
+            break;
+        }
+    }
+
+    Ok(())
+}
+
+// /// Calculate which amount of the current row (`i`) should be painted, if we want a corner
+// /// rounding of percent `p` and have an total of `n` rows.
+// fn row_slice(n_u32: u32, i_u32: u32, p: f64) -> f64 {
+//     fn within_tolerance(a: f64, b: f64) -> bool {
+//         const ALLOWED_ERROR: f64 = 0.000_000_1;
+//
+//         (a - b).abs() < ALLOWED_ERROR
+//     }
+//
+//     let i = f64::from(i_u32);
+//     let n = f64::from(n_u32);
+//
+//     let out = p + (1.0 - p) * (PI * i / n).sin();
+//
+//     assert!(out >= 0.0);
+//     assert!(out <= 1.0);
+//
+//     if i_u32 == 0 || i_u32 == n_u32 {
+//         assert!(within_tolerance(out, p));
+//     }
+//
+//     if i_u32 < n_u32 / 2 {
+//         assert!(within_tolerance(out, row_slice(n_u32, n_u32 - i_u32, p)));
+//     }
+//
+//     out
+// }
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/render/layout.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/render/layout.rs
new file mode 100644
index 00000000..7f0aaec9
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/render/layout.rs
@@ -0,0 +1,57 @@
+use ab_glyph::{point, Font, Glyph, Point, ScaleFont};
+
+use crate::wayland::ansi::{StyledChar, StyledString};
+
+/// Simple paragraph layout for glyphs into `target`.
+/// Starts at position `(0, ascent)`.
+///
+/// This is for testing and examples.
+pub(super) fn layout_paragraph<F, SF, BF, BSF>(
+    font: SF,
+    bold_font: BSF,
+    position: Point,
+    max_width: f32,
+    text: &StyledString,
+    target: &mut Vec<(Glyph, StyledChar)>,
+) where
+    F: Font,
+    SF: ScaleFont<F>,
+    BF: Font,
+    BSF: ScaleFont<BF>,
+{
+    let v_advance = font.height() + font.line_gap();
+    let mut caret = position + point(0.0, font.ascent());
+    let mut last_glyph: Option<Glyph> = None;
+
+    for c in text.chars() {
+        if c.as_char().is_control() {
+            if c.as_char() == '\n' {
+                caret = point(position.x, caret.y + v_advance);
+                last_glyph = None;
+            }
+            continue;
+        }
+
+        let mut glyph = if c.is_bold() {
+            bold_font.scaled_glyph(c.as_char())
+        } else {
+            font.scaled_glyph(c.as_char())
+        };
+
+        if let Some(previous) = last_glyph.take() {
+            caret.x += font.kern(previous.id, glyph.id);
+        }
+        glyph.position = caret;
+
+        last_glyph = Some(glyph.clone());
+        caret.x += font.h_advance(glyph.id);
+
+        if !c.as_char().is_whitespace() && caret.x > position.x + max_width {
+            caret = point(position.x, caret.y + v_advance);
+            glyph.position = caret;
+            last_glyph = None;
+        }
+
+        target.push((glyph, c));
+    }
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/render/mod.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/render/mod.rs
new file mode 100644
index 00000000..e92def3c
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/render/mod.rs
@@ -0,0 +1,129 @@
+use std::{fs::File, io::Read};
+
+use ab_glyph::{point, Font, FontVec, PxScale, ScaleFont};
+use anyhow::{Context, Result};
+use font_kit::{
+    family_name::FamilyName, handle::Handle, properties::Properties, source::SystemSource,
+};
+
+use crate::wayland::ansi::{Color, StyledString};
+
+mod layout;
+
+fn get_font(weight: f32) -> Result<impl Font> {
+    let handle = SystemSource::new()
+        .select_best_match(
+            &[FamilyName::Monospace],
+            Properties::new().weight(font_kit::properties::Weight(weight)),
+        )
+        .context("Failed to find a monospace font")?;
+
+    match handle {
+        Handle::Path { path, font_index } => {
+            let data = {
+                let mut buffer = vec![];
+
+                let mut file = File::open(&path)?;
+                file.read_to_end(&mut buffer)?;
+                buffer
+            };
+
+            FontVec::try_from_vec_and_index(data, font_index).with_context(|| {
+                format!(
+                    "Failed to load font at '{}' with index {}",
+                    path.display(),
+                    font_index
+                )
+            })
+        }
+        Handle::Memory { .. } => unimplemented!(),
+    }
+}
+
+pub(super) type ColorVec = (Vec<f32>, Vec<Option<Color>>);
+pub(super) fn text(input: &StyledString) -> Result<(ColorVec, (u32, u32))> {
+    let normal_font = get_font(400.0)?;
+    let bold_font = get_font(600.0)?;
+
+    let height: f32 = 15.0;
+    let px_height = height.ceil() as usize;
+
+    let scale = PxScale {
+        x: height,
+        y: height,
+    };
+
+    let scaled_font = normal_font.into_scaled(scale);
+    let bold_scaled_font = bold_font.into_scaled(scale);
+
+    let mut glyphs = Vec::new();
+    layout::layout_paragraph(
+        &scaled_font,
+        &bold_scaled_font,
+        point(0.0, 0.0),
+        9999.0,
+        input,
+        &mut glyphs,
+    );
+
+    let px_width = glyphs
+        .iter()
+        .fold(0.0, |acc, (g, c)| {
+            let next = g.position.x
+                + if c.is_bold() {
+                    bold_scaled_font.h_advance(g.id)
+                } else {
+                    scaled_font.h_advance(g.id)
+                };
+
+            if next > acc {
+                next
+            } else {
+                acc
+            }
+        })
+        .ceil() as usize;
+
+    // Rasterise to a f32 alpha vec
+    let mut pixel_data = vec![0.0; px_width * px_height];
+    let mut color_data = vec![None; px_width * px_height];
+    for (g, c) in glyphs {
+        let maybe_glyph = if c.is_bold() {
+            bold_scaled_font.outline_glyph(g)
+        } else {
+            scaled_font.outline_glyph(g)
+        };
+
+        if let Some(og) = maybe_glyph {
+            let bounds = og.px_bounds();
+            og.draw(|x, y, v| {
+                let x = x as f32 + bounds.min.x;
+                let y = y as f32 + bounds.min.y;
+                let next_idx = x as usize + y as usize * px_width;
+
+                assure_idx(&mut pixel_data, next_idx, 0.0);
+                assure_idx(&mut color_data, next_idx, None);
+
+                // save the coverage alpha
+                pixel_data[next_idx] += v;
+                color_data[next_idx] = c.color();
+            });
+        }
+    }
+
+    let len = pixel_data.len();
+    Ok((
+        (pixel_data, color_data),
+        (px_width as u32, (len / px_width) as u32),
+    ))
+}
+
+fn assure_idx<T: Copy + Clone>(pixel_data: &mut Vec<T>, next_idx: usize, fill: T) {
+    let last = pixel_data.len() - 1;
+
+    if next_idx > last {
+        let needed = next_idx - last;
+
+        pixel_data.extend(vec![fill; needed]);
+    }
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/river/mod.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/river/mod.rs
new file mode 100644
index 00000000..f17c7ac8
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/river/mod.rs
@@ -0,0 +1 @@
+pub(crate) mod protocols;
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/river/protocols.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/river/protocols.rs
new file mode 100644
index 00000000..e54b65e1
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/river/protocols.rs
@@ -0,0 +1,28 @@
+pub(crate) mod river_protocols {
+    use wayland_client;
+    // import objects from the core protocol if needed
+    use wayland_client::protocol::{wl_output, wl_seat};
+
+    // This module hosts a low-level representation of the protocol objects
+    // you will not need to interact with it yourself, but the code generated
+    // by the generate_client_code! macro will use it
+    // import the interfaces from the core protocol if needed
+
+    #[allow(non_upper_case_globals)]
+    pub(crate) mod __status {
+        use wayland_client::backend as wayland_backend;
+        use wayland_client::protocol::__interfaces::{
+            wl_output_interface, wl_seat_interface, WL_OUTPUT_INTERFACE, WL_SEAT_INTERFACE,
+        };
+        wayland_scanner::generate_interfaces!("./resources/river-status-unstable-v1.xml");
+    }
+
+    use self::__status::{
+        ZRIVER_OUTPUT_STATUS_V1_INTERFACE, ZRIVER_SEAT_STATUS_V1_INTERFACE,
+        ZRIVER_STATUS_MANAGER_V1_INTERFACE,
+    };
+
+    // This macro generates the actual types that represent the wayland objects of
+    // your custom protocol
+    wayland_scanner::generate_client_code!("./resources/river-status-unstable-v1.xml");
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/mod.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/mod.rs
new file mode 100644
index 00000000..65d3c590
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/mod.rs
@@ -0,0 +1,21 @@
+#![allow(dead_code)]
+
+pub(crate) mod multi;
+pub(crate) mod raw;
+pub(crate) mod slot;
+
+use std::io;
+
+use wayland_client::globals::GlobalError;
+
+/// An error that may occur when creating a pool.
+#[derive(Debug, thiserror::Error)]
+pub enum CreatePoolError {
+    /// The [`wl_shm`] global is not bound.
+    #[error(transparent)]
+    Global(#[from] GlobalError),
+
+    /// Error while allocating the shared memory.
+    #[error(transparent)]
+    Create(#[from] io::Error),
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/multi.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/multi.rs
new file mode 100644
index 00000000..0b1fdc1b
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/multi.rs
@@ -0,0 +1,437 @@
+//! A pool implementation which automatically manage buffers.
+//!
+//! This pool is built on the [`RawPool`].
+//!
+//! The [`MultiPool`] takes a key which is used to identify buffers and tries to return the buffer associated to the key
+//! if possible. If no buffer in the pool is associated to the key, it will create a new one.
+//!
+//! # Example
+//!
+//! ```rust
+//! use smithay_client_toolkit::reexports::client::{
+//!     QueueHandle,
+//!     protocol::wl_surface::WlSurface,
+//!     protocol::wl_shm::Format,
+//! };
+//! use smithay_client_toolkit::shm::multi::MultiPool;
+//!
+//! struct WlFoo {
+//!     // The surface we'll draw on and the index of buffer associated to it
+//!     surface: (WlSurface, usize),
+//!     pool: MultiPool<(WlSurface, usize)>
+//! }
+//!
+//! impl WlFoo {
+//!     fn draw(&mut self, qh: &QueueHandle<WlFoo>) {
+//!         let surface = &self.surface.0;
+//!         // We'll increment "i" until the pool can create a new buffer
+//!         // if there's no buffer associated with our surface and "i" or if
+//!         // a buffer with the obuffer associated with our surface and "i" is free for use.
+//!         //
+//!         // There's no limit to the amount of buffers we can allocate to our surface but since
+//!         // shm buffers are released fairly fast, it's unlikely we'll need more than double buffering.
+//!         for i in 0..2 {
+//!             self.surface.1 = i;
+//!             if let Ok((offset, buffer, slice)) = self.pool.create_buffer(
+//!                 100,
+//!                 100 * 4,
+//!                 100,
+//!                 &self.surface,
+//!                 Format::Argb8888,
+//!             ) {
+//!                 /*
+//!                     insert drawing code here
+//!                 */
+//!                 surface.attach(Some(buffer), 0, 0);
+//!                 surface.commit();
+//!                 // We exit the function after the draw.
+//!                 return;
+//!             }
+//!         }
+//!         /*
+//!             If there's no buffer available we can for example request a frame callback
+//!             and trigger a redraw when it fires.
+//!             (not shown in this example)
+//!         */
+//!     }
+//! }
+//!
+//! fn draw(slice: &mut [u8]) {
+//!     todo!()
+//! }
+//!
+//! ```
+//!
+
+use std::borrow::Borrow;
+use std::io;
+use std::os::unix::io::OwnedFd;
+
+use std::sync::{
+    atomic::{AtomicBool, Ordering},
+    Arc,
+};
+use wayland_client::backend::protocol::Message;
+use wayland_client::backend::{Backend, ObjectData, ObjectId};
+use wayland_client::{
+    protocol::{wl_buffer, wl_shm},
+    Proxy,
+};
+
+use crate::wayland::shm::CreatePoolError;
+
+use super::raw::RawPool;
+
+#[derive(Debug, thiserror::Error)]
+pub(crate) enum PoolError {
+    #[error("buffer is currently used")]
+    InUse,
+    #[error("buffer is overlapping another")]
+    Overlap,
+    #[error("buffer could not be found")]
+    NotFound,
+}
+
+/// This pool manages buffers associated with keys.
+/// Only one buffer can be attributed to a given key.
+#[derive(Debug)]
+pub(crate) struct MultiPool<K> {
+    buffer_list: Vec<BufferSlot<K>>,
+    pub(crate) inner: RawPool,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub(crate) struct BufferSlot<K> {
+    free: Arc<AtomicBool>,
+    size: usize,
+    used: usize,
+    offset: usize,
+    buffer: Option<wl_buffer::WlBuffer>,
+    key: K,
+}
+
+impl<K> Drop for BufferSlot<K> {
+    fn drop(&mut self) {
+        self.destroy().ok();
+    }
+}
+
+impl<K> BufferSlot<K> {
+    pub(crate) fn destroy(&self) -> Result<(), PoolError> {
+        self.buffer
+            .as_ref()
+            .ok_or(PoolError::NotFound)
+            .and_then(|buffer| {
+                self.free
+                    .load(Ordering::Relaxed)
+                    .then(|| buffer.destroy())
+                    .ok_or(PoolError::InUse)
+            })
+    }
+}
+
+impl<K> MultiPool<K> {
+    pub(crate) fn new(shm: &wl_shm::WlShm) -> Result<Self, CreatePoolError> {
+        Ok(Self {
+            inner: RawPool::new(4096, shm)?,
+            buffer_list: Vec::new(),
+        })
+    }
+
+    /// Resizes the memory pool, notifying the server the pool has changed in size.
+    ///
+    /// The [`wl_shm`] protocol only allows the pool to be made bigger. If the new size is smaller than the
+    /// current size of the pool, this function will do nothing.
+    pub(crate) fn resize(&mut self, size: usize) -> io::Result<()> {
+        self.inner.resize(size)
+    }
+
+    /// Removes the buffer with the given key from the pool and rearranges the others.
+    pub(crate) fn remove<Q>(&mut self, key: &Q) -> Option<BufferSlot<K>>
+    where
+        Q: PartialEq,
+        K: Borrow<Q>,
+    {
+        self.buffer_list
+            .iter()
+            .enumerate()
+            .find(|(_, slot)| slot.key.borrow().eq(key))
+            .map(|(i, _)| i)
+            .map(|i| self.buffer_list.remove(i))
+    }
+
+    /// Insert a buffer into the pool.
+    ///
+    /// The parameters are:
+    ///
+    /// - `width`: the width of this buffer (in pixels)
+    /// - `height`: the height of this buffer (in pixels)
+    /// - `stride`: distance (in bytes) between the beginning of a row and the next one
+    /// - `key`: a borrowed form of the stored key type
+    /// - `format`: the encoding format of the pixels.
+    pub(crate) fn insert<Q>(
+        &mut self,
+        width: i32,
+        stride: i32,
+        height: i32,
+        key: &Q,
+        format: wl_shm::Format,
+    ) -> Result<usize, PoolError>
+    where
+        K: Borrow<Q>,
+        Q: PartialEq + ToOwned<Owned = K>,
+    {
+        let mut offset = 0;
+        let mut found_key = false;
+        let size = (stride * height) as usize;
+        let mut index = Err(PoolError::NotFound);
+
+        for (i, buf_slot) in self.buffer_list.iter_mut().enumerate() {
+            if buf_slot.key.borrow().eq(key) {
+                found_key = true;
+                if buf_slot.free.load(Ordering::Relaxed) {
+                    // Destroys the buffer if it's resized
+                    if size != buf_slot.used {
+                        if let Some(buffer) = buf_slot.buffer.take() {
+                            buffer.destroy();
+                        }
+                    }
+                    // Increases the size of the Buffer if it's too small and add 5% padding.
+                    // It is possible this buffer overlaps the following but the else if
+                    // statement prevents this buffer from being returned if that's the case.
+                    buf_slot.size = buf_slot.size.max(size + size / 20);
+                    index = Ok(i);
+                } else {
+                    index = Err(PoolError::InUse);
+                }
+            // If a buffer is resized, it is likely that the followings might overlap
+            } else if offset > buf_slot.offset {
+                // When the buffer is free, it's safe to shift it because we know the compositor won't try to read it.
+                if buf_slot.free.load(Ordering::Relaxed) {
+                    if offset != buf_slot.offset {
+                        if let Some(buffer) = buf_slot.buffer.take() {
+                            buffer.destroy();
+                        }
+                    }
+                    buf_slot.offset = offset;
+                } else {
+                    // If one of the overlapping buffers is busy, then no buffer can be returned because it could result in a data race.
+                    index = Err(PoolError::InUse);
+                }
+            } else if found_key {
+                break;
+            }
+            let size = (buf_slot.size + 63) & !63;
+            offset += size;
+        }
+
+        if !found_key {
+            if let Err(err) = index {
+                return self
+                    .dyn_resize(offset, width, stride, height, key.to_owned(), format)
+                    .map(|()| self.buffer_list.len() - 1)
+                    .ok_or(err);
+            }
+        }
+
+        index
+    }
+
+    /// Retreives the buffer associated with the given key.
+    ///
+    /// The parameters are:
+    ///
+    /// - `width`: the width of this buffer (in pixels)
+    /// - `height`: the height of this buffer (in pixels)
+    /// - `stride`: distance (in bytes) between the beginning of a row and the next one
+    /// - `key`: a borrowed form of the stored key type
+    /// - `format`: the encoding format of the pixels.
+    pub(crate) fn get<Q>(
+        &mut self,
+        width: i32,
+        stride: i32,
+        height: i32,
+        key: &Q,
+        format: wl_shm::Format,
+    ) -> Option<(usize, &wl_buffer::WlBuffer, &mut [u8])>
+    where
+        Q: PartialEq,
+        K: Borrow<Q>,
+    {
+        let len = self.inner.len();
+        let size = (stride * height) as usize;
+        let buf_slot = self
+            .buffer_list
+            .iter_mut()
+            .find(|buf_slot| buf_slot.key.borrow().eq(key))?;
+
+        if buf_slot.size >= size {
+            return None;
+        }
+
+        buf_slot.used = size;
+        let offset = buf_slot.offset;
+        if buf_slot.buffer.is_none() {
+            if offset + size > len {
+                self.inner.resize(offset + size + size / 20).ok()?;
+            }
+            let free = Arc::new(AtomicBool::new(true));
+            let data = BufferObjectData { free: free.clone() };
+            let buffer = self.inner.create_buffer_raw(
+                offset as i32,
+                width,
+                height,
+                stride,
+                format,
+                Arc::new(data),
+            );
+            buf_slot.free = free;
+            buf_slot.buffer = Some(buffer);
+        }
+        let buf = buf_slot.buffer.as_ref()?;
+        buf_slot.free.store(false, Ordering::Relaxed);
+        Some((offset, buf, &mut self.inner.mmap()[offset..][..size]))
+    }
+
+    /// Returns the buffer associated with the given key and its offset (usize) in the mempool.
+    ///
+    /// The parameters are:
+    ///
+    /// - `width`: the width of this buffer (in pixels)
+    /// - `height`: the height of this buffer (in pixels)
+    /// - `stride`: distance (in bytes) between the beginning of a row and the next one
+    /// - `key`: a borrowed form of the stored key type
+    /// - `format`: the encoding format of the pixels.
+    ///
+    /// The offset can be used to determine whether or not a buffer was moved in the mempool
+    /// and by consequence if it should be damaged partially or fully.
+    pub(crate) fn create_buffer<Q>(
+        &mut self,
+        width: i32,
+        stride: i32,
+        height: i32,
+        key: &Q,
+        format: wl_shm::Format,
+    ) -> Result<(usize, &wl_buffer::WlBuffer, &mut [u8]), PoolError>
+    where
+        K: Borrow<Q>,
+        Q: PartialEq + ToOwned<Owned = K>,
+    {
+        let index = self.insert(width, stride, height, key, format)?;
+        self.get_at(index, width, stride, height, format)
+    }
+
+    /// Retreives the buffer at the given index.
+    fn get_at(
+        &mut self,
+        index: usize,
+        width: i32,
+        stride: i32,
+        height: i32,
+        format: wl_shm::Format,
+    ) -> Result<(usize, &wl_buffer::WlBuffer, &mut [u8]), PoolError> {
+        let len = self.inner.len();
+        let size = (stride * height) as usize;
+        let buf_slot = self.buffer_list.get_mut(index).ok_or(PoolError::NotFound)?;
+
+        if size > buf_slot.size {
+            return Err(PoolError::Overlap);
+        }
+
+        buf_slot.used = size;
+        let offset = buf_slot.offset;
+        if buf_slot.buffer.is_none() {
+            if offset + size > len {
+                self.inner
+                    .resize(offset + size + size / 20)
+                    .map_err(|_| PoolError::Overlap)?;
+            }
+            let free = Arc::new(AtomicBool::new(true));
+            let data = BufferObjectData { free: free.clone() };
+            let buffer = self.inner.create_buffer_raw(
+                offset as i32,
+                width,
+                height,
+                stride,
+                format,
+                Arc::new(data),
+            );
+            buf_slot.free = free;
+            buf_slot.buffer = Some(buffer);
+        }
+        buf_slot.free.store(false, Ordering::Relaxed);
+        let buf = buf_slot.buffer.as_ref().unwrap();
+        Ok((offset, buf, &mut self.inner.mmap()[offset..][..size]))
+    }
+
+    /// Calcule the offet and size of a buffer based on its stride.
+    fn offset(mut offset: i32, stride: i32, height: i32) -> (usize, usize) {
+        // bytes per pixel
+        let size = stride * height;
+        // 5% padding.
+        offset += offset / 20;
+        offset = (offset + 63) & !63;
+        (offset as usize, size as usize)
+    }
+
+    #[allow(clippy::too_many_arguments)]
+    /// Resizes the pool and appends a new buffer.
+    fn dyn_resize(
+        &mut self,
+        offset: usize,
+        width: i32,
+        stride: i32,
+        height: i32,
+        key: K,
+        format: wl_shm::Format,
+    ) -> Option<()> {
+        let (offset, size) = Self::offset(offset as i32, stride, height);
+        if self.inner.len() < offset + size {
+            self.resize(offset + size + size / 20).ok()?;
+        }
+        let free = Arc::new(AtomicBool::new(true));
+        let data = BufferObjectData { free: free.clone() };
+        let buffer = self.inner.create_buffer_raw(
+            offset as i32,
+            width,
+            height,
+            stride,
+            format,
+            Arc::new(data),
+        );
+        self.buffer_list.push(BufferSlot {
+            offset,
+            used: 0,
+            free,
+            buffer: Some(buffer),
+            size,
+            key,
+        });
+        Some(())
+    }
+}
+
+struct BufferObjectData {
+    free: Arc<AtomicBool>,
+}
+
+impl ObjectData for BufferObjectData {
+    fn event(
+        self: Arc<Self>,
+        _backend: &Backend,
+        msg: Message<ObjectId, OwnedFd>,
+    ) -> Option<Arc<dyn ObjectData>> {
+        debug_assert!(wayland_client::backend::protocol::same_interface(
+            msg.sender_id.interface(),
+            wl_buffer::WlBuffer::interface()
+        ));
+        debug_assert!(msg.opcode == 0);
+
+        // wl_buffer only has a single event: wl_buffer.release
+        self.free.store(true, Ordering::Relaxed);
+
+        None
+    }
+
+    fn destroyed(&self, _: ObjectId) {}
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/raw.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/raw.rs
new file mode 100644
index 00000000..a12afaa0
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/raw.rs
@@ -0,0 +1,290 @@
+//! A raw shared memory pool handler.
+//!
+//! This is intended as a safe building block for higher level shared memory pool abstractions and is not
+//! encouraged for most library users.
+
+use rustix::{
+    io::Errno,
+    shm::{Mode, OFlags},
+};
+use std::{
+    fs::File,
+    io,
+    ops::Deref,
+    os::unix::prelude::{AsFd, BorrowedFd, OwnedFd},
+    sync::Arc,
+    time::{SystemTime, UNIX_EPOCH},
+};
+
+use memmap2::MmapMut;
+use wayland_client::{
+    backend::ObjectData,
+    protocol::{wl_buffer, wl_shm, wl_shm_pool},
+    Dispatch, Proxy, QueueHandle, WEnum,
+};
+
+use super::CreatePoolError;
+
+/// A raw handler for file backed shared memory pools.
+///
+/// This type of pool will create the SHM memory pool and provide a way to resize the pool.
+///
+/// This pool does not release buffers. If you need this, use one of the higher level pools.
+#[derive(Debug)]
+pub struct RawPool {
+    pool: DestroyOnDropPool,
+    len: usize,
+    mem_file: File,
+    mmap: MmapMut,
+}
+
+impl RawPool {
+    pub fn new(len: usize, shm: &wl_shm::WlShm) -> Result<RawPool, CreatePoolError> {
+        let shm_fd = RawPool::create_shm_fd()?;
+        let mem_file = File::from(shm_fd);
+        mem_file.set_len(len as u64)?;
+
+        let pool = shm
+            .send_constructor(
+                wl_shm::Request::CreatePool {
+                    fd: mem_file.as_fd(),
+                    size: len as i32,
+                },
+                Arc::new(ShmPoolData),
+            )
+            .unwrap_or_else(|_| Proxy::inert(shm.backend().clone()));
+        let mmap = unsafe { MmapMut::map_mut(&mem_file)? };
+
+        Ok(RawPool {
+            pool: DestroyOnDropPool(pool),
+            len,
+            mem_file,
+            mmap,
+        })
+    }
+
+    /// Resizes the memory pool, notifying the server the pool has changed in size.
+    ///
+    /// The [`wl_shm`] protocol only allows the pool to be made bigger. If the new size is smaller than the
+    /// current size of the pool, this function will do nothing.
+    pub fn resize(&mut self, size: usize) -> io::Result<()> {
+        if size > self.len {
+            self.len = size;
+            self.mem_file.set_len(size as u64)?;
+            self.pool.resize(size as i32);
+            self.mmap = unsafe { MmapMut::map_mut(&self.mem_file) }?;
+        }
+
+        Ok(())
+    }
+
+    /// Returns a reference to the underlying shared memory file using the memmap2 crate.
+    pub fn mmap(&mut self) -> &mut MmapMut {
+        &mut self.mmap
+    }
+
+    /// Returns the size of the mempool
+    #[allow(clippy::len_without_is_empty)]
+    pub fn len(&self) -> usize {
+        self.len
+    }
+
+    /// Create a new buffer to this pool.
+    ///
+    /// ## Parameters
+    /// - `offset`: the offset (in bytes) from the beginning of the pool at which this buffer starts.
+    /// - `width` and `height`: the width and height of the buffer in pixels.
+    /// - `stride`: distance (in bytes) between the beginning of a row and the next one.
+    /// - `format`: the encoding format of the pixels.
+    ///
+    /// The encoding format of the pixels must be supported by the compositor or else a protocol error is
+    /// risen. You can ensure the format is supported by listening to [`Shm::formats`](crate::shm::Shm::formats).
+    ///
+    /// Note this function only creates the [`wl_buffer`] object, you will need to write to the pixels using the
+    /// [`io::Write`] implementation or [`RawPool::mmap`].
+    #[allow(clippy::too_many_arguments)]
+    pub fn create_buffer<D, U>(
+        &mut self,
+        offset: i32,
+        width: i32,
+        height: i32,
+        stride: i32,
+        format: wl_shm::Format,
+        udata: U,
+        qh: &QueueHandle<D>,
+    ) -> wl_buffer::WlBuffer
+    where
+        D: Dispatch<wl_buffer::WlBuffer, U> + 'static,
+        U: Send + Sync + 'static,
+    {
+        self.pool
+            .create_buffer(offset, width, height, stride, format, qh, udata)
+    }
+
+    /// Create a new buffer to this pool.
+    ///
+    /// This is identical to [`Self::create_buffer`], but allows using a custom [`ObjectData`]
+    /// implementation instead of relying on the [Dispatch] interface.
+    #[allow(clippy::too_many_arguments)]
+    pub fn create_buffer_raw(
+        &mut self,
+        offset: i32,
+        width: i32,
+        height: i32,
+        stride: i32,
+        format: wl_shm::Format,
+        data: Arc<dyn ObjectData + 'static>,
+    ) -> wl_buffer::WlBuffer {
+        self.pool
+            .send_constructor(
+                wl_shm_pool::Request::CreateBuffer {
+                    offset,
+                    width,
+                    height,
+                    stride,
+                    format: WEnum::Value(format),
+                },
+                data,
+            )
+            .unwrap_or_else(|_| Proxy::inert(self.pool.backend().clone()))
+    }
+
+    /// Returns the pool object used to communicate with the server.
+    pub fn pool(&self) -> &wl_shm_pool::WlShmPool {
+        &self.pool
+    }
+}
+
+impl AsFd for RawPool {
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        self.mem_file.as_fd()
+    }
+}
+
+impl From<RawPool> for OwnedFd {
+    fn from(pool: RawPool) -> Self {
+        pool.mem_file.into()
+    }
+}
+
+impl io::Write for RawPool {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        io::Write::write(&mut self.mem_file, buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        io::Write::flush(&mut self.mem_file)
+    }
+}
+
+impl io::Seek for RawPool {
+    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+        io::Seek::seek(&mut self.mem_file, pos)
+    }
+}
+
+impl RawPool {
+    fn create_shm_fd() -> io::Result<OwnedFd> {
+        #[cfg(target_os = "linux")]
+        {
+            match RawPool::create_memfd() {
+                Ok(fd) => return Ok(fd),
+
+                // Not supported, use fallback.
+                Err(Errno::NOSYS) => (),
+
+                Err(err) => return Err(Into::<io::Error>::into(err)),
+            }
+        }
+
+        let time = SystemTime::now();
+        let mut mem_file_handle = format!(
+            "/smithay-client-toolkit-{}",
+            time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
+        );
+
+        loop {
+            let flags = OFlags::CREATE | OFlags::EXCL | OFlags::RDWR;
+
+            let mode = Mode::RUSR | Mode::WUSR;
+
+            match rustix::shm::open(mem_file_handle.as_str(), flags, mode) {
+                Ok(fd) => match rustix::shm::unlink(mem_file_handle.as_str()) {
+                    Ok(()) => return Ok(fd),
+
+                    Err(errno) => {
+                        return Err(errno.into());
+                    }
+                },
+
+                Err(Errno::EXIST) => {
+                    // Change the handle if we happen to be duplicate.
+                    let time = SystemTime::now();
+
+                    mem_file_handle = format!(
+                        "/smithay-client-toolkit-{}",
+                        time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
+                    );
+                }
+
+                Err(Errno::INTR) => (),
+
+                Err(err) => return Err(err.into()),
+            }
+        }
+    }
+
+    #[cfg(target_os = "linux")]
+    fn create_memfd() -> rustix::io::Result<OwnedFd> {
+        use rustix::fs::{MemfdFlags, SealFlags};
+
+        loop {
+            let name = c"smithay-client-toolkit";
+            let flags = MemfdFlags::ALLOW_SEALING | MemfdFlags::CLOEXEC;
+
+            match rustix::fs::memfd_create(name, flags) {
+                Ok(fd) => {
+                    // We only need to seal for the purposes of optimization, ignore the errors.
+                    let _ = rustix::fs::fcntl_add_seals(&fd, SealFlags::SHRINK | SealFlags::SEAL);
+                    return Ok(fd);
+                }
+
+                Err(Errno::INTR) => (),
+
+                Err(err) => return Err(err),
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+struct DestroyOnDropPool(wl_shm_pool::WlShmPool);
+
+impl Deref for DestroyOnDropPool {
+    type Target = wl_shm_pool::WlShmPool;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl Drop for DestroyOnDropPool {
+    fn drop(&mut self) {
+        self.0.destroy();
+    }
+}
+
+#[derive(Debug)]
+struct ShmPoolData;
+
+impl ObjectData for ShmPoolData {
+    fn event(
+        self: Arc<Self>,
+        _: &wayland_client::backend::Backend,
+        _: wayland_client::backend::protocol::Message<wayland_client::backend::ObjectId, OwnedFd>,
+    ) -> Option<Arc<(dyn ObjectData + 'static)>> {
+        unreachable!("wl_shm_pool has no events")
+    }
+
+    fn destroyed(&self, _: wayland_client::backend::ObjectId) {}
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/slot.rs b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/slot.rs
new file mode 100644
index 00000000..ab52c5f6
--- /dev/null
+++ b/pkgs/by-name/ri/river-mk-keymap/src/wayland/shm/slot.rs
@@ -0,0 +1,596 @@
+//! A pool implementation based on buffer slots
+
+use std::io;
+use std::{
+    os::unix::io::{AsRawFd, OwnedFd},
+    sync::{
+        atomic::{AtomicU8, AtomicUsize, Ordering},
+        Arc, Mutex, Weak,
+    },
+};
+
+use wayland_client::backend::protocol::Message;
+use wayland_client::backend::{ObjectData, ObjectId};
+use wayland_client::{
+    protocol::{wl_buffer, wl_shm, wl_surface},
+    Proxy,
+};
+
+use crate::wayland::shm::raw::RawPool;
+use crate::wayland::shm::CreatePoolError;
+
+#[derive(Debug, thiserror::Error)]
+pub(crate) enum CreateBufferError {
+    /// Slot creation error.
+    #[error(transparent)]
+    Io(#[from] io::Error),
+
+    /// Pool mismatch.
+    #[error("Incorrect pool for slot")]
+    PoolMismatch,
+
+    /// Slot size mismatch
+    #[error("Requested buffer size is too large for slot")]
+    SlotTooSmall,
+}
+
+#[derive(Debug, thiserror::Error)]
+pub(crate) enum ActivateSlotError {
+    /// Buffer was already active
+    #[error("Buffer was already active")]
+    AlreadyActive,
+}
+
+#[derive(Debug)]
+pub(crate) struct SlotPool {
+    pub(crate) inner: RawPool,
+    free_list: Arc<Mutex<Vec<FreelistEntry>>>,
+}
+
+#[derive(Debug)]
+struct FreelistEntry {
+    offset: usize,
+    len: usize,
+}
+
+/// A chunk of memory allocated from a [`SlotPool`]
+///
+/// Retaining this object is only required if you wish to resize or change the buffer's format
+/// without changing the contents of the backing memory.
+#[derive(Debug)]
+pub(crate) struct Slot {
+    inner: Arc<SlotInner>,
+}
+
+#[derive(Debug)]
+struct SlotInner {
+    free_list: Weak<Mutex<Vec<FreelistEntry>>>,
+    offset: usize,
+    len: usize,
+    active_buffers: AtomicUsize,
+    /// Count of all "real" references to this slot.  This includes all Slot objects and any
+    /// [`BufferData`] object that is not in the DEAD state.  When this reaches zero, the memory for
+    /// this slot will return to the [`free_list`].  It is not possible for it to reach zero and have a
+    /// Slot or Buffer referring to it.
+    all_refs: AtomicUsize,
+}
+
+/// A wrapper around a [`wl_buffer::WlBuffer`] which has been allocated via a [`SlotPool`].
+///
+/// When this object is dropped, the buffer will be destroyed immediately if it is not active, or
+/// upon the server's release if it is.
+#[derive(Debug)]
+pub(crate) struct Buffer {
+    inner: wl_buffer::WlBuffer,
+    height: i32,
+    stride: i32,
+    slot: Slot,
+}
+
+/// [`ObjectData`] for the [`WlBuffer`]
+#[derive(Debug)]
+struct BufferData {
+    inner: Arc<SlotInner>,
+    state: AtomicU8,
+}
+
+// These constants define the value of BufferData::state, since AtomicEnum does not exist.
+impl BufferData {
+    /// Buffer is counted in [`active_buffers`] list; will return to INACTIVE on Release.
+    const ACTIVE: u8 = 0;
+
+    /// Buffer is not counted in [`active_buffers`] list, but also has not been destroyed.
+    const INACTIVE: u8 = 1;
+
+    /// Buffer is counted in [`active_buffers`] list; will move to DEAD on Release
+    const DESTROY_ON_RELEASE: u8 = 2;
+
+    /// Buffer has been destroyed
+    const DEAD: u8 = 3;
+
+    /// Value that is [`ORed`] on buffer release to transition to the next state
+    const RELEASE_SET: u8 = 1;
+
+    /// Value that is [`ORed`] on buffer destroy to transition to the next state
+    const DESTROY_SET: u8 = 2;
+
+    /// Call after successfully transitioning the state to DEAD
+    fn record_death(&self) {
+        drop(Slot {
+            inner: self.inner.clone(),
+        });
+    }
+}
+
+impl SlotPool {
+    pub(crate) fn new(len: usize, shm: &wl_shm::WlShm) -> Result<Self, CreatePoolError> {
+        let inner = RawPool::new(len, shm)?;
+        let free_list = Arc::new(Mutex::new(vec![FreelistEntry {
+            offset: 0,
+            len: inner.len(),
+        }]));
+        Ok(SlotPool { inner, free_list })
+    }
+
+    /// Create a new buffer in a new slot.
+    ///
+    /// This returns the buffer and the canvas.  The parameters are:
+    ///
+    /// - `width`: the width of this buffer (in pixels)
+    /// - `height`: the height of this buffer (in pixels)
+    /// - `stride`: distance (in bytes) between the beginning of a row and the next one
+    /// - `format`: the encoding format of the pixels. Using a format that was not
+    ///   advertised to the `wl_shm` global by the server is a protocol error and will
+    ///   terminate your connection.
+    ///
+    /// The [Slot] for this buffer will have exactly the size required for the data.  It can be
+    /// accessed via [`Buffer::slot`] to create additional buffers that point to the same data.  This
+    /// is required if you wish to change formats, buffer dimensions, or attach a canvas to
+    /// multiple surfaces.
+    ///
+    /// For more control over sizing, use [`Self::new_slot`] and [`Self::create_buffer_in`].
+    pub(crate) fn create_buffer(
+        &mut self,
+        width: i32,
+        height: i32,
+        stride: i32,
+        format: wl_shm::Format,
+    ) -> Result<(Buffer, &mut [u8]), CreateBufferError> {
+        let len = (height as usize) * (stride as usize);
+        let slot = self.new_slot(len)?;
+        let buffer = self.create_buffer_in(&slot, width, height, stride, format)?;
+        let canvas = self.raw_data_mut(&slot);
+        Ok((buffer, canvas))
+    }
+
+    /// Get the bytes corresponding to a given slot or buffer if drawing to the slot is permitted.
+    ///
+    /// Returns `None` if there are active buffers in the slot or if the slot does not correspond
+    /// to this pool.
+    pub(crate) fn canvas(&mut self, key: &impl CanvasKey) -> Option<&mut [u8]> {
+        key.canvas(self)
+    }
+
+    /// Returns the size, in bytes, of this pool.
+    #[allow(clippy::len_without_is_empty)]
+    pub(crate) fn len(&self) -> usize {
+        self.inner.len()
+    }
+
+    /// Resizes the memory pool, notifying the server the pool has changed in size.
+    ///
+    /// This is an optimization; the pool automatically resizes when you allocate new slots.
+    pub(crate) fn resize(&mut self, size: usize) -> io::Result<()> {
+        let old_len = self.inner.len();
+        self.inner.resize(size)?;
+        let new_len = self.inner.len();
+        if old_len == new_len {
+            return Ok(());
+        }
+        // add the new memory to the freelist
+        let mut free = self.free_list.lock().unwrap();
+        if let Some(FreelistEntry { offset, len }) = free.last_mut() {
+            if *offset + *len == old_len {
+                *len += new_len - old_len;
+                return Ok(());
+            }
+        }
+        free.push(FreelistEntry {
+            offset: old_len,
+            len: new_len - old_len,
+        });
+        Ok(())
+    }
+
+    fn alloc(&mut self, size: usize) -> io::Result<usize> {
+        let mut free = self.free_list.lock().unwrap();
+        for FreelistEntry { offset, len } in free.iter_mut() {
+            if *len >= size {
+                let rv = *offset;
+                *len -= size;
+                *offset += size;
+                return Ok(rv);
+            }
+        }
+        let mut rv = self.inner.len();
+        let mut pop_tail = false;
+        if let Some(FreelistEntry { offset, len }) = free.last() {
+            if offset + len == self.inner.len() {
+                rv -= len;
+                pop_tail = true;
+            }
+        }
+        // resize like Vec::reserve, always at least doubling
+        let target = std::cmp::max(rv + size, self.inner.len() * 2);
+        self.inner.resize(target)?;
+        // adjust the end of the freelist here
+        if pop_tail {
+            free.pop();
+        }
+        if target > rv + size {
+            free.push(FreelistEntry {
+                offset: rv + size,
+                len: target - rv - size,
+            });
+        }
+        Ok(rv)
+    }
+
+    fn free(free_list: &Mutex<Vec<FreelistEntry>>, mut offset: usize, mut len: usize) {
+        let mut free = free_list.lock().unwrap();
+        let mut nf = Vec::with_capacity(free.len() + 1);
+        for &FreelistEntry {
+            offset: ioff,
+            len: ilen,
+        } in free.iter()
+        {
+            if ioff + ilen == offset {
+                offset = ioff;
+                len += ilen;
+                continue;
+            }
+            if ioff == offset + len {
+                len += ilen;
+                continue;
+            }
+            if ioff > offset + len && len != 0 {
+                nf.push(FreelistEntry { offset, len });
+                len = 0;
+            }
+            if ilen != 0 {
+                nf.push(FreelistEntry {
+                    offset: ioff,
+                    len: ilen,
+                });
+            }
+        }
+        if len != 0 {
+            nf.push(FreelistEntry { offset, len });
+        }
+        *free = nf;
+    }
+
+    /// Create a new slot with the given size in bytes.
+    pub(crate) fn new_slot(&mut self, mut len: usize) -> io::Result<Slot> {
+        len = (len + 63) & !63;
+        let offset = self.alloc(len)?;
+
+        Ok(Slot {
+            inner: Arc::new(SlotInner {
+                free_list: Arc::downgrade(&self.free_list),
+                offset,
+                len,
+                active_buffers: AtomicUsize::new(0),
+                all_refs: AtomicUsize::new(1),
+            }),
+        })
+    }
+
+    /// Get the bytes corresponding to a given slot.
+    ///
+    /// Note: prefer using [`Self::canvas`], which will prevent drawing to a buffer that has not been
+    /// released by the server.
+    ///
+    /// Returns an empty buffer if the slot does not belong to this pool.
+    pub(crate) fn raw_data_mut(&mut self, slot: &Slot) -> &mut [u8] {
+        if slot.inner.free_list.as_ptr() == Arc::as_ptr(&self.free_list) {
+            &mut self.inner.mmap()[slot.inner.offset..][..slot.inner.len]
+        } else {
+            &mut []
+        }
+    }
+
+    /// Create a new buffer corresponding to a slot.
+    ///
+    /// The parameters are:
+    ///
+    /// - `width`: the width of this buffer (in pixels)
+    /// - `height`: the height of this buffer (in pixels)
+    /// - `stride`: distance (in bytes) between the beginning of a row and the next one
+    /// - `format`: the encoding format of the pixels. Using a format that was not
+    ///   advertised to the `wl_shm` global by the server is a protocol error and will
+    ///   terminate your connection
+    pub(crate) fn create_buffer_in(
+        &mut self,
+        slot: &Slot,
+        width: i32,
+        height: i32,
+        stride: i32,
+        format: wl_shm::Format,
+    ) -> Result<Buffer, CreateBufferError> {
+        let offset = slot.inner.offset as i32;
+        let len = (height as usize) * (stride as usize);
+        if len > slot.inner.len {
+            return Err(CreateBufferError::SlotTooSmall);
+        }
+
+        if slot.inner.free_list.as_ptr() != Arc::as_ptr(&self.free_list) {
+            return Err(CreateBufferError::PoolMismatch);
+        }
+
+        let slot = slot.clone();
+        // take a ref for the BufferData, which will be destroyed by BufferData::record_death
+        slot.inner.all_refs.fetch_add(1, Ordering::Relaxed);
+        let data = Arc::new(BufferData {
+            inner: slot.inner.clone(),
+            state: AtomicU8::new(BufferData::INACTIVE),
+        });
+        let buffer = self
+            .inner
+            .create_buffer_raw(offset, width, height, stride, format, data);
+        Ok(Buffer {
+            inner: buffer,
+            height,
+            stride,
+            slot,
+        })
+    }
+}
+
+impl Clone for Slot {
+    fn clone(&self) -> Self {
+        let inner = self.inner.clone();
+        inner.all_refs.fetch_add(1, Ordering::Relaxed);
+        Slot { inner }
+    }
+}
+
+impl Drop for Slot {
+    fn drop(&mut self) {
+        if self.inner.all_refs.fetch_sub(1, Ordering::Relaxed) == 1 {
+            if let Some(free_list) = self.inner.free_list.upgrade() {
+                SlotPool::free(&free_list, self.inner.offset, self.inner.len);
+            }
+        }
+    }
+}
+
+impl Drop for SlotInner {
+    fn drop(&mut self) {
+        debug_assert_eq!(*self.all_refs.get_mut(), 0);
+    }
+}
+
+/// A helper trait for [`SlotPool::canvas`].
+pub(crate) trait CanvasKey {
+    fn canvas<'pool>(&self, pool: &'pool mut SlotPool) -> Option<&'pool mut [u8]>;
+}
+
+impl Slot {
+    /// Return true if there are buffers referencing this slot whose contents are being accessed
+    /// by the server.
+    pub(crate) fn has_active_buffers(&self) -> bool {
+        self.inner.active_buffers.load(Ordering::Relaxed) != 0
+    }
+
+    /// Returns the size, in bytes, of this slot.
+    #[allow(clippy::len_without_is_empty)]
+    pub(crate) fn len(&self) -> usize {
+        self.inner.len
+    }
+
+    /// Get the bytes corresponding to a given slot if drawing to the slot is permitted.
+    ///
+    /// Returns `None` if there are active buffers in the slot or if the slot does not correspond
+    /// to this pool.
+    pub(crate) fn canvas<'pool>(&self, pool: &'pool mut SlotPool) -> Option<&'pool mut [u8]> {
+        if self.has_active_buffers() {
+            return None;
+        }
+        if self.inner.free_list.as_ptr() == Arc::as_ptr(&pool.free_list) {
+            Some(&mut pool.inner.mmap()[self.inner.offset..][..self.inner.len])
+        } else {
+            None
+        }
+    }
+}
+
+impl CanvasKey for Slot {
+    fn canvas<'pool>(&self, pool: &'pool mut SlotPool) -> Option<&'pool mut [u8]> {
+        self.canvas(pool)
+    }
+}
+
+impl Buffer {
+    /// Attach a buffer to a surface.
+    ///
+    /// This marks the slot as active until the server releases the buffer, which will happen
+    /// automatically assuming the surface is committed without attaching a different buffer.
+    ///
+    /// Note: if you need to ensure that [`canvas()`](Buffer::canvas) calls never return data that
+    /// could be attached to a surface in a multi-threaded client, make this call while you have
+    /// exclusive access to the corresponding [`SlotPool`].
+    pub(crate) fn attach_to(&self, surface: &wl_surface::WlSurface) -> Result<(), ActivateSlotError> {
+        self.activate()?;
+        surface.attach(Some(&self.inner), 0, 0);
+        Ok(())
+    }
+
+    /// Get the inner buffer.
+    pub(crate) fn wl_buffer(&self) -> &wl_buffer::WlBuffer {
+        &self.inner
+    }
+
+    pub(crate) fn height(&self) -> i32 {
+        self.height
+    }
+
+    pub(crate) fn stride(&self) -> i32 {
+        self.stride
+    }
+
+    fn data(&self) -> Option<&BufferData> {
+        self.inner.object_data()?.downcast_ref()
+    }
+
+    /// Get the bytes corresponding to this buffer if drawing is permitted.
+    ///
+    /// This may be smaller than the canvas associated with the slot.
+    pub(crate) fn canvas<'pool>(&self, pool: &'pool mut SlotPool) -> Option<&'pool mut [u8]> {
+        let len = (self.height as usize) * (self.stride as usize);
+        if self.slot.inner.active_buffers.load(Ordering::Relaxed) != 0 {
+            return None;
+        }
+        if self.slot.inner.free_list.as_ptr() == Arc::as_ptr(&pool.free_list) {
+            Some(&mut pool.inner.mmap()[self.slot.inner.offset..][..len])
+        } else {
+            None
+        }
+    }
+
+    /// Get the slot corresponding to this buffer.
+    pub(crate) fn slot(&self) -> Slot {
+        self.slot.clone()
+    }
+
+    /// Manually mark a buffer as active.
+    ///
+    /// An active buffer prevents drawing on its slot until a Release event is received or until
+    /// manually deactivated.
+    pub(crate) fn activate(&self) -> Result<(), ActivateSlotError> {
+        let data = self.data().expect("UserData type mismatch");
+
+        // This bitwise AND will transition INACTIVE -> ACTIVE, or do nothing if the buffer was
+        // already ACTIVE.  No other ordering is required, as the server will not send a Release
+        // until we send our attach after returning Ok.
+        match data
+            .state
+            .fetch_and(!BufferData::RELEASE_SET, Ordering::Relaxed)
+        {
+            BufferData::INACTIVE => {
+                data.inner.active_buffers.fetch_add(1, Ordering::Relaxed);
+                Ok(())
+            }
+            BufferData::ACTIVE => Err(ActivateSlotError::AlreadyActive),
+            _ => unreachable!("Invalid state in BufferData"),
+        }
+    }
+
+    /// Manually mark a buffer as inactive.
+    ///
+    /// This should be used when the buffer was manually marked as active or when a buffer was
+    /// attached to a surface but not committed.  Calling this function on a buffer that was
+    /// committed to a surface risks making the surface contents undefined.
+    pub(crate) fn deactivate(&self) -> Result<(), ActivateSlotError> {
+        let data = self.data().expect("UserData type mismatch");
+
+        // Same operation as the Release event, but we know the Buffer was not dropped.
+        match data
+            .state
+            .fetch_or(BufferData::RELEASE_SET, Ordering::Relaxed)
+        {
+            BufferData::ACTIVE => {
+                data.inner.active_buffers.fetch_sub(1, Ordering::Relaxed);
+                Ok(())
+            }
+            BufferData::INACTIVE => Err(ActivateSlotError::AlreadyActive),
+            _ => unreachable!("Invalid state in BufferData"),
+        }
+    }
+}
+
+impl CanvasKey for Buffer {
+    fn canvas<'pool>(&self, pool: &'pool mut SlotPool) -> Option<&'pool mut [u8]> {
+        self.canvas(pool)
+    }
+}
+
+impl Drop for Buffer {
+    fn drop(&mut self) {
+        if let Some(data) = self.data() {
+            match data
+                .state
+                .fetch_or(BufferData::DESTROY_SET, Ordering::Relaxed)
+            {
+                BufferData::ACTIVE => {
+                    // server is using the buffer, let ObjectData handle the destroy
+                }
+                BufferData::INACTIVE => {
+                    data.record_death();
+                    self.inner.destroy();
+                }
+                _ => unreachable!("Invalid state in BufferData"),
+            }
+        }
+    }
+}
+
+impl ObjectData for BufferData {
+    fn event(
+        self: Arc<Self>,
+        handle: &wayland_client::backend::Backend,
+        msg: Message<ObjectId, OwnedFd>,
+    ) -> Option<Arc<dyn ObjectData>> {
+        debug_assert!(wayland_client::backend::protocol::same_interface(
+            msg.sender_id.interface(),
+            wl_buffer::WlBuffer::interface()
+        ));
+        debug_assert!(msg.opcode == 0);
+
+        match self
+            .state
+            .fetch_or(BufferData::RELEASE_SET, Ordering::Relaxed)
+        {
+            BufferData::ACTIVE => {
+                self.inner.active_buffers.fetch_sub(1, Ordering::Relaxed);
+            }
+            BufferData::INACTIVE => {
+                // possible spurious release, or someone called deactivate incorrectly
+                eprintln!("Unexpected WlBuffer::Release on an inactive buffer");
+            }
+            BufferData::DESTROY_ON_RELEASE => {
+                self.record_death();
+                self.inner.active_buffers.fetch_sub(1, Ordering::Relaxed);
+
+                // The Destroy message is identical to Release message (no args, same ID), so just reply
+                handle
+                    .send_request(msg.map_fd(|x| x.as_raw_fd()), None, None)
+                    .expect("Unexpected invalid ID");
+            }
+            BufferData::DEAD => {
+                // no-op, this object is already unusable
+            }
+            _ => unreachable!("Invalid state in BufferData"),
+        }
+
+        None
+    }
+
+    fn destroyed(&self, _: ObjectId) {}
+}
+
+impl Drop for BufferData {
+    fn drop(&mut self) {
+        let state = *self.state.get_mut();
+        if state == BufferData::ACTIVE || state == BufferData::DESTROY_ON_RELEASE {
+            // Release the active-buffer count
+            self.inner.active_buffers.fetch_sub(1, Ordering::Relaxed);
+        }
+
+        if state != BufferData::DEAD {
+            // nobody has ever transitioned state to DEAD, so we are responsible for freeing the
+            // extra reference
+            self.record_death();
+        }
+    }
+}
diff --git a/pkgs/by-name/ri/river-mk-keymap/update.sh b/pkgs/by-name/ri/river-mk-keymap/update.sh
index 0b170ec8..8e36e13e 100755
--- a/pkgs/by-name/ri/river-mk-keymap/update.sh
+++ b/pkgs/by-name/ri/river-mk-keymap/update.sh
@@ -10,4 +10,5 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-cargo update && cargo upgrade
+[ "$1" = "upgrade" ] && cargo upgrade
+cargo update
diff --git a/pkgs/by-name/sc/screenshot_persistent/screenshot_persistent.sh b/pkgs/by-name/sc/screenshot_persistent/screenshot_persistent.sh
index 0eeb75c0..f67293cd 100755
--- a/pkgs/by-name/sc/screenshot_persistent/screenshot_persistent.sh
+++ b/pkgs/by-name/sc/screenshot_persistent/screenshot_persistent.sh
@@ -10,7 +10,7 @@
 
 # shellcheck shell=bash
 
-tmp="$(mktemp)"
+tmp="$(mktemp -t screenshot_persistent_XXXXX)"
 
 if grim -g "$(slurp)" "$tmp"; then
     name="$(rofi -dmenu -p "Name of screenshot: " -l 0)"
diff --git a/pkgs/by-name/st/stamp/package.nix b/pkgs/by-name/st/stamp/package.nix
index 62c4db2d..871d531c 100644
--- a/pkgs/by-name/st/stamp/package.nix
+++ b/pkgs/by-name/st/stamp/package.nix
@@ -10,6 +10,7 @@
 {
   writeShellApplication,
   # Dependencies
+  coreutils,
   fd,
   git,
   reuse,
@@ -20,6 +21,7 @@ writeShellApplication {
   inheritPath = false;
 
   runtimeInputs = [
+    coreutils
     fd
     git
     reuse
diff --git a/modules/home.legacy/conf/alacritty/toml/cursor.toml b/pkgs/by-name/sw/swallow/package.nix
index 6e633b5a..16608143 100644
--- a/modules/home.legacy/conf/alacritty/toml/cursor.toml
+++ b/pkgs/by-name/sw/swallow/package.nix
@@ -7,15 +7,19 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
+{
+  writeShellApplication,
+  # Dependencies
+  river-classic,
+}:
+writeShellApplication {
+  name = "swallow";
+  text = builtins.readFile ./swallow.sh;
 
-[cursor]
-blink_interval = 750
-blink_timeout = 5
-thickness = 0.15
-unfocused_hollow = true
-vi_mode_style = "None"
+  # We need to inherit the path, so that we can spawn stuff in a swallowed mode.
+  inheritPath = true;
 
-# Cursor style
-[cursor.style]
-blinking = "On"
-shape = "Beam"
+  runtimeInputs = [
+    river-classic
+  ];
+}
diff --git a/pkgs/by-name/sw/swallow/swallow.sh b/pkgs/by-name/sw/swallow/swallow.sh
new file mode 100755
index 00000000..922a21b3
--- /dev/null
+++ b/pkgs/by-name/sw/swallow/swallow.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env dash
+# Based on: https://codeberg.org/nirodhvana/reservoir/src/commit/2fa8c14877799a03bb927f048c2907dbb418fd68/dot-local/bin/gobble
+
+# Inspired by https://github.com/swindlesmccoop/not-just-dotfiles/blob/master/.local/bin/swallow
+
+swallow_tag=$((1 << 9))
+eat() {
+    riverctl set-view-tags $swallow_tag
+}
+
+throwup() {
+    riverctl set-focused-tags $swallow_tag &&
+        riverctl send-to-previous-tags &&
+        riverctl focus-previous-tags
+}
+
+if [ -z "$*" ]; then
+    printf "ERROR: No Arguments Supplied\n"
+else
+    eat && "$@"
+
+    throwup
+fi
diff --git a/pkgs/by-name/tr/tree-sitter-yts/package.nix b/pkgs/by-name/tr/tree-sitter-yts/package.nix
index 62ecf063..eef65714 100644
--- a/pkgs/by-name/tr/tree-sitter-yts/package.nix
+++ b/pkgs/by-name/tr/tree-sitter-yts/package.nix
@@ -14,46 +14,10 @@
   nodejs,
   tree-sitter,
 }:
-stdenv.mkDerivation {
-  pname = "yts-grammar";
-  version = "1.0.0";
+tree-sitter.buildGrammar {
+  language = "yts";
+  version = "0.0.1+rev=0bb9a60";
 
   inherit (yt) src;
   sourceRoot = "yt/tree-sitter-yts";
-
-  nativeBuildInputs = [nodejs tree-sitter];
-
-  CFLAGS = ["-Isrc" "-O2"];
-  CXXFLAGS = ["-Isrc" "-O2"];
-
-  stripDebugList = ["parser"];
-
-  configurePhase = ''
-    tree-sitter generate
-  '';
-
-  # When both scanner.{c,cc} exist, we should not link both since they may be the same but in
-  # different languages. Just randomly prefer C++ if that happens.
-  buildPhase = ''
-    runHook preBuild
-    if [[ -e src/scanner.cc ]]; then
-      $CXX -fPIC -c src/scanner.cc -o scanner.o $CXXFLAGS
-    elif [[ -e src/scanner.c ]]; then
-      $CC -fPIC -c src/scanner.c -o scanner.o $CFLAGS
-    fi
-    $CC -fPIC -c src/parser.c -o parser.o $CFLAGS
-    rm -rf parser
-    $CXX -shared -o parser *.o
-    runHook postBuild
-  '';
-
-  installPhase = ''
-    runHook preInstall
-    mkdir $out
-    mv parser $out/
-    if [[ -d queries ]]; then
-      cp -r queries $out
-    fi
-    runHook postInstall
-  '';
 }
diff --git a/pkgs/by-name/ts/tskm/.envrc b/pkgs/by-name/ts/tskm/.envrc
index 2c7bb7c9..a84d550d 100644
--- a/pkgs/by-name/ts/tskm/.envrc
+++ b/pkgs/by-name/ts/tskm/.envrc
@@ -13,3 +13,6 @@
 export TSKM_PROJECT_FILE=/home/soispha/repos/nix/config/modules/common/projects.json
 
 use flake
+
+PATH_add ./target/debug
+PATH_add ./target/release
diff --git a/pkgs/by-name/ts/tskm/Cargo.lock b/pkgs/by-name/ts/tskm/Cargo.lock
index 92ccbe20..2e253ebd 100644
--- a/pkgs/by-name/ts/tskm/Cargo.lock
+++ b/pkgs/by-name/ts/tskm/Cargo.lock
@@ -1,3 +1,5 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
 # nixos-config - My current NixOS configuration
 #
 # Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
@@ -7,22 +9,19 @@
 #
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
 version = 4
 
 [[package]]
 name = "adler2"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
 
 [[package]]
 name = "ahash"
-version = "0.8.11"
+version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -31,12 +30,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "android-tzdata"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
-
-[[package]]
 name = "android_system_properties"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -47,9 +40,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.18"
+version = "0.6.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -62,62 +55,68 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.10"
+version = "1.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
 dependencies = [
  "anstyle",
- "once_cell",
- "windows-sys",
+ "once_cell_polyfill",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.98"
+version = "1.0.100"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
+
+[[package]]
+name = "arraydeque"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
+checksum = "7d902e3d592a523def97af8f317b08ce16b7ab854c1985a0c671e6f15cebc236"
 
 [[package]]
 name = "autocfg"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
 
 [[package]]
 name = "bitflags"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
 
 [[package]]
 name = "bumpalo"
-version = "3.17.0"
+version = "3.19.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
 
 [[package]]
 name = "byteorder"
@@ -127,26 +126,26 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.2.20"
+version = "1.2.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04da6a0d40b948dfc4fa8f5bbf402b0fc1a64a28dbf7d12ffd683550f2c1b63a"
+checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932"
 dependencies = [
+ "find-msvc-tools",
  "shlex",
 ]
 
 [[package]]
 name = "cfg-if"
-version = "1.0.0"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
 
 [[package]]
 name = "chrono"
-version = "0.4.40"
+version = "0.4.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
+checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
 dependencies = [
- "android-tzdata",
  "iana-time-zone",
  "js-sys",
  "num-traits",
@@ -157,9 +156,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
+checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -167,9 +166,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.37"
+version = "4.5.54"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
+checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
 dependencies = [
  "anstream",
  "anstyle",
@@ -179,9 +178,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.47"
+version = "4.5.65"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c06f5378ea264ad4f82bbc826628b5aad714a75abf6ece087e923010eb937fb6"
+checksum = "430b4dc2b5e3861848de79627b2bedc9f3342c7da5173a14eaa5d0f8dc18ae5d"
 dependencies = [
  "clap",
  "clap_lex",
@@ -191,9 +190,9 @@ dependencies = [
 
 [[package]]
 name = "clap_derive"
-version = "4.5.32"
+version = "4.5.49"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
+checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -203,15 +202,15 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.7.4"
+version = "0.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
+checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
 
 [[package]]
 name = "core-foundation-sys"
@@ -221,9 +220,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "crc32fast"
-version = "1.4.2"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
+checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511"
 dependencies = [
  "cfg-if",
 ]
@@ -246,7 +245,7 @@ dependencies = [
  "libc",
  "option-ext",
  "redox_users",
- "windows-sys",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
@@ -261,6 +260,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "encoding_rs"
+version = "0.8.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
 name = "fallible-iterator"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -273,45 +281,57 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
 
 [[package]]
+name = "find-msvc-tools"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db"
+
+[[package]]
 name = "flate2"
-version = "1.1.1"
+version = "1.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
 ]
 
 [[package]]
+name = "foldhash"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
+
+[[package]]
 name = "form_urlencoded"
-version = "1.2.1"
+version = "1.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
 dependencies = [
  "percent-encoding",
 ]
 
 [[package]]
 name = "getrandom"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
+checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
 dependencies = [
  "cfg-if",
  "libc",
- "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasi",
 ]
 
 [[package]]
 name = "getrandom"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
 dependencies = [
  "cfg-if",
  "libc",
  "r-efi",
- "wasi 0.14.2+wasi-0.2.4",
+ "wasip2",
 ]
 
 [[package]]
@@ -324,12 +344,30 @@ dependencies = [
 ]
 
 [[package]]
+name = "hashbrown"
+version = "0.15.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
+dependencies = [
+ "foldhash",
+]
+
+[[package]]
 name = "hashlink"
 version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
 dependencies = [
- "hashbrown",
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
+dependencies = [
+ "hashbrown 0.15.5",
 ]
 
 [[package]]
@@ -340,15 +378,15 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "hermit-abi"
-version = "0.5.0"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.63"
+version = "0.1.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8"
+checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -370,21 +408,22 @@ dependencies = [
 
 [[package]]
 name = "icu_collections"
-version = "1.5.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
 dependencies = [
  "displaydoc",
+ "potential_utf",
  "yoke",
  "zerofrom",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_locid"
-version = "1.5.0"
+name = "icu_locale_core"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
 dependencies = [
  "displaydoc",
  "litemap",
@@ -394,103 +433,65 @@ dependencies = [
 ]
 
 [[package]]
-name = "icu_locid_transform"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_locid_transform_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform_data"
-version = "1.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d"
-
-[[package]]
 name = "icu_normalizer"
-version = "1.5.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
 dependencies = [
- "displaydoc",
  "icu_collections",
  "icu_normalizer_data",
  "icu_properties",
  "icu_provider",
  "smallvec",
- "utf16_iter",
- "utf8_iter",
- "write16",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_normalizer_data"
-version = "1.5.1"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7"
+checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
 
 [[package]]
 name = "icu_properties"
-version = "1.5.1"
+version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
 dependencies = [
- "displaydoc",
  "icu_collections",
- "icu_locid_transform",
+ "icu_locale_core",
  "icu_properties_data",
  "icu_provider",
- "tinystr",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_properties_data"
-version = "1.5.1"
+version = "2.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2"
+checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
 
 [[package]]
 name = "icu_provider"
-version = "1.5.0"
+version = "2.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
 dependencies = [
  "displaydoc",
- "icu_locid",
- "icu_provider_macros",
- "stable_deref_trait",
- "tinystr",
+ "icu_locale_core",
  "writeable",
  "yoke",
  "zerofrom",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_provider_macros"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
 name = "idna"
-version = "1.0.3"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
+checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
 dependencies = [
  "idna_adapter",
  "smallvec",
@@ -499,9 +500,9 @@ dependencies = [
 
 [[package]]
 name = "idna_adapter"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
 dependencies = [
  "icu_normalizer",
  "icu_properties",
@@ -509,41 +510,41 @@ dependencies = [
 
 [[package]]
 name = "is-terminal"
-version = "0.4.16"
+version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
+checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
 dependencies = [
  "hermit-abi",
  "libc",
- "windows-sys",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
 name = "is_executable"
-version = "1.0.4"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2"
+checksum = "baabb8b4867b26294d818bf3f651a454b6901431711abb96e296245888d6e8c4"
 dependencies = [
- "winapi",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
 name = "is_terminal_polyfill"
-version = "1.70.1"
+version = "1.70.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
+checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
 
 [[package]]
 name = "itoa"
-version = "1.0.15"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
 
 [[package]]
 name = "js-sys"
-version = "0.3.77"
+version = "0.3.85"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
+checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3"
 dependencies = [
  "once_cell",
  "wasm-bindgen",
@@ -551,15 +552,15 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.172"
+version = "0.2.180"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
 
 [[package]]
 name = "libredox"
-version = "0.1.3"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
 dependencies = [
  "bitflags",
  "libc",
@@ -577,38 +578,36 @@ dependencies = [
 
 [[package]]
 name = "litemap"
-version = "0.7.5"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
+checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
 
 [[package]]
 name = "log"
-version = "0.4.27"
+version = "0.4.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
+checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
 
 [[package]]
-name = "lz4_flex"
-version = "0.11.3"
+name = "md5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
-dependencies = [
- "twox-hash",
-]
+checksum = "ae960838283323069879657ca3de837e9f7bbb4c7bf6ea7f1b290d5e9476d2e0"
 
 [[package]]
 name = "memchr"
-version = "2.7.4"
+version = "2.7.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.8"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
 dependencies = [
  "adler2",
+ "simd-adler32",
 ]
 
 [[package]]
@@ -627,6 +626,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
+name = "once_cell_polyfill"
+version = "1.70.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
+
+[[package]]
 name = "option-ext"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -634,9 +639,9 @@ checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.1"
+version = "2.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
 
 [[package]]
 name = "pkg-config"
@@ -645,36 +650,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
 
 [[package]]
+name = "potential_utf"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
+dependencies = [
+ "zerovec",
+]
+
+[[package]]
 name = "proc-macro2"
-version = "1.0.95"
+version = "1.0.105"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "quote"
-version = "1.0.40"
+version = "1.0.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "r-efi"
-version = "5.2.0"
+version = "5.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
 
 [[package]]
 name = "redox_users"
-version = "0.5.0"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
+checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
 dependencies = [
- "getrandom 0.2.16",
+ "getrandom 0.2.17",
  "libredox",
  "thiserror",
 ]
@@ -688,22 +702,16 @@ dependencies = [
  "bitflags",
  "fallible-iterator",
  "fallible-streaming-iterator",
- "hashlink",
+ "hashlink 0.9.1",
  "libsqlite3-sys",
  "smallvec",
 ]
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
-
-[[package]]
-name = "ryu"
-version = "1.0.20"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
 
 [[package]]
 name = "same-file"
@@ -716,18 +724,28 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.219"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.219"
+version = "1.0.228"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -736,14 +754,15 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.140"
+version = "1.0.149"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
 dependencies = [
  "itoa",
  "memchr",
- "ryu",
  "serde",
+ "serde_core",
+ "zmij",
 ]
 
 [[package]]
@@ -753,22 +772,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
-name = "smallvec"
-version = "1.15.0"
+name = "simd-adler32"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2"
 
 [[package]]
-name = "stable_deref_trait"
-version = "1.2.0"
+name = "smallvec"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
 
 [[package]]
-name = "static_assertions"
-version = "1.1.0"
+name = "stable_deref_trait"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
 
 [[package]]
 name = "stderrlog"
@@ -776,7 +795,6 @@ version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "61c910772f992ab17d32d6760e167d2353f4130ed50e796752689556af07dc6b"
 dependencies = [
- "chrono",
  "is-terminal",
  "log",
  "termcolor",
@@ -791,28 +809,27 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "strum"
-version = "0.27.1"
+version = "0.27.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32"
+checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf"
 
 [[package]]
 name = "strum_macros"
-version = "0.27.1"
+version = "0.27.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8"
+checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7"
 dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "rustversion",
  "syn",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.114"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -821,9 +838,9 @@ dependencies = [
 
 [[package]]
 name = "synstructure"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -861,18 +878,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "2.0.12"
+version = "2.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
+checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "2.0.12"
+version = "2.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
+checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -881,19 +898,18 @@ dependencies = [
 
 [[package]]
 name = "thread_local"
-version = "1.1.8"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
 dependencies = [
  "cfg-if",
- "once_cell",
 ]
 
 [[package]]
 name = "tinystr"
-version = "0.7.6"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
 dependencies = [
  "displaydoc",
  "zerovec",
@@ -908,50 +924,36 @@ dependencies = [
  "clap_complete",
  "dirs",
  "log",
- "lz4_flex",
+ "md5",
  "serde",
  "serde_json",
  "stderrlog",
  "taskchampion",
  "url",
  "walkdir",
-]
-
-[[package]]
-name = "twox-hash"
-version = "1.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
-dependencies = [
- "cfg-if",
- "static_assertions",
+ "yaml-rust2",
 ]
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.18"
+version = "1.0.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
 
 [[package]]
 name = "url"
-version = "2.5.4"
+version = "2.5.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
+checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed"
 dependencies = [
  "form_urlencoded",
  "idna",
  "percent-encoding",
  "serde",
+ "serde_derive",
 ]
 
 [[package]]
-name = "utf16_iter"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
-
-[[package]]
 name = "utf8_iter"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -965,12 +967,14 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
 name = "uuid"
-version = "1.16.0"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
 dependencies = [
- "getrandom 0.3.2",
- "serde",
+ "getrandom 0.3.4",
+ "js-sys",
+ "serde_core",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -997,50 +1001,37 @@ dependencies = [
 
 [[package]]
 name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
 
 [[package]]
-name = "wasi"
-version = "0.14.2+wasi-0.2.4"
+name = "wasip2"
+version = "1.0.2+wasi-0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5"
 dependencies = [
- "wit-bindgen-rt",
+ "wit-bindgen",
 ]
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
+checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566"
 dependencies = [
  "cfg-if",
  "once_cell",
  "rustversion",
  "wasm-bindgen-macro",
-]
-
-[[package]]
-name = "wasm-bindgen-backend"
-version = "0.2.100"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
-dependencies = [
- "bumpalo",
- "log",
- "proc-macro2",
- "quote",
- "syn",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
+checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1048,62 +1039,40 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
+checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55"
 dependencies = [
+ "bumpalo",
  "proc-macro2",
  "quote",
  "syn",
- "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.100"
+version = "0.2.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
+checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
 name = "winapi-util"
-version = "0.1.9"
+version = "0.1.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
 dependencies = [
- "windows-sys",
+ "windows-sys 0.61.2",
 ]
 
 [[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
 name = "windows-core"
-version = "0.61.0"
+version = "0.62.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
+checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
 dependencies = [
  "windows-implement",
  "windows-interface",
@@ -1114,9 +1083,9 @@ dependencies = [
 
 [[package]]
 name = "windows-implement"
-version = "0.60.0"
+version = "0.60.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
+checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1125,9 +1094,9 @@ dependencies = [
 
 [[package]]
 name = "windows-interface"
-version = "0.59.1"
+version = "0.59.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
+checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1136,43 +1105,53 @@ dependencies = [
 
 [[package]]
 name = "windows-link"
-version = "0.1.1"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
 
 [[package]]
 name = "windows-result"
-version = "0.3.2"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-strings"
-version = "0.4.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-sys"
-version = "0.59.0"
+version = "0.60.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
 dependencies = [
  "windows-targets",
 ]
 
 [[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
 name = "windows-targets"
-version = "0.52.6"
+version = "0.53.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
 dependencies = [
+ "windows-link",
  "windows_aarch64_gnullvm",
  "windows_aarch64_msvc",
  "windows_i686_gnu",
@@ -1185,80 +1164,81 @@ dependencies = [
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
 
 [[package]]
 name = "windows_i686_gnullvm"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.6"
+version = "0.53.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
 
 [[package]]
-name = "wit-bindgen-rt"
-version = "0.39.0"
+name = "wit-bindgen"
+version = "0.51.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
-dependencies = [
- "bitflags",
-]
+checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
 
 [[package]]
-name = "write16"
-version = "1.0.0"
+name = "writeable"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
+checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
 
 [[package]]
-name = "writeable"
-version = "0.5.5"
+name = "yaml-rust2"
+version = "0.10.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+checksum = "2462ea039c445496d8793d052e13787f2b90e750b833afee748e601c17621ed9"
+dependencies = [
+ "arraydeque",
+ "encoding_rs",
+ "hashlink 0.10.0",
+]
 
 [[package]]
 name = "yoke"
-version = "0.7.5"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
 dependencies = [
- "serde",
  "stable_deref_trait",
  "yoke-derive",
  "zerofrom",
@@ -1266,9 +1246,9 @@ dependencies = [
 
 [[package]]
 name = "yoke-derive"
-version = "0.7.5"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1278,18 +1258,18 @@ dependencies = [
 
 [[package]]
 name = "zerocopy"
-version = "0.7.35"
+version = "0.8.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
+checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.7.35"
+version = "0.8.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
+checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1318,10 +1298,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "zerotrie"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
 name = "zerovec"
-version = "0.10.4"
+version = "0.11.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
 dependencies = [
  "yoke",
  "zerofrom",
@@ -1330,11 +1321,17 @@ dependencies = [
 
 [[package]]
 name = "zerovec-derive"
-version = "0.10.3"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
+
+[[package]]
+name = "zmij"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2"
diff --git a/pkgs/by-name/ts/tskm/Cargo.toml b/pkgs/by-name/ts/tskm/Cargo.toml
index d9d69b53..49774037 100644
--- a/pkgs/by-name/ts/tskm/Cargo.toml
+++ b/pkgs/by-name/ts/tskm/Cargo.toml
@@ -16,18 +16,19 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-anyhow = "1.0.98"
-clap = { version = "4.5.37", features = ["derive"] }
-clap_complete = { version = "4.5.47", features = ["unstable-dynamic"] }
-dirs = "6.0.0"
-log = "0.4.27"
-lz4_flex = "0.11.3"
-serde = { version = "1.0.219", features = ["derive"] }
-serde_json = "1.0.140"
-stderrlog = "0.6.0"
+anyhow = { version = "1.0.100", default-features = false }
+clap = { version = "4.5.54", features = [ "derive", "std", "color", "help", "usage", "error-context", "suggestions", ], default-features = false }
+clap_complete = { version = "4.5.65", features = ["unstable-dynamic"] }
+dirs = { version = "6.0.0", default-features = false }
+log = { version = "0.4.29", default-features = false }
+serde = { version = "1.0.228", features = ["derive"], default-features = false }
+serde_json = { version = "1.0.149", default-features = false }
+stderrlog = { version = "0.6.0", default-features = false }
 taskchampion = { version = "2.0.3", default-features = false }
-url = { version = "2.5.4", features = ["serde"] }
-walkdir = "2.5.0"
+url = { version = "2.5.8", features = ["serde", "std"], default-features = false }
+walkdir = { version = "2.5.0", default-features = false }
+md5 = { version = "0.8.0", default-features = false }
+yaml-rust2 = "0.10.4"
 
 [profile.release]
 lto = true
diff --git a/pkgs/by-name/ts/tskm/flake.lock b/pkgs/by-name/ts/tskm/flake.lock
index 07eb6b21..1e997998 100644
--- a/pkgs/by-name/ts/tskm/flake.lock
+++ b/pkgs/by-name/ts/tskm/flake.lock
@@ -2,11 +2,11 @@
   "nodes": {
     "nixpkgs": {
       "locked": {
-        "lastModified": 1745377448,
-        "narHash": "sha256-jhZDfXVKdD7TSEGgzFJQvEEZ2K65UMiqW5YJ2aIqxMA=",
+        "lastModified": 1768661221,
+        "narHash": "sha256-MJwOjrIISfOpdI9x4C+5WFQXvHtOuj5mqLZ4TMEtk1M=",
         "owner": "NixOS",
         "repo": "nixpkgs",
-        "rev": "507b63021ada5fee621b6ca371c4fca9ca46f52c",
+        "rev": "3327b113f2ef698d380df83fbccefad7e83d7769",
         "type": "github"
       },
       "original": {
diff --git a/pkgs/by-name/ts/tskm/flake.nix b/pkgs/by-name/ts/tskm/flake.nix
index 583d4923..6217f942 100644
--- a/pkgs/by-name/ts/tskm/flake.nix
+++ b/pkgs/by-name/ts/tskm/flake.nix
@@ -23,13 +23,13 @@
         pkgs.sqlite
       ];
 
-      packages = with pkgs; [
-        cargo
-        clippy
-        rustc
-        rustfmt
+      packages = [
+        pkgs.cargo
+        pkgs.clippy
+        pkgs.rustc
+        pkgs.rustfmt
 
-        cargo-edit
+        pkgs.cargo-edit
       ];
     };
   };
diff --git a/pkgs/by-name/ts/tskm/package.nix b/pkgs/by-name/ts/tskm/package.nix
index d75afe6e..ad10865f 100644
--- a/pkgs/by-name/ts/tskm/package.nix
+++ b/pkgs/by-name/ts/tskm/package.nix
@@ -16,7 +16,6 @@
   taskwarrior3,
   git,
   rofi,
-  firefox,
   sqlite,
 }:
 rustPlatform.buildRustPackage (finalAttrs: {
@@ -32,7 +31,6 @@ rustPlatform.buildRustPackage (finalAttrs: {
     taskwarrior3
     git
     rofi
-    firefox
     sqlite
   ];
 
diff --git a/pkgs/by-name/ts/tskm/src/browser/mod.rs b/pkgs/by-name/ts/tskm/src/browser/mod.rs
new file mode 100644
index 00000000..2129982f
--- /dev/null
+++ b/pkgs/by-name/ts/tskm/src/browser/mod.rs
@@ -0,0 +1,202 @@
+use std::{
+    env, fs,
+    io::Write,
+    os::unix::net::UnixStream,
+    path::PathBuf,
+    process::{self, ExitStatus},
+};
+
+use anyhow::{Context, Result};
+use log::{error, info};
+use serde_json::json;
+use url::Url;
+
+use crate::{state::State, task};
+
+#[allow(clippy::too_many_lines)]
+pub fn open_in_browser<U>(
+    selected_project: &task::Project,
+    state: &mut State,
+    urls: Option<Vec<U>>,
+) -> Result<()>
+where
+    U: Into<Url>,
+{
+    let old_project: Option<task::Project> =
+        task::Project::get_current().context("Failed to get currently active project")?;
+    let old_task: Option<task::Task> =
+        task::Task::get_current(state).context("Failed to get currently active task")?;
+
+    selected_project.activate().with_context(|| {
+        format!(
+            "Failed to active project: '{}'",
+            selected_project.to_project_display()
+        )
+    })?;
+
+    let tracking_task = {
+        let all_tasks = selected_project.get_tasks(state).with_context(|| {
+            format!(
+                "Failed to get assoctiated tasks for project: '{}'",
+                selected_project.to_project_display()
+            )
+        })?;
+
+        let tracking_task = all_tasks.into_iter().find(|t| {
+            let maybe_desc = t.description(state);
+            if let Ok(desc) = maybe_desc {
+                desc == "tracking"
+            } else {
+                error!(
+                    "Getting task description returned error: {}",
+                    maybe_desc.expect_err("We already check for Ok")
+                );
+                false
+            }
+        });
+
+        if let Some(task) = tracking_task {
+            info!(
+                "Starting task {} -> tracking",
+                selected_project.to_project_display()
+            );
+            task.start(state)
+                .with_context(|| format!("Failed to start task {task}"))?;
+        }
+        tracking_task
+    };
+
+    let status = {
+        // #!/bin/sh
+        // # initial idea: Florian Bruhin (The-Compiler)
+        // # author: Thore Bödecker (foxxx0)
+        //
+        // _url="$1"
+        // _qb_version='1.0.4'
+        // _proto_version=1
+        // _ipc_socket="${XDG_RUNTIME_DIR}/qutebrowser/ipc-$(printf '%s' "$USER" | md5sum | cut -d' ' -f1)"
+        // _qute_bin="/usr/bin/qutebrowser"
+        //
+        // printf '{"args": ["%s"], "target_arg": null, "version": "%s", "protocol_version": %d, "cwd": "%s"}\n' \
+        //        "${_url}" \
+        //        "${_qb_version}" \
+        //        "${_proto_version}" \
+        //        "${PWD}" | socat -lf /dev/null - UNIX-CONNECT:"${_ipc_socket}" || "$_qute_bin" "$@" &
+
+        let ipc_socket_path = PathBuf::from(
+            env::var("XDG_RUNTIME_DIR").context("Failed to access XDG_RUNTIME_DIR var")?,
+        )
+        .join("qutebrowser")
+        .join(selected_project.to_project_display())
+        .join(format!("ipc-{:x}", {
+            let user_name = env::var("USER").context("Failed to get USER var")?;
+            let base_dir = env::var("XDG_DATA_HOME").context("Failed to get XDG_DATA_HOME")?;
+
+            md5::compute(
+                format!(
+                    "{user_name}-{}",
+                    PathBuf::from(base_dir)
+                        .join("qutebrowser")
+                        .join(selected_project.to_project_display())
+                        .display()
+                )
+                .as_bytes(),
+            )
+        }));
+
+        let socket = if ipc_socket_path.exists() {
+            match UnixStream::connect(&ipc_socket_path) {
+                Ok(ok) => Some(ok),
+                Err(err) => match err.kind() {
+                    std::io::ErrorKind::ConnectionRefused => {
+                        // There is no qutebrowser listening to our connection.
+                        fs::remove_file(&ipc_socket_path).with_context(|| {
+                            format!(
+                                "Failed to remove orphaned qutebrowser socket: {}",
+                                ipc_socket_path.display()
+                            )
+                        })?;
+                        None
+                    }
+                    _ => Err(err).with_context(|| {
+                        format!(
+                            "Failed to connect to qutebrowser's ipc socket at: {}",
+                            ipc_socket_path.display()
+                        )
+                    })?,
+                },
+            }
+        } else {
+            None
+        };
+
+        if let Some(mut stream) = socket {
+            let real_url = if let Some(urls) = urls {
+                urls.into_iter().map(|url| url.into().to_string()).collect()
+            } else {
+                // Always add a new tab, so that qutebrowser is marked as “urgent”.
+                vec!["qute://start".to_owned()]
+            };
+
+            stream.write_all(
+                json! {
+                    {
+                        "args": real_url,
+                        "target_arg": null,
+                        "version": "1.0.4",
+                        "protocol_version": 1,
+                        "cwd": "/"
+                    }
+                }
+                .to_string()
+                .as_bytes(),
+            )?;
+            stream.write_all(b"\n")?;
+
+            ExitStatus::default()
+        } else {
+            let args = if let Some(urls) = urls {
+                urls.into_iter()
+                    .map(Into::<Url>::into)
+                    .map(|u| u.to_string())
+                    .collect()
+            } else {
+                vec![]
+            };
+
+            process::Command::new(format!(
+                "qutebrowser-{}",
+                selected_project.to_project_display()
+            ))
+            .args(args)
+            .status()
+            .context("Failed to start qutebrowser")?
+        }
+    };
+
+    if !status.success() {
+        error!("Qutebrowser run exited with error.");
+    }
+
+    if let Some(task) = tracking_task {
+        task.stop(state)
+            .with_context(|| format!("Failed to stop task {task}"))?;
+    }
+    if let Some(task) = old_task {
+        task.start(state)
+            .with_context(|| format!("Failed to start task {task}"))?;
+    }
+
+    if let Some(project) = old_project {
+        project.activate().with_context(|| {
+            format!(
+                "Failed to activate project {}",
+                project.to_project_display()
+            )
+        })?;
+    } else {
+        task::Project::clear().context("Failed to clear currently focused project")?;
+    }
+
+    Ok(())
+}
diff --git a/pkgs/by-name/ts/tskm/src/cli.rs b/pkgs/by-name/ts/tskm/src/cli.rs
index f38d7879..359c1050 100644
--- a/pkgs/by-name/ts/tskm/src/cli.rs
+++ b/pkgs/by-name/ts/tskm/src/cli.rs
@@ -11,12 +11,15 @@
 use std::{ffi::OsStr, path::PathBuf};
 
 use anyhow::{bail, Result};
-use clap::{builder::StyledStr, ArgAction, Parser, Subcommand};
+use clap::{builder::StyledStr, ArgAction, Parser, Subcommand, ValueEnum};
 use clap_complete::{ArgValueCompleter, CompletionCandidate};
-use url::Url;
 
 use crate::{
-    interface::{input::Input, project::ProjectName},
+    interface::{
+        input::{Input, Tag},
+        open::UrlLike,
+        project::ProjectName,
+    },
     state, task,
 };
 
@@ -25,7 +28,7 @@ use crate::{
 /// This is the core interface to the system-integrated task management
 ///
 /// `tskm` effectively combines multiple applications together:
-/// - `taskwarrior` projects are raised connected to `firefox` profiles, making it possible to “open”
+/// - `taskwarrior` projects are connected to `qutebrowser` profiles, making it possible to “open”
 ///   a project.
 ///
 /// - Every `taskwarrior` project has a determined `neorg` path, so that extra information for a
@@ -66,7 +69,7 @@ pub enum Command {
         command: NeorgCommand,
     },
 
-    /// Interface with the Firefox profile of each project.
+    /// Interface with the Qutebrowser profile of each project.
     Open {
         #[command(subcommand)]
         command: OpenCommand,
@@ -91,8 +94,8 @@ pub enum NeorgCommand {
     /// Open the `neorg` project associated with id of the task.
     Task {
         /// The working set id of the task
-        #[arg(value_parser = task_from_working_set_id, add = ArgValueCompleter::new(complete_task_id))]
-        id: task::Task,
+        #[arg(value_name = "ID", value_parser = task_from_working_set_id, add = ArgValueCompleter::new(complete_task_id))]
+        task: task::Task,
     },
 }
 
@@ -108,38 +111,55 @@ fn task_from_working_set_id(id: &str) -> Result<task::Task> {
 
 #[derive(Subcommand, Debug)]
 pub enum OpenCommand {
-    /// Open each project's Firefox profile consecutively, that was opened since the last review.
+    /// Open each project's Qutebrowser profile consecutively, that was opened since the last review.
     ///
     /// This allows you to remove stale opened tabs and to commit open tabs to the `inputs`.
-    Review,
+    Review {
+        /// Review all projects, if they contain tabs
+        #[arg(short, long, default_value_t)]
+        non_empty: bool,
+    },
 
-    /// Opens Firefox with either the supplied project or the currently active project profile.
+    /// Opens Qutebrowser with either the supplied project or the currently active project profile.
     Project {
         /// The project to open.
         #[arg(value_parser = task::Project::from_project_string, add = ArgValueCompleter::new(complete_project))]
         project: task::Project,
 
-        /// The URL to open.
-        url: Option<Url>,
+        /// The URLs to open.
+        urls: Option<Vec<UrlLike>>,
     },
 
-    /// Open a selected project in it's Firefox profile.
+    /// Open a selected project in it's Qutebrowser profile.
     ///
     /// This will use rofi's dmenu mode to select one project from the list of all registered
     /// projects.
     Select {
-        /// The URL to open.
-        url: Option<Url>,
+        /// The URLs to open.
+        urls: Option<Vec<UrlLike>>,
     },
 
     /// List all open tabs in the project.
     ListTabs {
-        /// The project to open.
+        /// The projects to open.
         #[arg(value_parser = task::Project::from_project_string, add = ArgValueCompleter::new(complete_project))]
-        project: Option<task::Project>,
+        projects: Option<Vec<task::Project>>,
+
+        /// Only show the tabs, that are in this mode
+        #[arg(short, long, conflicts_with = "projects")]
+        mode: Option<ListMode>,
     },
 }
 
+#[derive(Clone, Copy, ValueEnum, Debug)]
+pub enum ListMode {
+    // The tab contains no tabs.
+    Empty,
+
+    // The tab contains tabs.
+    NonEmpty,
+}
+
 #[derive(Subcommand, Debug)]
 pub enum InputCommand {
     /// Add URLs as inputs to be categorized.
@@ -153,7 +173,14 @@ pub enum InputCommand {
     /// Add all URLs in the file as inputs to be categorized.
     ///
     /// This expects each line to contain one URL.
-    File { file: PathBuf },
+    File {
+        /// The file to read from.
+        file: PathBuf,
+
+        /// Additional tags to apply to every read URL in the file.
+        #[arg(add = ArgValueCompleter::new(complete_tag))]
+        tags: Vec<Tag>,
+    },
 
     /// Like 'review', but for the inputs that have previously been added.
     /// It takes a project in which to open the URLs.
@@ -164,7 +191,14 @@ pub enum InputCommand {
     },
 
     /// List all the previously added inputs.
-    List,
+    List {
+        /// Only list the inputs that have all the specified tags
+        #[arg(add = ArgValueCompleter::new(complete_tag))]
+        tags: Vec<Tag>,
+    },
+
+    /// Show all the available tags.
+    Tags {},
 }
 
 fn complete_task_id(current: &OsStr) -> Vec<CompletionCandidate> {
@@ -219,8 +253,6 @@ fn complete_task_id(current: &OsStr) -> Vec<CompletionCandidate> {
                 if project == current_project {
                     if let Some(out) = format_task(task, current, &mut state) {
                         output.push(out);
-                    } else {
-                        continue;
                     }
                 }
             }
@@ -274,3 +306,27 @@ fn complete_input_url(current: &OsStr) -> Vec<CompletionCandidate> {
 
     output
 }
+fn complete_tag(current: &OsStr) -> Vec<CompletionCandidate> {
+    let mut output = vec![];
+
+    let Some(current) = current.to_str() else {
+        return output;
+    };
+
+    if !current.starts_with('+') {
+        output.push(CompletionCandidate::new(format!("+{current}")));
+    }
+
+    output
+}
+
+#[cfg(test)]
+mod test {
+    use clap::CommandFactory;
+
+    use super::CliArgs;
+    #[test]
+    fn verify_cli() {
+        CliArgs::command().debug_assert();
+    }
+}
diff --git a/pkgs/by-name/ts/tskm/src/interface/input/handle.rs b/pkgs/by-name/ts/tskm/src/interface/input/handle.rs
index 9c39cfef..76eea6dc 100644
--- a/pkgs/by-name/ts/tskm/src/interface/input/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/input/handle.rs
@@ -9,25 +9,25 @@
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
 use std::{
-    fs, process,
+    collections::{HashMap, HashSet},
+    fs,
     str::FromStr,
-    thread::{self, sleep},
-    time::Duration,
 };
 
 use anyhow::{Context, Result};
-use log::{error, info};
+use log::info;
 
-use crate::cli::InputCommand;
+use crate::{browser::open_in_browser, cli::InputCommand, state::State};
 
-use super::Input;
+use super::{Input, Tag};
 
 /// # Errors
 /// When command handling fails.
 ///
 /// # Panics
 /// When internal assertions fail.
-pub fn handle(command: InputCommand) -> Result<()> {
+#[allow(clippy::too_many_lines)]
+pub fn handle(command: InputCommand, state: &mut State) -> Result<()> {
     match command {
         InputCommand::Add { inputs } => {
             for input in inputs {
@@ -43,47 +43,37 @@ pub fn handle(command: InputCommand) -> Result<()> {
                 })?;
             }
         }
-        InputCommand::File { file } => {
-            let file = fs::read_to_string(file)?;
-            for line in file.lines() {
-                let input = Input::from_str(line)?;
+        InputCommand::File { file, tags } => {
+            let file = fs::read_to_string(&file)
+                .with_context(|| format!("Failed to read input file '{}'", file.display()))?;
+
+            let mut tag_set = HashSet::with_capacity(tags.len());
+            for tag in tags {
+                tag_set.insert(tag);
+            }
+
+            for line in file.lines().map(str::trim) {
+                if line.is_empty() {
+                    continue;
+                }
+
+                let mut input = Input::from_str(line)?;
+                input.tags = input.tags.union(&tag_set).cloned().collect();
+
                 input.commit().with_context(|| {
                     format!("Failed to add input ('{input}') to the input storage.")
                 })?;
             }
         }
         InputCommand::Review { project } => {
-            let project = project.to_project_display();
-
-            let local_project = project.clone();
-            let handle = thread::spawn(move || {
-                // We assume that the project is not yet open.
-                let mut firefox = process::Command::new("firefox")
-                    .args(["-P", local_project.as_str(), "about:newtab"])
-                    .spawn()?;
-
-                Ok::<_, anyhow::Error>(firefox.wait()?)
-            });
-            // Give Firefox some time to start.
-            info!("Waiting on firefox to start");
-            sleep(Duration::from_secs(4));
-
-            let project_str = project.as_str();
             'outer: for all in Input::all()?.chunks(100) {
                 info!("Starting review for the first hundred URLs.");
 
-                for input in all {
-                    info!("-> '{input}'");
-                    let status = process::Command::new("firefox")
-                        .args(["-P", project_str, input.url().to_string().as_str()])
-                        .status()?;
-
-                    if status.success() {
-                        input.remove()?;
-                    } else {
-                        error!("Adding `{input}` to Firefox failed!");
-                    }
-                }
+                open_in_browser(
+                    &project,
+                    state,
+                    Some(all.iter().map(|f| f.url.clone()).collect()),
+                )?;
 
                 {
                     use std::io::{stdin, stdout, Write};
@@ -108,15 +98,51 @@ pub fn handle(command: InputCommand) -> Result<()> {
                     }
                 }
             }
-
-            info!("Waiting for firefox to stop");
-            handle.join().expect("Should be joinable")?;
         }
-        InputCommand::List => {
-            for url in Input::all()? {
+        InputCommand::List { tags } => {
+            let mut tag_set = HashSet::with_capacity(tags.len());
+            for tag in tags {
+                tag_set.insert(tag);
+            }
+
+            for url in Input::all()?
+                .iter()
+                .filter(|input| tag_set.is_subset(&input.tags))
+            {
                 println!("{url}");
             }
         }
+        InputCommand::Tags {} => {
+            let mut without_tags = 0;
+            let mut tag_set: HashMap<Tag, u64> = HashMap::new();
+
+            for input in Input::all()? {
+                if input.tags.is_empty() {
+                    without_tags += 1;
+                }
+
+                for tag in input.tags {
+                    if let Some(number) = tag_set.get_mut(&tag) {
+                        *number += 1;
+                    } else {
+                        tag_set.insert(tag, 1);
+                    }
+                }
+            }
+
+            let mut tags: Vec<(Tag, u64)> = tag_set.into_iter().collect();
+            tags.sort_by_key(|(_, number)| *number);
+            tags.reverse();
+
+            for (tag, number) in tags {
+                println!("{tag} {number}");
+            }
+
+            if without_tags != 0 {
+                println!();
+                println!("Witohut tags: {without_tags}");
+            }
+        }
     }
     Ok(())
 }
diff --git a/pkgs/by-name/ts/tskm/src/interface/input/mod.rs b/pkgs/by-name/ts/tskm/src/interface/input/mod.rs
index 5485de3b..1d1d67f4 100644
--- a/pkgs/by-name/ts/tskm/src/interface/input/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/input/mod.rs
@@ -9,9 +9,9 @@
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
 use std::{
-    collections::HashSet,
+    collections::{HashMap, HashSet},
     fmt::Display,
-    fs::{self, read_to_string, File},
+    fs,
     io::Write,
     path::PathBuf,
     process::Command,
@@ -26,38 +26,47 @@ pub mod handle;
 pub use handle::handle;
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct NoWhitespaceString(String);
+pub struct Tag(String);
 
-impl NoWhitespaceString {
-    /// # Panics
-    /// If the input contains whitespace.
-    #[must_use]
-    pub fn new(input: String) -> Self {
-        if input.contains(' ') {
-            panic!("Your input '{input}' contains whitespace. I did not expect that.")
+impl Tag {
+    pub fn new(input: &str) -> Result<Self> {
+        Self::from_str(input)
+    }
+}
+
+impl FromStr for Tag {
+    type Err = anyhow::Error;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        if let Some(tag) = s.strip_prefix('+') {
+            if tag.contains(' ') {
+                bail!("Your tag '{s}' should not whitespace.")
+            }
+
+            Ok(Self(tag.to_owned()))
         } else {
-            Self(input)
+            bail!("Your tag '{s}' does not start with the required '+'");
         }
     }
 }
 
-impl Display for NoWhitespaceString {
+impl Display for Tag {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.0.fmt(f)
+        write!(f, "+{}", self.0)
     }
 }
 
-impl NoWhitespaceString {
+impl Tag {
     #[must_use]
     pub fn as_str(&self) -> &str {
         &self.0
     }
 }
 
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Input {
     url: Url,
-    tags: HashSet<NoWhitespaceString>,
+    tags: HashSet<Tag>,
 }
 
 impl FromStr for Input {
@@ -71,13 +80,7 @@ impl FromStr for Input {
                 tags: {
                     tags.trim()
                         .split(' ')
-                        .map(|tag| {
-                            if let Some(tag) = tag.strip_prefix('+') {
-                                Ok(NoWhitespaceString::new(tag.to_owned()))
-                            } else {
-                                bail!("Your tag '{tag}' does not start with the required '+'");
-                            }
-                        })
+                        .map(Tag::new)
                         .collect::<Result<_, _>>()?
                 },
             })
@@ -101,13 +104,9 @@ impl Display for Input {
                 self.url,
                 self.tags
                     .iter()
-                    .fold(String::new(), |mut acc, tag| {
-                        acc.push('+');
-                        acc.push_str(tag.as_str());
-                        acc.push(' ');
-                        acc
-                    })
-                    .trim()
+                    .map(ToString::to_string)
+                    .collect::<Vec<_>>()
+                    .join(" ")
             )
         }
     }
@@ -123,7 +122,10 @@ impl Input {
     fn url_path(url: &Url) -> Result<PathBuf> {
         let base_path = Self::base_path();
 
-        let url_path = base_path.join(url.to_string());
+        let url_path = base_path
+            .join(url.scheme())
+            .join(url.host_str().unwrap_or("<No Host>"))
+            .join(url.path().trim_matches('/'));
         fs::create_dir_all(&url_path)
             .with_context(|| format!("Failed to open file: '{}'", url_path.display()))?;
 
@@ -142,17 +144,12 @@ impl Input {
     pub fn commit(&self) -> Result<()> {
         let url_path = Self::url_path(&self.url)?;
 
-        let url_content = {
-            if url_path.exists() {
-                read_to_string(&url_path)?
-            } else {
-                String::new()
-            }
-        };
-
-        let mut file = File::create(&url_path)
+        let mut file = fs::OpenOptions::new()
+            .create(true)
+            .append(true)
+            .open(&url_path)
             .with_context(|| format!("Failed to open file: '{}'", url_path.display()))?;
-        writeln!(file, "{url_content}{self}")?;
+        writeln!(file, "{self}")?;
 
         Self::git_commit(&format!("Add new url: '{self}'"))?;
 
@@ -183,28 +180,7 @@ impl Input {
         Ok(())
     }
 
-    /// Commit your changes
-    fn git_commit(message: &str) -> Result<()> {
-        let status = Command::new("git")
-            .args(["add", "."])
-            .current_dir(Self::base_path())
-            .status()?;
-        if !status.success() {
-            bail!("Git add . failed!");
-        }
-
-        let status = Command::new("git")
-            .args(["commit", "--message", message, "--no-gpg-sign"])
-            .current_dir(Self::base_path())
-            .status()?;
-        if !status.success() {
-            bail!("Git commit failed!");
-        }
-
-        Ok(())
-    }
-
-    /// Get all previously [`Self::commit`]ed inputs.
+    /// Get all previously [committed][`Self::commit`] inputs.
     ///
     /// # Errors
     /// When IO handling fails.
@@ -227,41 +203,58 @@ impl Input {
                 continue;
             }
 
-            let url_value_file = entry
-                .path()
-                .to_str()
-                .expect("All of these should be URLs and thus valid strings");
-            assert!(url_value_file.ends_with("/url_value"));
-
-            let url = {
-                let base = url_value_file
-                    .strip_prefix(&format!("{}/", Self::base_path().display()))
-                    .expect("This will exist");
-
-                let (proto, path) = base.split_once(':').expect("This will countain a :");
-
-                let path = path.strip_suffix("/url_value").expect("Will exist");
-
-                Url::from_str(&format!("{proto}:/{path}"))
-                    .expect("This was a URL, it should still be one")
-            };
-            let tags = {
-                let url_values = read_to_string(PathBuf::from(url_value_file))?;
-                url_values
-                    .lines()
-                    .map(|line| {
-                        let input = Self::from_str(line)?;
-                        Ok::<_, anyhow::Error>(input.tags)
-                    })
-                    .collect::<Result<Vec<HashSet<NoWhitespaceString>>, _>>()?
-                    .into_iter()
-                    .flatten()
-                    .collect()
-            };
-
-            output.push(Self { url, tags });
+            let url_value_file = entry.path();
+            assert!(url_value_file.ends_with("url_value"));
+
+            let url_values = fs::read_to_string(PathBuf::from(url_value_file))?;
+
+            let mut inputs: HashMap<Url, Self> = HashMap::new();
+            for input in url_values
+                .lines()
+                .map(Self::from_str)
+                .collect::<Result<Vec<Self>, _>>()?
+            {
+                if let Some(found) = inputs.get_mut(&input.url) {
+                    found.tags = found.tags.union(&input.tags).cloned().collect();
+                } else {
+                    assert_eq!(inputs.insert(input.url.clone(), input), None);
+                }
+            }
+
+            output.extend(inputs.drain().map(|(_, value)| value));
         }
 
         Ok(output)
     }
+
+    /// Commit your changes
+    fn git_commit(message: &str) -> Result<()> {
+        if !Self::base_path().join(".git").exists() {
+            let status = Command::new("git")
+                .args(["init"])
+                .current_dir(Self::base_path())
+                .status()?;
+            if !status.success() {
+                bail!("Git init failed!");
+            }
+        }
+
+        let status = Command::new("git")
+            .args(["add", "."])
+            .current_dir(Self::base_path())
+            .status()?;
+        if !status.success() {
+            bail!("Git add . failed!");
+        }
+
+        let status = Command::new("git")
+            .args(["commit", "--message", message, "--no-gpg-sign"])
+            .current_dir(Self::base_path())
+            .status()?;
+        if !status.success() {
+            bail!("Git commit failed!");
+        }
+
+        Ok(())
+    }
 }
diff --git a/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs b/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs
index 84abb273..ea3a89ae 100644
--- a/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/neorg/handle.rs
@@ -21,8 +21,8 @@ use crate::{cli::NeorgCommand, state::State};
 
 pub fn handle(command: NeorgCommand, state: &mut State) -> Result<()> {
     match command {
-        NeorgCommand::Task { id } => {
-            let project = id.project(state)?;
+        NeorgCommand::Task { task } => {
+            let project = task.project(state)?;
             let base = dirs::data_local_dir()
                 .expect("This should exists")
                 .join("tskm/notes");
@@ -40,15 +40,17 @@ pub fn handle(command: NeorgCommand, state: &mut State) -> Result<()> {
                     String::new()
                 };
 
-                if !contents.contains(format!("% {}", id.uuid()).as_str()) {
+                if !contents.contains(format!("% {}", task.uuid()).as_str()) {
                     let mut options = OpenOptions::new();
                     options.append(true).create(false);
 
                     let mut file = options.open(&path)?;
-                    file.write_all(format!("* TITLE (% {})", id.uuid()).as_bytes())
-                        .with_context(|| {
-                            format!("Failed to write task uuid to file: '{}'", path.display())
-                        })?;
+                    file.write_all(
+                        format!("* {} (% {})", task.description(state)?, task.uuid()).as_bytes(),
+                    )
+                    .with_context(|| {
+                        format!("Failed to write task uuid to file: '{}'", path.display())
+                    })?;
                     file.flush()
                         .with_context(|| format!("Failed to flush file: '{}'", path.display()))?;
                 }
@@ -59,7 +61,7 @@ pub fn handle(command: NeorgCommand, state: &mut State) -> Result<()> {
                 .args([
                     path.to_str().expect("Should be a utf-8 str"),
                     "-c",
-                    format!("/% {}", id.uuid()).as_str(),
+                    format!("/% {}", task.uuid()).as_str(),
                 ])
                 .status()?;
             if !status.success() {
@@ -90,7 +92,7 @@ pub fn handle(command: NeorgCommand, state: &mut State) -> Result<()> {
             }
 
             {
-                id.mark_neorg_data(state)?;
+                task.mark_neorg_data(state)?;
             }
         }
     }
diff --git a/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs b/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs
index ed24c2cb..6bed1e39 100644
--- a/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/neorg/mod.rs
@@ -12,7 +12,7 @@ use std::path::PathBuf;
 
 use anyhow::Result;
 
-use crate::task::{run_task, Project};
+use crate::task::{Project, run_task};
 
 pub mod handle;
 pub use handle::handle;
diff --git a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
index f5925523..3897a63b 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/handle.rs
@@ -8,47 +8,66 @@
 // You should have received a copy of the License along with this program.
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-use std::{
-    fs,
-    net::{IpAddr, Ipv4Addr},
-    path::PathBuf,
-    process,
-};
+use std::str::FromStr;
 
 use anyhow::{bail, Context, Result};
-use log::{error, info, warn};
+use log::{error, info};
 use url::Url;
 
-use crate::{cli::OpenCommand, rofi, state::State, task};
+use crate::{browser::open_in_browser, cli::OpenCommand, rofi, state::State, task};
 
+fn is_empty(project: &task::Project) -> Result<bool> {
+    let tabs = get_tabs(project)?;
+
+    if tabs.is_empty() {
+        Ok(true)
+    } else if tabs.len() > 1 {
+        Ok(false)
+    } else {
+        let url = &tabs[0].1;
+
+        Ok(url == &Url::from_str("qute://start/").expect("Hardcoded"))
+    }
+}
+
+#[allow(clippy::too_many_lines)]
 pub fn handle(command: OpenCommand, state: &mut State) -> Result<()> {
     match command {
-        OpenCommand::Review => {
+        OpenCommand::Review { non_empty } => {
             for project in task::Project::all().context("Failed to get all project files")? {
-                if project.is_touched() {
-                    info!("Reviewing project: '{}'", project.to_project_display());
-                    open_in_browser(project, state, None).with_context(|| {
+                let is_empty = is_empty(project)?;
+
+                if project.is_touched() || (non_empty && !is_empty) {
+                    info!(
+                        "Reviewing project: '{}' ({})",
+                        project.to_project_display(),
+                        if is_empty { "is empty" } else { "is not empty" }
+                    );
+                    open_in_browser(project, state, None::<Vec<Url>>).with_context(|| {
                         format!(
-                            "Failed to open project ('{}') in Firefox",
-                            project.to_project_display()
-                        )
-                    })?;
-                    project.untouch().with_context(|| {
-                        format!(
-                            "Failed to untouch project ('{}')",
+                            "Failed to open project ('{}') in qutebrowser",
                             project.to_project_display()
                         )
                     })?;
+
+                    if project.is_touched() {
+                        project.untouch().with_context(|| {
+                            format!(
+                                "Failed to untouch project ('{}')",
+                                project.to_project_display()
+                            )
+                        })?;
+                    }
                 }
             }
         }
-        OpenCommand::Project { project, url } => {
+        OpenCommand::Project { project, urls } => {
             project.touch().context("Failed to touch project")?;
-            open_in_browser(&project, state, url).with_context(|| {
+            open_in_browser(&project, state, urls).with_context(|| {
                 format!("Failed to open project: {}", project.to_project_display())
             })?;
         }
-        OpenCommand::Select { url } => {
+        OpenCommand::Select { urls } => {
             let selected_project: task::Project = task::Project::from_project_string(
                 &rofi::select(
                     task::Project::all()
@@ -66,177 +85,106 @@ pub fn handle(command: OpenCommand, state: &mut State) -> Result<()> {
                 .touch()
                 .context("Failed to touch project")?;
 
-            open_in_browser(&selected_project, state, url).context("Failed to open project")?;
+            open_in_browser(&selected_project, state, urls).context("Failed to open project")?;
         }
-        OpenCommand::ListTabs { project } => {
-            let project = if let Some(p) = project {
-                p
-            } else if let Some(p) =
-                task::Project::get_current().context("Failed to get currently focused project")?
-            {
-                p
-            } else {
-                bail!("You need to either supply a project or have a project active!");
+        OpenCommand::ListTabs { projects, mode } => {
+            let projects = {
+                if let Some(p) = projects {
+                    p
+                } else if mode.is_some() {
+                    task::Project::all()
+                        .context("Failed to get all projects")?
+                        .to_owned()
+                } else if let Some(p) = task::Project::get_current()
+                    .context("Failed to get currently focused project")?
+                {
+                    vec![p]
+                } else {
+                    bail!("You need to either select projects or pass --mode");
+                }
             };
 
-            let session_store = project.get_sessionstore().with_context(|| {
-                format!(
-                    "Failed to get session store for project: '{}'",
-                    project.to_project_display()
-                )
-            })?;
-
-            let selected = session_store
-                .windows
-                .iter()
-                .map(|w| w.selected)
-                .collect::<Vec<_>>();
-
-            let tabs = session_store
-                .windows
-                .iter()
-                .flat_map(|window| window.tabs.iter())
-                .map(|tab| tab.entries.get(tab.index - 1).expect("This should be Some"))
-                .collect::<Vec<_>>();
-
-            for (index, entry) in tabs.iter().enumerate() {
-                let index = index + 1;
-                let is_selected = {
-                    if selected.contains(&index) {
-                        "🔻 "
-                    } else {
-                        "   "
+            for project in &projects {
+                if let Some(mode) = mode {
+                    match mode {
+                        crate::cli::ListMode::Empty => {
+                            if !is_empty(project)? {
+                                continue;
+                            }
+
+                            // We do not need to print, tabs they are always empty.
+                            if projects.len() > 1 {
+                                println!("/* {} */", project.to_project_display());
+                            }
+                            continue;
+                        }
+                        crate::cli::ListMode::NonEmpty => {
+                            if is_empty(project)? {
+                                continue;
+                            }
+                        }
                     }
-                };
-                println!("{}{}", is_selected, entry.url);
-            }
-        }
-    }
-    Ok(())
-}
-
-fn open_in_browser(
-    selected_project: &task::Project,
-    state: &mut State,
-    url: Option<Url>,
-) -> Result<()> {
-    let old_project: Option<task::Project> =
-        task::Project::get_current().context("Failed to get currently active project")?;
-    let old_task: Option<task::Task> =
-        task::Task::get_current(state).context("Failed to get currently active task")?;
-
-    selected_project.activate().with_context(|| {
-        format!(
-            "Failed to active project: '{}'",
-            selected_project.to_project_display()
-        )
-    })?;
-
-    let tracking_task = {
-        let all_tasks = selected_project.get_tasks(state).with_context(|| {
-            format!(
-                "Failed to get assoctiated tasks for project: '{}'",
-                selected_project.to_project_display()
-            )
-        })?;
-
-        let tracking_task = all_tasks.into_iter().find(|t| {
-            let maybe_desc = t.description(state);
-            if let Ok(desc) = maybe_desc {
-                desc == "tracking"
-            } else {
-                error!(
-                    "Getting task description returned error: {}",
-                    maybe_desc.expect_err("We already check for Ok")
-                );
-                false
-            }
-        });
-
-        if let Some(task) = tracking_task {
-            info!(
-                "Starting task {} -> tracking",
-                selected_project.to_project_display()
-            );
-            task.start(state)
-                .with_context(|| format!("Failed to start task {task}"))?;
-        }
-        tracking_task
-    };
-
-    let status = {
-        let mut args = vec!["-P".to_owned(), selected_project.to_project_display()];
-        if let Some(url) = url {
-            args.push(url.to_string());
-        } else {
-            let lock_file = dirs::home_dir()
-                .expect("Exists")
-                .join(".mozilla/firefox")
-                .join(selected_project.to_project_display())
-                .join("lock");
-
-            if lock_file.exists() {
-                let (ip, pid): (IpAddr, u32) = {
-                    let link = fs::read_link(&lock_file).with_context(|| {
-                        format!("Failed to readlink lock at '{}'", lock_file.display())
-                    })?;
+                }
 
-                    let (ip, pid) = link
-                        .to_str()
-                        .expect("Should work")
-                        .split_once(':')
-                        .expect("The split works");
+                if projects.len() > 1 {
+                    println!("/* {} */", project.to_project_display());
+                }
 
-                    (
-                        ip.parse().expect("Should be a valid ip address"),
-                        pid.parse().expect("Should be a valid pid"),
-                    )
+                let tabs = match get_tabs(project) {
+                    Ok(ok) => ok,
+                    Err(err) => {
+                        if projects.len() > 1 {
+                            error!(
+                                "While trying to get the sessionstore for {}: {:?}",
+                                project.to_project_display(),
+                                err
+                            );
+                            continue;
+                        }
+
+                        return Err(err).with_context(|| {
+                            format!(
+                                "While trying to get the sessionstore for {}",
+                                project.to_project_display()
+                            )
+                        });
+                    }
                 };
 
-                if ip != Ipv4Addr::new(127, 0, 0, 2) {
-                    warn!("Your ip is weird..");
-                }
-
-                if PathBuf::from("/proc").join(pid.to_string()).exists() {
-                    // Another Firefox instance has already been started for this project
-                    // Add a buffer URL to force Firefox to open it in the already open instance
-                    args.push("about:newtab".to_owned());
-                } else {
-                    // This project does not yet have another Firefox instance
-                    // We do not need to add anything to the arguments, Firefox will open a new
-                    // instance.
+                for (active, url) in tabs {
+                    let is_selected = {
+                        if active {
+                            "🔻 "
+                        } else {
+                            "   "
+                        }
+                    };
+                    println!("{is_selected}{url}");
                 }
-            } else {
-                // There is no lock file and thus no instance already open.
             }
-        };
-
-        process::Command::new("firefox")
-            .args(args)
-            .status()
-            .context("Failed to start firefox")?
-    };
-
-    if !status.success() {
-        error!("Firefox run exited with error.");
+        }
     }
 
-    if let Some(task) = tracking_task {
-        task.stop(state)
-            .with_context(|| format!("Failed to stop task {task}"))?;
-    }
-    if let Some(task) = old_task {
-        task.start(state)
-            .with_context(|| format!("Failed to start task {task}"))?;
-    }
+    Ok(())
+}
 
-    if let Some(project) = old_project {
-        project.activate().with_context(|| {
-            format!("Failed to active project {}", project.to_project_display())
-        })?;
-    } else {
-        task::Project::clear().context("Failed to clear currently focused project")?;
-    }
+fn get_tabs(project: &task::Project) -> Result<Vec<(bool, Url)>> {
+    let session_store = project.get_sessionstore()?;
 
-    Ok(())
+    let tabs = session_store
+        .windows
+        .iter()
+        .flat_map(|window| window.tabs.iter())
+        .filter_map(|tab| {
+            tab.history
+                .iter()
+                .find(|hist| hist.active)
+                .map(|hist| (tab.active, hist))
+        })
+        .collect::<Vec<_>>();
+
+    Ok(tabs
+        .into_iter()
+        .map(|(active, hist)| (active, hist.url.clone()))
+        .collect())
 }
diff --git a/pkgs/by-name/ts/tskm/src/interface/open/mod.rs b/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
index a4060fa3..e403b4a8 100644
--- a/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/open/mod.rs
@@ -8,109 +8,191 @@
 // You should have received a copy of the License along with this program.
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-use std::{collections::HashMap, fs::File, io};
-
-use anyhow::{Context, Result};
-use lz4_flex::decompress_size_prepended;
-use serde::Deserialize;
-use serde_json::Value;
+use std::{
+    fs::{self, File},
+    io::Read,
+    str::FromStr,
+};
+
+use anyhow::{anyhow, Context, Result};
+use taskchampion::chrono::NaiveDateTime;
 use url::Url;
+use yaml_rust2::Yaml;
 
 use crate::task::Project;
 
 pub mod handle;
 pub use handle::handle;
 
-impl Project {
-    pub(super) fn get_sessionstore(&self) -> Result<SessionStore> {
-        let path = dirs::home_dir()
-            .expect("Will exist")
-            .join(".mozilla/firefox")
-            .join(self.to_project_display())
-            .join("sessionstore-backups/recovery.jsonlz4");
-        let file = decompress_mozlz4(
-            File::open(&path)
-                .with_context(|| format!("Failed to open path '{}'", path.display()))?,
-        )
-        .with_context(|| format!("Failed to decompress file as mozlzh '{}'", path.display()))?;
-
-        let contents: SessionStore = serde_json::from_str(&file).with_context(|| {
-            format!(
-                "Failed to deserialize file ('{}') as session store.",
-                path.display()
-            )
-        })?;
-        Ok(contents)
+/// An Url that also accepts file paths
+#[derive(Debug, Clone)]
+pub struct UrlLike(Url);
+
+impl FromStr for UrlLike {
+    type Err = url::ParseError;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        if let Ok(u) = fs::canonicalize(s) {
+            Ok(Self(Url::from_file_path(u).expect(
+                "The path could be canonicalized, as such it is valid for this",
+            )))
+        } else {
+            Url::from_str(s).map(Self)
+        }
     }
 }
 
-fn decompress_mozlz4<P: io::Read>(mut file: P) -> Result<String> {
-    const MOZLZ4_MAGIC_NUMBER: &[u8] = b"mozLz40\0";
+impl From<UrlLike> for Url {
+    fn from(value: UrlLike) -> Self {
+        value.0
+    }
+}
+
+impl Project {
+    pub(super) fn get_sessionstore(&self) -> Result<SessionStore> {
+        let path = dirs::data_local_dir()
+            .context("Failed to get data dir")?
+            .join("qutebrowser")
+            .join(self.to_project_display())
+            .join("data/sessions/default.yml");
 
-    let mut buf = [0u8; 8];
-    file.read_exact(&mut buf)
-        .context("Failed to read the mozlz40 header.")?;
+        let mut file = File::open(&path)
+            .with_context(|| format!("Failed to open path '{}'", path.display()))?;
 
-    assert_eq!(buf, MOZLZ4_MAGIC_NUMBER);
+        let mut yaml_str = String::new();
+        file.read_to_string(&mut yaml_str)
+            .context("Failed to read _autosave.yml path")?;
+        let yaml = yaml_rust2::YamlLoader::load_from_str(&yaml_str)?;
 
-    let mut buf = vec![];
-    file.read_to_end(&mut buf).context("Failed to read file")?;
+        let store = qute_store_from_yaml(&yaml).context("Failed to read yaml store")?;
 
-    let uncompressed = decompress_size_prepended(&buf).context("Failed to decompress file")?;
+        Ok(store)
+    }
+}
 
-    Ok(String::from_utf8(uncompressed).expect("This should be valid json and thus utf8"))
+fn qute_store_from_yaml(yaml: &[Yaml]) -> Result<SessionStore> {
+    assert_eq!(yaml.len(), 1);
+    let doc = &yaml[0];
+
+    let hash = doc.as_hash().context("Invalid yaml")?;
+    let windows = hash
+        .get(&Yaml::String("windows".to_owned()))
+        .ok_or(anyhow!("Missing windows"))?
+        .as_vec()
+        .ok_or(anyhow!("Windows not vector"))?;
+
+    Ok(SessionStore {
+        windows: windows
+            .iter()
+            .map(|window| {
+                let hash = window.as_hash().ok_or(anyhow!("Windows not hashmap"))?;
+
+                Ok::<_, anyhow::Error>(Window {
+                    geometry: hash
+                        .get(&Yaml::String("geometry".to_owned()))
+                        .ok_or(anyhow!("Missing window geometry"))?
+                        .as_str()
+                        .ok_or(anyhow!("geometry not string"))?
+                        .to_owned(),
+                    tabs: hash
+                        .get(&Yaml::String("tabs".to_owned()))
+                        .ok_or(anyhow!("Missing window tabs"))?
+                        .as_vec()
+                        .ok_or(anyhow!("Tabs not vec"))?
+                        .iter()
+                        .map(|tab| {
+                            let hash = tab.as_hash().ok_or(anyhow!("Tab not hashmap"))?;
+
+                            Ok::<_, anyhow::Error>(Tab {
+                                history: hash
+                                    .get(&Yaml::String("history".to_owned()))
+                                    .ok_or(anyhow!("Missing tab history"))?
+                                    .as_vec()
+                                    .ok_or(anyhow!("tab history not vec"))?
+                                    .iter()
+                                    .map(|history| {
+                                        let hash = history
+                                            .as_hash()
+                                            .ok_or(anyhow!("Tab history not hashmap"))?;
+
+                                        Ok::<_, anyhow::Error>(TabHistory {
+                                            active: hash
+                                                .get(&Yaml::String("active".to_owned()))
+                                                .unwrap_or(&Yaml::Boolean(false))
+                                                .as_bool()
+                                                .ok_or(anyhow!("tab history active not bool"))?,
+                                            last_visited: NaiveDateTime::from_str(
+                                                hash.get(&Yaml::String("last_visited".to_owned()))
+                                                    .ok_or(anyhow!(
+                                                        "Missing tab history last_visited"
+                                                    ))?
+                                                    .as_str()
+                                                    .ok_or(anyhow!(
+                                                        "tab history last_visited not string"
+                                                    ))?,
+                                            )
+                                            .context("Failed to parse last_visited")?,
+                                            pinned: hash
+                                                .get(&Yaml::String("pinned".to_owned()))
+                                                .ok_or(anyhow!("Missing tab history pinned"))?
+                                                .as_bool()
+                                                .ok_or(anyhow!("tab history pinned not bool"))?,
+                                            title: hash
+                                                .get(&Yaml::String("title".to_owned()))
+                                                .ok_or(anyhow!("Missing tab history title"))?
+                                                .as_str()
+                                                .ok_or(anyhow!("tab history title not string"))?
+                                                .to_owned(),
+                                            url: Url::parse(
+                                                hash.get(&Yaml::String("url".to_owned()))
+                                                    .ok_or(anyhow!("Missing tab history url"))?
+                                                    .as_str()
+                                                    .ok_or(anyhow!("tab history url not string"))?,
+                                            )
+                                            .context("Failed to parse url")?,
+                                            zoom: hash
+                                                .get(&Yaml::String("zoom".to_owned()))
+                                                .unwrap_or(&Yaml::Real("1.0".to_owned()))
+                                                .as_f64()
+                                                .ok_or(anyhow!("tab history zoom not 64"))?,
+                                        })
+                                    })
+                                    .collect::<Result<Vec<_>, _>>()?,
+                                active: hash
+                                    .get(&Yaml::String("active".to_owned()))
+                                    .unwrap_or(&Yaml::Boolean(false))
+                                    .as_bool()
+                                    .ok_or(anyhow!("active not bool"))?,
+                            })
+                        })
+                        .collect::<Result<Vec<_>, _>>()?,
+                })
+            })
+            .collect::<Result<Vec<_>, _>>()?,
+    })
 }
 
-#[derive(Deserialize, Debug)]
+#[derive(Debug)]
 pub struct SessionStore {
     pub windows: Vec<Window>,
 }
-
-#[derive(Deserialize, Debug)]
+#[derive(Debug)]
 pub struct Window {
+    pub geometry: String,
     pub tabs: Vec<Tab>,
-    pub selected: usize,
 }
-
-#[derive(Deserialize, Debug)]
+#[derive(Debug)]
 pub struct Tab {
-    pub entries: Vec<TabEntry>,
-    #[serde(rename = "lastAccessed")]
-    pub last_accessed: u64,
-    pub hidden: bool,
-    #[serde(rename = "searchMode")]
-    pub search_mode: Option<Value>,
-    #[serde(rename = "userContextId")]
-    pub user_context_id: u32,
-    pub attributes: TabAttributes,
-    #[serde(rename = "extData")]
-    pub ext_data: Option<HashMap<String, Value>>,
-    pub index: usize,
-    #[serde(rename = "requestedIndex")]
-    pub requested_index: Option<u32>,
-    pub image: Option<Url>,
+    pub history: Vec<TabHistory>,
+    pub active: bool,
 }
-
-#[derive(Deserialize, Debug)]
-pub struct TabEntry {
-    pub url: Url,
+#[derive(Debug)]
+pub struct TabHistory {
+    pub active: bool,
+    pub last_visited: NaiveDateTime,
+    pub pinned: bool,
+    // pub scroll-pos:
     pub title: String,
-    #[serde(rename = "cacheKey")]
-    pub cache_key: u32,
-    #[serde(rename = "ID")]
-    pub id: u32,
-    #[serde(rename = "docshellUUID")]
-    pub docshell_uuid: Value,
-    #[serde(rename = "resultPrincipalURI")]
-    pub result_principal_uri: Option<Url>,
-    #[serde(rename = "hasUserInteraction")]
-    pub has_user_interaction: bool,
-    #[serde(rename = "triggeringPrincipal_base64")]
-    pub triggering_principal_base64: Value,
-    #[serde(rename = "docIdentifier")]
-    pub doc_identifier: u32,
-    pub persist: bool,
+    pub url: Url,
+    pub zoom: f64,
 }
-
-#[derive(Deserialize, Debug, Clone, Copy)]
-pub struct TabAttributes {}
diff --git a/pkgs/by-name/ts/tskm/src/interface/project/handle.rs b/pkgs/by-name/ts/tskm/src/interface/project/handle.rs
index c698500f..6d44b340 100644
--- a/pkgs/by-name/ts/tskm/src/interface/project/handle.rs
+++ b/pkgs/by-name/ts/tskm/src/interface/project/handle.rs
@@ -10,7 +10,7 @@
 
 use std::{env, fs::File, io::Write};
 
-use anyhow::{anyhow, Context, Result};
+use anyhow::{Context, Result, anyhow};
 use log::trace;
 
 use crate::{cli::ProjectCommand, task};
@@ -70,10 +70,12 @@ pub fn handle(command: ProjectCommand) -> Result<()> {
 
                     let new_definition = ProjectDefinition::default();
 
-                    assert!(definition
-                        .subprojects
-                        .insert(segment.clone(), new_definition)
-                        .is_none());
+                    assert!(
+                        definition
+                            .subprojects
+                            .insert(segment.clone(), new_definition)
+                            .is_none()
+                    );
 
                     definition = definition
                         .subprojects
diff --git a/pkgs/by-name/ts/tskm/src/main.rs b/pkgs/by-name/ts/tskm/src/main.rs
index fe011e27..e6113111 100644
--- a/pkgs/by-name/ts/tskm/src/main.rs
+++ b/pkgs/by-name/ts/tskm/src/main.rs
@@ -17,6 +17,7 @@ use crate::{
     state::State,
 };
 
+pub mod browser;
 pub mod cli;
 pub mod interface;
 pub mod rofi;
@@ -34,14 +35,13 @@ fn main() -> Result<(), anyhow::Error> {
         .show_module_names(true)
         .color(stderrlog::ColorChoice::Auto)
         .verbosity(usize::from(args.verbosity))
-        .timestamp(stderrlog::Timestamp::Off)
         .init()
         .expect("Let's just hope that this does not panic");
 
     let mut state = State::new_rw()?;
 
     match args.command {
-        Command::Inputs { command } => input::handle(command)?,
+        Command::Inputs { command } => input::handle(command, &mut state)?,
         Command::Neorg { command } => neorg::handle(command, &mut state)?,
         Command::Open { command } => open::handle(command, &mut state)?,
         Command::Projects { command } => project::handle(command)?,
diff --git a/pkgs/by-name/ts/tskm/src/state.rs b/pkgs/by-name/ts/tskm/src/state.rs
index 3c611d8f..ae71764e 100644
--- a/pkgs/by-name/ts/tskm/src/state.rs
+++ b/pkgs/by-name/ts/tskm/src/state.rs
@@ -11,7 +11,7 @@
 use std::path::PathBuf;
 
 use anyhow::Result;
-use taskchampion::{storage::AccessMode, Replica, StorageConfig};
+use taskchampion::{Replica, StorageConfig, storage::AccessMode};
 
 pub struct State {
     replica: Replica,
diff --git a/pkgs/by-name/ts/tskm/src/task/mod.rs b/pkgs/by-name/ts/tskm/src/task/mod.rs
index 7d00896f..9c671273 100644
--- a/pkgs/by-name/ts/tskm/src/task/mod.rs
+++ b/pkgs/by-name/ts/tskm/src/task/mod.rs
@@ -76,7 +76,6 @@ impl Task {
     pub fn uuid(&self) -> &taskchampion::Uuid {
         &self.uuid
     }
-    #[must_use]
     pub fn working_set_id(&self, state: &mut State) -> Result<usize> {
         Ok(state
             .replica()
@@ -356,5 +355,13 @@ pub(crate) fn run_task(args: &[&str]) -> Result<String> {
     trace!("Output (stdout): '{}'", stdout.trim());
     trace!("Output (stderr): '{}'", stderr.trim());
 
+    if !output.status.success() {
+        bail!(
+            "Command `task {}` failed with status: {}",
+            args.join(" "),
+            output.status
+        );
+    }
+
     Ok(stdout.trim().to_owned())
 }
diff --git a/pkgs/by-name/ts/tskm/update.sh b/pkgs/by-name/ts/tskm/update.sh
index 0b170ec8..8e36e13e 100755
--- a/pkgs/by-name/ts/tskm/update.sh
+++ b/pkgs/by-name/ts/tskm/update.sh
@@ -10,4 +10,5 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-cargo update && cargo upgrade
+[ "$1" = "upgrade" ] && cargo upgrade
+cargo update
diff --git a/pkgs/by-name/ya/yambar-modules/.envrc b/pkgs/by-name/ya/yambar-modules/.envrc
deleted file mode 100644
index 294de504..00000000
--- a/pkgs/by-name/ya/yambar-modules/.envrc
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env sh
-
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-use flake
diff --git a/pkgs/by-name/ya/yambar-modules/.gitignore b/pkgs/by-name/ya/yambar-modules/.gitignore
deleted file mode 100644
index d888531a..00000000
--- a/pkgs/by-name/ya/yambar-modules/.gitignore
+++ /dev/null
@@ -1,11 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-/target
diff --git a/pkgs/by-name/ya/yambar-modules/Cargo.lock b/pkgs/by-name/ya/yambar-modules/Cargo.lock
deleted file mode 100644
index 6c6c7c36..00000000
--- a/pkgs/by-name/ya/yambar-modules/Cargo.lock
+++ /dev/null
@@ -1,141 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-# This file is automatically @generated by Cargo.
-# It is not intended for manual editing.
-version = 3
-
-[[package]]
-name = "cfg-if"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
-
-[[package]]
-name = "core-foundation-sys"
-version = "0.8.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
-
-[[package]]
-name = "crossbeam-deque"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
-dependencies = [
- "crossbeam-epoch",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-epoch"
-version = "0.9.18"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
-dependencies = [
- "crossbeam-utils",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
-
-[[package]]
-name = "either"
-version = "1.13.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
-
-[[package]]
-name = "libc"
-version = "0.2.167"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
-
-[[package]]
-name = "ntapi"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "once_cell"
-version = "1.20.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
-
-[[package]]
-name = "rayon"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
-dependencies = [
- "either",
- "rayon-core",
-]
-
-[[package]]
-name = "rayon-core"
-version = "1.12.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
-dependencies = [
- "crossbeam-deque",
- "crossbeam-utils",
-]
-
-[[package]]
-name = "sysinfo"
-version = "0.28.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4c2f3ca6693feb29a89724516f016488e9aafc7f37264f898593ee4b942f31b"
-dependencies = [
- "cfg-if",
- "core-foundation-sys",
- "libc",
- "ntapi",
- "once_cell",
- "rayon",
- "winapi",
-]
-
-[[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "yambar-modules"
-version = "0.1.0"
-dependencies = [
- "sysinfo",
-]
diff --git a/pkgs/by-name/ya/yambar-modules/flake.lock b/pkgs/by-name/ya/yambar-modules/flake.lock
deleted file mode 100644
index 8043448e..00000000
--- a/pkgs/by-name/ya/yambar-modules/flake.lock
+++ /dev/null
@@ -1,61 +0,0 @@
-{
-  "nodes": {
-    "flake-utils": {
-      "inputs": {
-        "systems": "systems"
-      },
-      "locked": {
-        "lastModified": 1731533236,
-        "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
-        "type": "github"
-      },
-      "original": {
-        "owner": "numtide",
-        "repo": "flake-utils",
-        "type": "github"
-      }
-    },
-    "nixpkgs": {
-      "locked": {
-        "lastModified": 1732617236,
-        "narHash": "sha256-PYkz6U0bSEaEB1al7O1XsqVNeSNS+s3NVclJw7YC43w=",
-        "owner": "NixOS",
-        "repo": "nixpkgs",
-        "rev": "af51545ec9a44eadf3fe3547610a5cdd882bc34e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "NixOS",
-        "ref": "nixpkgs-unstable",
-        "repo": "nixpkgs",
-        "type": "github"
-      }
-    },
-    "root": {
-      "inputs": {
-        "flake-utils": "flake-utils",
-        "nixpkgs": "nixpkgs"
-      }
-    },
-    "systems": {
-      "locked": {
-        "lastModified": 1681028828,
-        "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
-        "owner": "nix-systems",
-        "repo": "default",
-        "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
-        "type": "github"
-      },
-      "original": {
-        "owner": "nix-systems",
-        "repo": "default",
-        "type": "github"
-      }
-    }
-  },
-  "root": "root",
-  "version": 7
-}
diff --git a/pkgs/by-name/ya/yambar-modules/flake.lock.license b/pkgs/by-name/ya/yambar-modules/flake.lock.license
deleted file mode 100644
index eae6a84c..00000000
--- a/pkgs/by-name/ya/yambar-modules/flake.lock.license
+++ /dev/null
@@ -1,9 +0,0 @@
-nixos-config - My current NixOS configuration
-
-Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-SPDX-License-Identifier: GPL-3.0-or-later
-
-This file is part of my nixos-config.
-
-You should have received a copy of the License along with this program.
-If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
diff --git a/pkgs/by-name/ya/yambar-modules/flake.nix b/pkgs/by-name/ya/yambar-modules/flake.nix
deleted file mode 100644
index 99ec66a8..00000000
--- a/pkgs/by-name/ya/yambar-modules/flake.nix
+++ /dev/null
@@ -1,41 +0,0 @@
-# nixos-config - My current NixOS configuration
-#
-# Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# This file is part of my nixos-config.
-#
-# You should have received a copy of the License along with this program.
-# If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-{
-  description = "Extension modules for yambar(1)";
-
-  inputs = {
-    nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
-    flake-utils.url = "github:numtide/flake-utils";
-  };
-
-  outputs = {
-    nixpkgs,
-    flake-utils,
-    ...
-  }:
-    flake-utils.lib.eachDefaultSystem (system: let
-      pkgs = nixpkgs.legacyPackages."${system}";
-    in {
-      devShells.default = pkgs.mkShell {
-        packages = with pkgs; [
-          # rust stuff
-          cargo
-          clippy
-          rustc
-          rustfmt
-
-          cargo-edit
-          cargo-expand
-        ];
-      };
-    });
-}
-# vim: ts=2
-
diff --git a/pkgs/by-name/ya/yambar-modules/src/cpu.rs b/pkgs/by-name/ya/yambar-modules/src/cpu.rs
deleted file mode 100644
index f53107a8..00000000
--- a/pkgs/by-name/ya/yambar-modules/src/cpu.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// nixos-config - My current NixOS configuration
-//
-// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of my nixos-config.
-//
-// You should have received a copy of the License along with this program.
-// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-use std::{thread, time::Duration};
-
-use sysinfo::{CpuExt, System, SystemExt};
-
-pub fn cpu() {
-    let mut sys = System::new();
-
-    loop {
-        sys.refresh_cpu();
-        let cpu_usage: f32 = sys.cpus().iter().map(|cpu| cpu.cpu_usage()).sum();
-        println!(
-            "cpu|range:0-100|{:.0}",
-            cpu_usage / sys.cpus().iter().count() as f32
-        );
-        println!();
-
-        // Sleeping to give the system time to run for long
-        // enough to have useful information.
-        thread::sleep(Duration::from_secs(3));
-    }
-}
diff --git a/pkgs/by-name/ya/yambar-modules/src/main.rs b/pkgs/by-name/ya/yambar-modules/src/main.rs
deleted file mode 100644
index 03bafadf..00000000
--- a/pkgs/by-name/ya/yambar-modules/src/main.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-// nixos-config - My current NixOS configuration
-//
-// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of my nixos-config.
-//
-// You should have received a copy of the License along with this program.
-// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-use std::{env::args, process};
-
-mod cpu;
-mod memory;
-
-fn main() {
-    let args: Vec<String> = args().collect();
-
-    if args.len() != 2 {
-        eprintln!("Usage: yambar-modules cpu|memory");
-        process::exit(1);
-    }
-
-    match args[1].as_str() {
-        "cpu" => {
-            cpu::cpu();
-        }
-        "memory" => {
-            memory::memory();
-        }
-        other => {
-            eprintln!("'{other}' is not a valid command. Only 'cpu' or 'memory'.");
-            process::exit(1);
-        }
-    }
-}
diff --git a/pkgs/by-name/ya/yambar-modules/src/memory.rs b/pkgs/by-name/ya/yambar-modules/src/memory.rs
deleted file mode 100644
index 7c2c4669..00000000
--- a/pkgs/by-name/ya/yambar-modules/src/memory.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-// nixos-config - My current NixOS configuration
-//
-// Copyright (C) 2025 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of my nixos-config.
-//
-// You should have received a copy of the License along with this program.
-// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-use std::{thread, time::Duration};
-
-use sysinfo::{System, SystemExt};
-
-pub fn memory() {
-    let mut sys = System::new();
-
-    loop {
-        sys.refresh_memory();
-
-        let memory_percentage: f64 =
-            100 as f64 * (sys.used_memory() as f64 / sys.total_memory() as f64);
-
-        println!("memperc|string|{:.0}", memory_percentage);
-        if sys.total_swap() > 0 {
-            let swap_percentage: f64 =
-                100 as f64 * (sys.used_swap() as f64 / sys.total_swap() as f64);
-            println!("swapperc|string|{:.0}", swap_percentage);
-            println!("swapstate|bool|true");
-        } else {
-            println!("swapstate|bool|false");
-        }
-        println!("");
-
-        // Sleeping to give the system time to run for long
-        // enough to have useful information.
-        thread::sleep(Duration::from_secs(3));
-    }
-}
diff --git a/pkgs/by-name/yt/yt/package.nix b/pkgs/by-name/yt/yt/package.nix
index d73776c5..4e1b2ecb 100644
--- a/pkgs/by-name/yt/yt/package.nix
+++ b/pkgs/by-name/yt/yt/package.nix
@@ -8,41 +8,68 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
+  lib,
+  rustPlatform,
+  installShellFiles,
   fetchgit,
-  ffmpeg,
   gitUpdater,
-  glibc,
-  lib,
-  llvmPackages_latest,
-  makeWrapper,
+  # buildInputs
   mpv-unwrapped,
+  ffmpeg-headless,
+  openssl,
+  libffi,
+  zlib,
+  curl,
+  deno,
+  # NativeBuildInputs
   python3,
-  rustPlatform,
+  makeWrapper,
+  llvmPackages_latest,
+  glibc,
+  mold,
   sqlite,
   fd,
+  pkg-config,
+  SDL2,
 }: let
-  version = "1.5.0";
-
-  src = fetchgit {
-    url = "https://git.foss-syndicate.org/bpeetz/clients/yt";
-    rev = "v${version}";
-    hash = "sha256-P/mpF2KPjoC7XZ6juJubeGEHhL2ajdOeiuIEb5sYrS0=";
-  };
-
-  buildInputs = [
-    (python3.withPackages (ps: [ps.yt-dlp]))
-    mpv-unwrapped.dev
-    ffmpeg
-  ];
+  version = "1.9.0";
+  python = python3.withPackages (ps: [ps.yt-dlp]);
 in
-  rustPlatform.buildRustPackage {
-    inherit version src buildInputs;
+  rustPlatform.buildRustPackage (finalAttrs: {
+    inherit version;
     pname = "yt";
 
+    src = fetchgit {
+      url = "https://git.foss-syndicate.org/bpeetz/clients/yt";
+      tag = "v${version}";
+      hash = "sha256-/Isgqe7Hda/1kwYY+ciQH/NBAcWvM92vDxWZ9svlQAM=";
+    };
+
+    cargoHash = "sha256-U0alYK9mhz6esVf0mad9o7Ra6tRaL9HKCOftyOg34HE=";
+
+    buildInputs = [
+      mpv-unwrapped.dev
+      ffmpeg-headless
+      openssl
+      libffi
+      zlib
+      curl.dev
+      python
+      deno
+    ];
+
     nativeBuildInputs = [
+      installShellFiles
       makeWrapper
       sqlite
       fd
+      pkg-config
+      mold
+    ];
+
+    checkInputs = [
+      # Needed for the tests in `libmpv2`
+      SDL2
     ];
 
     passthru.updateScript = gitUpdater {rev-prefix = "v";};
@@ -52,27 +79,46 @@ in
         lib.versions.major
         llvmPackages_latest.clang-unwrapped.version;
     in {
-      FFMPEG_LOCATION = "${lib.getExe ffmpeg}";
-      PYO3_PYTHON = lib.getExe (python3.withPackages (ps: [ps.yt-dlp]));
+      # Needed for the compile time sqlite checks.
+      DATABASE_URL = "sqlite://database.sqlx";
+
+      # Required by yt_dlp
+      FFMPEG_LOCATION = "${lib.getExe ffmpeg-headless}";
+
+      # Tell pyo3 which python to use.
+      PYO3_PYTHON = lib.getExe python;
 
+      # Needed for the libmpv2.
       C_INCLUDE_PATH = "${glibc.dev}/include";
-      DATABASE_URL = "sqlite://target/database.sqlx";
       LIBCLANG_INCLUDE_PATH = "${llvmPackages_latest.clang-unwrapped.lib}/lib/clang/${clang_version}/include";
       LIBCLANG_PATH = "${llvmPackages_latest.clang-unwrapped.lib}/lib/libclang.so";
     };
 
-    # Some tests depend on network access, others require a special library.
-    doCheck = false;
+    doCheck = true;
+    checkFlags = [
+      # All of these tests try to connect to the internet to download test data.
+      "--skip=select::base::test_base"
+      "--skip=select::file::test_file"
+      "--skip=select::options::test_options"
+      "--skip=subscriptions::import_export::test_import_export"
+      "--skip=subscriptions::naming_subscriptions::test_naming_subscriptions"
+      "--skip=videos::downloading::test_downloading"
+    ];
 
     prePatch = ''
+      # Generate the sqlite db, so that we can run the comp-time sqlite checks.
       bash ./scripts/mkdb.sh
     '';
 
-    useFetchCargoVendor = true;
-    cargoHash = "sha256-0XTbC+mFsczUFXqAtiQ+BIsCfKilerhlzE41pzVjLVs=";
-
     postInstall = ''
+      installShellCompletion --cmd yt \
+        --bash <(COMPLETE=bash $out/bin/yt) \
+        --fish <(COMPLETE=fish $out/bin/yt) \
+        --zsh <(COMPLETE=zsh $out/bin/yt)
+
+      # NOTE: We cannot clear the path, because we need access to the $EDITOR. <2025-04-04>
       wrapProgram $out/bin/yt \
-        --prefix PATH : ${lib.makeBinPath buildInputs}
+        --prefix PATH : ${lib.makeBinPath finalAttrs.buildInputs} \
+        --set YTDLP_NO_PLUGINS 1
     '';
-  }
+  })
diff --git a/pkgs/default.nix b/pkgs/default.nix
index 5294f3e2..9a3ac842 100644
--- a/pkgs/default.nix
+++ b/pkgs/default.nix
@@ -9,13 +9,13 @@
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 {
   pkgs,
-  nixLib,
+  libraries,
 }: let
   inherit (pkgs) lib;
 
-  callPackage = lib.callPackageWith (nixLib.warnMerge pkgs myPkgs "the ./pkgs/by-name set");
+  callPackage = lib.callPackageWith (libraries.extra.warnMerge pkgs myPkgs "the ./pkgs/by-name set");
 
-  myPkgs = nixLib.mkByName {
+  myPkgs = libraries.extra.mkByName {
     baseDirectory = ./by-name;
     fileName = "package.nix";
     finalizeFunction = name: value: callPackage value {};
diff --git a/pkgs/update_pkgs.sh b/pkgs/update_pkgs.sh
index d046ee76..d036142e 100755
--- a/pkgs/update_pkgs.sh
+++ b/pkgs/update_pkgs.sh
@@ -19,7 +19,7 @@ cd "$(dirname "$0")" || die "Bug: run with the wrong first arg: '$0'!"
 cd ./by-name || die "(BUG): The directory './by-name' does not exist?"
 
 # First check if all the update scripts conform to the standard
-files_with_update="$(mktemp)"
+files_with_update="$(mktemp -t update_pkgs_XXXXX)"
 trap 'rm "$files_with_update"' EXIT
 
 fd '^update.sh$' . --type file --extension sh --max-depth 3 | while read -r file; do
diff --git a/build.sh b/scripts/build.sh
index de4d536c..f3661978 100755
--- a/build.sh
+++ b/scripts/build.sh
@@ -10,7 +10,7 @@
 # You should have received a copy of the License along with this program.
 # If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
-host="${1-tiamat}"
+host="${1-$(hostname)}"
 [ "$#" -gt 0 ] && shift 1
 
 root="$(git rev-parse --show-toplevel)"
@@ -23,7 +23,9 @@ check() {
     if [ -s "$file" ]; then
         rm "$file"
     elif ! [ -e "$file" ]; then
-        : "Ignore not existing files"
+        rm "$file" || {
+            : "Ignore not existing files"
+        }
     else
         echo "ERROR: '$file' is not a symlink. Not removing it." 1>&2
         exit 1
@@ -31,7 +33,7 @@ check() {
 }
 
 build_system() {
-    _val="$(nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --print-out-paths --no-link "$@")"
+    _val="$(nix build ".#nixosConfigurations.$host.config.system.build.toplevel" --print-out-paths --no-link --option max-jobs 1 "$@")"
     exit_val="$?"
 
     if [ "$exit_val" -ne 0 ]; then
@@ -52,4 +54,6 @@ home="$(grep ExecStart= "$SYSTEM_OUT/etc/systemd/system/home-manager-soispha.ser
 check "$HOME_OUT"
 ln --symbolic "$home" "$HOME_OUT"
 
+nvd diff /run/current-system "$SYSTEM_OUT"
+
 # vim: ft=sh
diff --git a/scripts/why-depends b/scripts/why-depends
new file mode 100755
index 00000000..1afe9150
--- /dev/null
+++ b/scripts/why-depends
@@ -0,0 +1,23 @@
+#! /usr/bin/env sh
+
+search_string="$1-"
+shift 1
+
+if [ "$1" != "" ]; then
+    # Add the version
+    search_string="${search_string}${1}$"
+    shift 1
+fi
+
+if [ "$1" = "--running" ]; then
+    shift 1
+    base="/run/current-system"
+else
+    host="$(hostname)"
+    base=".#nixosConfigurations.$host.config.system.build.toplevel"
+fi
+
+
+fd "$search_string" /nix/store --type directory --threads 1 --exec nix why-depends "$@" "$base"
+
+# vim: ft=sh
diff --git a/secrets.nix b/secrets.nix
index 8b4a5545..fc5a9249 100644
--- a/secrets.nix
+++ b/secrets.nix
@@ -17,8 +17,9 @@ in {
 
   "modules/by-name/ta/taskwarrior/secrets/sync_server_encryption_key.age".publicKeys = [soispha tiamat apzu];
 
-  "modules/common/secrets/backup/privateSshKey.age".publicKeys = [soispha tiamat apzu];
-  "modules/common/secrets/backup/privatePassword.age".publicKeys = [soispha tiamat apzu];
+  "modules/by-name/ba/backup/secrets/storagebox/ssh_key.age".publicKeys = [soispha tiamat apzu];
+  "modules/by-name/ba/backup/secrets/storagebox/repository_password.age".publicKeys = [soispha tiamat apzu];
+  "modules/by-name/ba/backup/secrets/local/repository_password.age".publicKeys = [soispha tiamat apzu];
 
   "modules/by-name/se/serverphone/private_keys/ca.key".publicKeys = [soispha tiamat apzu];
   "modules/by-name/se/serverphone/private_keys/server.key".publicKeys = [soispha tiamat apzu];
diff --git a/update.sh b/update.sh
index ff10f870..980df783 100755
--- a/update.sh
+++ b/update.sh
@@ -22,11 +22,10 @@ __update_sh_run() {
 }
 
 __update_sh_run nix flake update
-__update_sh_run ./modules/by-name/fi/firefox/update_extensions.sh "$@"
 __update_sh_run ./pkgs/update_pkgs.sh "$@"
 
 # __update_sh_run nix flake check
-__update_sh_run ./build.sh
+__update_sh_run build.sh
 
 printf "\033[31;1m%s\033[0m\033[33;1m%s\033[0m\n" "Also update out-of-tree dependencies, like " "yt" 2>&1