{"id":21735173,"url":"https://github.com/0dpe/linux-journey","last_synced_at":"2026-04-16T17:32:04.885Z","repository":{"id":224279733,"uuid":"762464819","full_name":"0dpe/Linux-Journey","owner":"0dpe","description":"Linux stuff","archived":false,"fork":false,"pushed_at":"2025-03-15T23:50:43.000Z","size":551,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-16T00:23:30.533Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Nix","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/0dpe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-23T20:50:25.000Z","updated_at":"2025-03-15T23:50:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"5a513065-2f77-4baa-af08-54e5c09372bc","html_url":"https://github.com/0dpe/Linux-Journey","commit_stats":null,"previous_names":["0dpe/morse-quiz","0dpe/linux-journey"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dpe%2FLinux-Journey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dpe%2FLinux-Journey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dpe%2FLinux-Journey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/0dpe%2FLinux-Journey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/0dpe","download_url":"https://codeload.github.com/0dpe/Linux-Journey/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244712846,"owners_count":20497561,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-26T05:12:15.644Z","updated_at":"2026-04-16T17:32:04.873Z","avatar_url":"https://github.com/0dpe.png","language":"Nix","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Linux Journey\r\nStarted on Jun 20, 2024. Still updating.\r\n\r\n## Choosing\r\n\r\n### Linux Distribution\r\nDistro | Package Manager | Minimal | Comments\r\n-|-|-|-\r\n[PeppermintOS](https://peppermintos.com/) | Debian based | Yes | Small community; only xfce supported?\r\n[antiX Linux](https://antixlinux.com/) | Debian based | Extremely | Looks old\r\n[Tiny Core Linux](http://tinycorelinux.net/) | | Extremely | Advanced\r\n[Void Linux](https://voidlinux.org/) | XBPS (independent) | No\r\n[Arch Linux](https://archlinux.org/) | Pacman (AUR - independent) | Maybe | Great documentation\r\n:heavy_check_mark: [NixOS](https://nixos.org/) | Nix (independent) | No | [Has the most packages](https://repology.org/repositories/statistics/total \"Repology.org\"); clean config\r\n\r\n### [Display Server](https://en.wikipedia.org/wiki/Windowing_system#Display_server_communications_protocols \"Wikipedia\") \u0026 Window Manager\r\nX11 will be replaced by Wayland.\r\nCompositing \u003cbr\u003e Window Manager | Minimal \u003cbr\u003e Eyecandy | Comments \r\n-|-|-\r\n[Qtile](https://qtile.org/) | Neither | Written in Python\r\n[Sway](https://swaywm.org/) | Neither\r\n[dwl](https://codeberg.org/dwl/dwl) | Minimal | dwm fork\r\n[SwayFX](https://github.com/WillPower3309/swayfx) | Eyecandy | Inferior to Hyprland?\r\n[river](https://codeberg.org/river/river) | Minimal | Lacking wiki\r\n:heavy_check_mark: [Hyprland](https://hyprland.org/) | Eyecandy |  Great wiki\r\n\r\n### [Command Shell](https://wiki.archlinux.org/title/command-line_shell#List_of_shells \"Arch Wiki\")\r\nA *command shell* converts human commands to something the kernel understands. Use `$ echo $SHELL` to see the current command shell. NixOS by default uses Bourne-Again shell (bash). Popular modern command shells: \r\n* Friendly Interactive Shell (fish)\r\n* :heavy_check_mark: Z Shell (zsh)\r\n\r\n### Terminal Emulator\r\nTerminals provide access to the command shell. The TTY (*TeleTYpe* informally, *virtual terminal* formally, *framebuffer terminal* functionally; switch between TTYs using \u003ckbd\u003ectrl\u003c/kbd\u003e+\u003ckbd\u003ealt\u003c/kbd\u003e+\u003ckbd\u003eF#\u003c/kbd\u003e) does not support copy and paste, panels, scrolling, multitasking with multiple windows, etc... Therefore, a non-framebuffer terminal emulator is useful for using commands without having to switch out of the graphical environment.\r\n* [Alacritty](https://alacritty.org/): A cross-platform, OpenGL terminal emulator.\r\n* [Foot](https://codeberg.org/dnkl/foot): A fast, lightweight and minimalistic Wayland terminal emulator.\r\n* [Terminator](https://gnome-terminator.org/): Multiple GNOME terminals in one window!\r\n* [WezTerm](https://wezfurlong.org/wezterm/): A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust.\r\n* :heavy_check_mark: [kitty](https://sw.kovidgoyal.net/kitty/index.html): The fast, feature-rich, GPU based terminal emulator.\r\n\r\nNot included in Home Manager option documentation:\r\n* [Konsole](https://konsole.kde.org/): A powerful and customizable terminal emulator made by KDE.\r\n* [MLTERM](https://github.com/arakiken/mlterm): Multi Lingual TERMinal emulator.\r\n* [st](https://st.suckless.org/): A simple terminal implementation for X.\r\n* [Warp](https://www.warp.dev/): The terminal reimagined with AI and collaborative tools for better productivity.\r\n* [Contour](https://contour-terminal.org/): A modern \u0026 actually fast Terminal Emulator.\r\n* [Darktile](https://github.com/liamg/darktile): A GPU rendered terminal emulator designed for tiling window managers.\r\n\r\nNot in nixpkgs:\r\n* [Extraterm](https://extraterm.org/): The swiss army chainsaw of terminal emulators.\r\n* [Tabby](https://tabby.sh/): A terminal for the modern age.\r\n\r\n### [Web Engine](https://eylenburg.github.io/browser_engines.htm \"Eylenburg.github.io\") \u0026 [Browser](https://en.wikipedia.org/wiki/Web_browser#:~:text=hide-,Active,-Blink%2Dbased \"Wikipedia\")\r\n* Blink: Chromium\r\n* QtWebEngine (Chromium): Qutebrowser\r\n* :heavy_check_mark: Gecko: Firefox \r\n\r\nOther web engines have outdated browsers.\\\r\nText based browsers are interesting but impractical.\\\r\nForks of Firefox or Chromium are generally inferior. Edge, Brave, and Opera are modern but bloated.\r\n\r\n### Cursor Theme\r\nNumix, Gruppled, [Graphite](https://github.com/vinceliuice/Graphite-cursors), [Afterglow (recolored)](https://github.com/TeddyBearKilla/Afterglow-Cursors-Recolored), [McMojave](https://github.com/vinceliuice/McMojave-cursors), Breeze Hacked, Comix, [Bibata](https://github.com/ful1e5/Bibata_Cursor), Google inspired, [Phinger](https://github.com/phisch/phinger-cursors), Quintom, Whitesur, Vimix, Catppuccin, [Vanilla DMZ](https://www.gnome-look.org/p/999970/), OpenZone, Hackneyed, Borealis, Nordzy, [Simp1e](https://www.gnome-look.org/p/1932768), Volantes, :heavy_check_mark: [Capitaine](https://github.com/keeferrourke/capitaine-cursors/), ...\r\n\r\n### Wallpaper Manager\r\nWayland wallpaper managers (all in nixpkgs):\r\nManager | Animated | Transitions | Home \u003cbr\u003e Manager\r\n-|-|-|-\r\n[swaybg](https://github.com/swaywm/swaybg) | ? | ? | No\r\n[mpvpaper](https://github.com/GhostNaN/mpvpaper) | MPV | ? | No\r\n[Wallutils](https://github.com/xyproto/wallutils) | No | Yes | No\r\n[wbg](https://codeberg.org/dnkl/wbg) | No | No | No\r\n[hyprpaper](https://github.com/hyprwm/hyprpaper) | No | No | Yes\r\n[wpaperd](https://github.com/danyspin97/wpaperd) | No | Cross Fade | Yes\r\n:heavy_check_mark: [swww](https://github.com/LGFae/swww) | GIF | Yes | No (CLI)\r\n\r\n### Status bar\r\nWayland status bars (all in nixpkgs):\r\n* [eww](https://elkowar.github.io/eww): ElKowars wacky widgets (extreme, complicated customizability with its own language)\r\n* [ags](https://github.com/Aylur/ags): Scaffolding CLI for Astal+TypeScript (similar to eww but with TypeScript)\r\n* [Yambar](https://codeberg.org/dnkl/yambar): Modular status panel for X11 and Wayland (similar to Waybar but not as popular and not as many modules; does not support Hyprland by default)\r\n* [xmobar](https://codeberg.org/xmobar/xmobar): A minimalist status bar (originally designed to work with xmonad; Wayland support was an afterthought)\r\n* :heavy_check_mark: [Waybar](https://github.com/Alexays/Waybar): Highly customizable Wayland bar for Sway and Wlroots based compositors.\r\n\r\nNot included in Home Manager option documentation:\r\n* [HyprPanel](https://github.com/Jas-SinghFSU/HyprPanel): A Bar/Panel for Hyprland with extensive customizability. (only avaible through flake)\r\n* [Luastatus](https://github.com/shdown/luastatus): universal status bar content generator\r\n* [Fabric](https://wiki.ffpy.org/getting-started/introduction): The next-generation framework for building desktop widgets using Python (only available through flake)\r\n* [Ironbar](https://crates.io/crates/ironbar): Customisable Wayland gtk bar written in Rust.\r\n* [gBar](https://github.com/scorpion-26/gBar): Blazingly fast status bar written with GTK\r\n* [Root Bar](https://hg.sr.ht/~scoopta/rootbar): Root Bar is a bar for wlroots based wayland compositors such as sway and was designed to address the lack of good bars for wayland.\r\n* [sfwbar](https://github.com/LBCrion/sfwbar): S* Floating Window Bar\r\n* [nwg-panel](https://github.com/nwg-piotr/nwg-panel): GTK3-based panel for sway and Hyprland Wayland compositors\r\n* [ashell](https://github.com/MalpenZibo/ashell): A ready to go Wayland status bar for Hyprland (only available through flake)\r\n* [Quickshell](https://quickshell.outfoxxed.me/): Flexible toolkit for making desktop shells with QtQuick, targeting Wayland and X11 (only available through flake)\r\n\r\n## Installing NixOS\r\n\r\nInstalling NixOS minimal (no GNOME or KDE) on an HP ZHAN 66 Pro 14 G2:\r\n\r\n1. Download NixOS minimal [ISO image](https://nixos.org/download/#:~:text=without%20a%20desktop.-,Minimal%20ISO%20image,-The%20minimal%20installation \"NixOS.org\").\r\n\r\n1. Use [balenaEtcher](https://etcher.balena.io/#download-etcher) to flash the .iso to a USB.\r\n\r\n1. Plug the USB into the laptop and turn on the laptop.\\\r\n   Spam \u003ckbd\u003eesc\u003c/kbd\u003e while booting to open the HP startup menu.\\\r\n   [Disable secure boot](https://support.hp.com/us-en/document/ish_6930187-6931079-16#:~:text=Secure%20Boot%20settings%20for%20commercial%20notebooks%20and%20workstations \"HP Support\").\\\r\n   Select boot from USB in Boot Menu (\u003ckbd\u003eF9\u003c/kbd\u003e).\r\n\r\n1. Follow [manual](https://nixos.org/manual/nixos/stable/#sec-installation-manual \"NixOS Manual - Manual Installation\"): Networking (use following commands).\\\r\n   `# systemctl start wpa_supplicant`\\\r\n   `# wpa_cli`\\\r\n   `\u003e add_network` (`0` should appear)\\\r\n   `\u003e set_network 0 ssid \"CU_FS6D\"` (network called `CU_FS6D`)\\\r\n   `\u003e set_network 0 psk \"redacted\"` (using password `redacted` for `CU_FS6D`)\\\r\n   `\u003e set_network 0 key_mgmt WPA-PSK`\\\r\n   `\u003e enable_network 0`\\\r\n   If something like `\u003c3\u003eCTRL-EVENT-CONNECTED - Connection to 32:85:ab:ef:24:5c completed [id=0 id_str=]` appears, then the laptop has connection to the internet. Leave `wpa_cli` using `\u003e quit`.\\\r\n   Note: Also use `# ping www.baidu.com` to test the internet connection. Use \u003ckbd\u003ectrl\u003c/kbd\u003e+\u003ckbd\u003ec\u003c/kbd\u003e to quit `ping`.\r\n\r\n1. Follow [manual](https://nixos.org/manual/nixos/stable/#sec-installation-manual-partitioning \"NixOS Manual - Partitioning and formatting\"): Partitioning.\\\r\n   Turns out my laptop only has a single SSD drive, which means I have to install Linux and keep Windows on the same drive; I have to *dual boot* Windows 10 and Linux if I want to keep Windows. I could also [install Linux on a USB](https://www.reddit.com/r/linuxquestions/comments/romnib/comment/hpzbpnt/?utm_source=share\u0026utm_medium=web3x\u0026utm_name=web3xcss\u0026utm_term=1\u0026utm_content=share_button \"Reddit\"), but that seems iffy.\\\r\n   I ditch this installation and boot into Windows to [create a partition](https://youtu.be/GXxTxBPKecQ?t=115\u0026si=hTMWLO_NkSU4OVR2 \"YouTube\") for Linux on the same drive as Windows.\\\r\n   Note: To launch the Windows 10 partitioning software, search in Windows \"创建并格式换硬盘分区\".\\\r\n   I set up partitions. Windows displays that my drive has 476.92GB total (Why is it not 512GB?).\r\n   * Before:\r\n      1. 260MB: EFI系统分区\r\n      1. Windows (C:)\r\n      1. 930MB: 恢复分区\r\n   * After:\r\n      1. 260MB: EFI系统分区\r\n      1. 243.82GB: Windows (C:)\r\n      1. 231.93GB: 未分配\r\n      1. 930MB: 恢复分区\r\n\r\n1. Boot into Linux and follow manual to partitioning again.\\\r\n   `/dev/sda` is my USB; `/dev/nvme0n1` is my SSD drive. Using `# parted /dev/nvme0n1 print` only shows non-free partitions, which are all numbered and named. Using `# parted /dev/nvme0n1 print free` shows free or 未分配 partitions:\r\n   ```\r\n   Model: INTEL SSDPEKNW512G8H (nvme)\r\n   Disk /dev/nvme0n1: 512GB\r\n   Sector size (logical/physical): 512GB/512GB\r\n   Partition Table: gpt\r\n   Disk Flags:\r\n\r\n   Number  Start   End     Size    File system  Name                          Flags\r\n           17.4kB  1049kB  1031kB  Free Space\r\n    1      1049kB  274MB   273MB   fat32        EFI system partition          boot, esp, no_automount\r\n    2      274MB   290MB   16.8MB               Microsoft reserved partition  msftres, no_automount\r\n    3      290MB   262GB   262GB   ntfs         Basic data partition          msftdata\r\n           262GB   511GB   249GB   Free Space\r\n    4      511GB   512GB   975MB   ntfs         Basic data partition          hidden, diag, no_automount\r\n           512GB   512GB   5578kB  Free Space\r\n   ```\r\n   This shows that the 未分配 partition I created is the Free Space after number 3 with apparently 249GB. From here on, I have to slightly deviate from the NixOS manual, which assumes a clean SATA ([`/dev/sda`](https://unix.stackexchange.com/questions/510778/linux-block-devices-naming \"StackExchange\")) drive; I have an NVMe drive with Windows 10 and some partitions already configured. The manual recommends:\r\n   1. GPT partition table: `# parted /dev/sda -- mklabel gpt`\r\n   1. A *boot* partition (EFI system partition) of 512MiB at the start of the drive: `# parted /dev/sda -- mkpart ESP fat32 1MB 512MB` and `# parted /dev/sda -- set 3 esp on`\r\n   1. A *swap* (extended RAM) partition of 8GB at the end of the drive: `# parted /dev/sda -- mkpart swap linux-swap -8GB 100%`\r\n   1. A *root* partition as large as possible in between: `# parted /dev/sda -- mkpart root ext4 512MB -8GB`\r\n   \r\n   Since `/dev/nvme0n1` already has partition table: gpt, I can skip step 1.\\\r\n   Since [I know I'm using UEFI](https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/configure-uefigpt-based-hard-drive-partitions?view=windows-11#:~:text=When%20you%20deploy%20Windows%20to%20a%20UEFI%2Dbased%20device%2C%20you%20must%20format%20the%20hard%20drive%20that%20includes%20the%20Windows%20partition%20by%20using%20a%20GUID%20partition%20table%20(GPT)%20file%20system.%20Additional%20drives%20may%20use%20either%20the%20GPT%20or%20the%20master%20boot%20record%20(MBR)%20file%20format. \"Microsoft Learn\"), and [UEFI has only 1 EFI system partition](https://www.reddit.com/r/linuxquestions/comments/t7ypx8/comment/hzkpagr/?utm_source=share\u0026utm_medium=web3x\u0026utm_name=web3xcss\u0026utm_term=1\u0026utm_content=share_button \"Reddit\"), and Windows already created that partition with an *esp* flag, I can completely skip step 2.\\\r\n   I use `# parted /dev/nvme0n1 -- mkpart root ext4 262GB -10GB` for creating the root partition.\\\r\n   I use `# parted /dev/nvme0n1 -- mkpart swap linux-swap -10GB 510GB` for creating the swap partition.\\\r\n   Note: Partition 4 created by Windows (Basic data partition) is likely the Windows recovery partition, so I left 1GB of margin for error to make sure it doesn't get messed up; I use `510GB` instead of `511GB` for the swap partition.\\\r\n   After partitioning, `# parted /dev/nvme0n1 print free` shows (header incomplete):\r\n   ```\r\n   Number  Start   End     Size    File system  Name                          Flags\r\n           17.4kB  1049kB  1031kB  Free Space\r\n    1      1049kB  274MB   273MB   fat32        EFI system partition          boot, esp, no_automount\r\n    2      274MB   290MB   16.8MB               Microsoft reserved partition  msftres, no_automount\r\n    3      290MB   262GB   262GB   ntfs         Basic data partition          msftdata\r\n    5      262GB   502GB   240GB                root\r\n    6      502GB   510GB   7889MB               swap                          swap\r\n           510GB   511GB   1129MB  Free Space\r\n    4      511GB   512GB   975MB   ntfs         Basic data partition          hidden, diag, no_automount\r\n           512GB   512GB   5578kB  Free Space\r\n   ```\r\n\r\n1. Follow [manual](https://nixos.org/manual/nixos/stable/#sec-installation-manual-partitioning-formatting \"NixOS Manual - Formatting\"): Formatting.\\\r\n   I use `# mkfs.ext4 -L nixos /dev/nvme0n1p5` to my format my root partition (number 5).\\\r\n   I use `# mkswap -L swap /dev/nvme0n1p6` to format my swap partition (number 6).\\\r\n   Note: I still use `-L` to label the partitions even though they already have names because filesystem labels are different from partition names. Filesystem labels are used to mount partitions in the next step.\\\r\n   Note: Boot partition (EFI system partition; number 1) is already formatted.\\\r\n   After formatting, `# parted /dev/nvme0n1 print free` shows (incomplete):\r\n   ```\r\n   Number  Start  End    Size    File system     Name  Flags\r\n    5      262GB  502GB  240GB   ext4            root\r\n    6      502GB  510GB  7889MB  linux-swap(v1)  swap  swap\r\n   ```\r\n\r\n1. Follow [manual](https://nixos.org/manual/nixos/stable/#sec-installation-manual-installing \"NixOS Manual - Installing\"): Mounting.\\\r\n   Note: Saying \"*mount A to B*\" means \"*make the contents of A accessible at location B*\".\\\r\n   I use `# mount /dev/disk/by-label/nixos /mnt` to mount my root partition to `/mnt`, which exists by default in the root filesystem of my *live environment*, which is a complete but temporary OS running in RAM using read-only storage in the USB. Use `# ls /` (`/` is the root filesystem) to see `mnt`: `bin  dev  etc  home  iso  mnt  nix  proc  root  run  srv  sys  tmp  usr  var`. Here, the `mount` command creates a \"bridge\" between the partition on the disk and the live environment. After installation, the live environment \"dies\", meaning the temporary OS along with its files won't be accessible anymore. Also, the command uses the filesystem label; for me, it is equivalent to `# mount /dev/nvme0n1p5 /mnt`.\\\r\n   I use `# mkdir -p /mnt/boot` then `# mount -o umask=077 /dev/nvme0n1p1 /mnt/boot` to mount Windows' EFI system partition to `/mnt/boot`. [`-o umask=077`](https://en.wikipedia.org/wiki/Umask#Command_line_examples \"Wikipedia\") specifies an option that sets the permission for the newly created directory; 077 means that the owner has full permissions (read, write, execute), and no permissions for everyone else (this only affects Linux, not Windows). I could maybe use `# mount -o umask=077 /dev/disk/by-label/boot /mnt/boot`, but I do not know for sure if Windows' boot partition has the filesystem label `boot`.\\\r\n   I use `# swapon /dev/disk/by-label/swap` to enable swap. Equivalent to `# swapon /dev/nvme0n1p6` for me.\r\n\r\n1. Follow [manual](https://nixos.org/manual/nixos/stable/#sec-installation-manual-installing \"NixOS Manual - Installing\"): Configure NixOS and install.\\\r\n   Generate the NixOS configuration file using `# nixos-generate-config --root /mnt`.\\\r\n   Note: Using `# ls /mnt/etc/nixos` now shows `configuration.nix  hardware-configuration.nix`.\\\r\n   Edit the NixOS configuration using `# nano /mnt/etc/nixos/configuration.nix`.\\\r\n   I'm using UEFI, and `boot.loader.systemd-boot.enable = true;` and `boot.loader.efi.canTouchEfiVariables = true;` have already been automatically uncommented, so I don't have to change that.\\\r\n   Uncomment or edit:\r\n   ```nix\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     imports =\r\n       [\r\n         ./hardware-configuration.nix\r\n       ];\r\n   \r\n     boot.loader = {\r\n       systemd-boot.enable = true;\r\n       efi.canTouchEfiVariables = true;\r\n     };\r\n\r\n     networking = {\r\n       hostName = \"ZHAN\";\r\n       networkmanager.enable = true;\r\n     };\r\n\r\n     time.timeZone = \"America/New_York\";\r\n\r\n     services = {\r\n       libinput.enable = true;\r\n     };\r\n\r\n     users = {\r\n       users.tim = {\r\n         isNormalUser = true;\r\n         extraGroups = [ \"wheel\" \"networkmanager\" ];\r\n       };\r\n     };\r\n\r\n     system.stateVersion = \"24.05\";\r\n   }\r\n   ```\r\n   Press \u003ckbd\u003ectrl\u003c/kbd\u003e+\u003ckbd\u003eo\u003c/kbd\u003e, \u003ckbd\u003eenter\u003c/kbd\u003e, and \u003ckbd\u003ectrl\u003c/kbd\u003e+\u003ckbd\u003ex\u003c/kbd\u003e to save `configuration.nix` and exit `nano`.\\\r\n   Install NixOS using `# nixos-install`. Wait for a few minutes.\\\r\n   Set the root password as prompted.\\\r\n   Reboot using `# reboot`.\\\r\n   Reboot automatically booted into Windows 10. Shutdown and turn on laptop to access HP startup menu again.\\\r\n   Select \"UEFI - Linux Boot Manager\" from Boot Menu (\u003ckbd\u003eF9\u003c/kbd\u003e).\r\n\r\n1. Login to NixOS by typing `root` for `ZHAN login:` and my root password for `Password:`.\\\r\n   Use `# passwd tim` to set the password for `tim` as prompted. \r\n\r\nDone! Unplug the USB.\\\r\n[Revert bootable USB to storage USB](https://blog.balena.io/did-etcher-break-my-usb-sd-card/ \"Balena Blog\").\r\n\r\n## Using NixOS\r\n\r\n### Connecting to the Internet\r\nUsing `# systemctl start wpa_supplicant` and then `# wpa_cli` doesn't work anymore. `Could not connect to wpa_supplicant: (nil) - re-trying`. This is probably because in `configuration.nix`:\r\n```nix\r\n# Pick only one of the below networking options.\r\n# networking.wireless.enable = true;\r\nnetworking.networkmanager.enable = true; # Easiest to use and most distros use this by default.\r\n```\r\nAnyways, since `networking.networkmanager.enable = true;` was uncommented, I can use that.\r\n* Use `$ nmcli device wifi list` to list available wifi.\r\n* Use `$ nmcli device wifi connect \"CU_FS6D\" password \"redacted\"` to connect.\\\r\nSeems like it automatically connects at each boot.\r\n\r\n### Using [Flakes](https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-flake \"Nix Reference Manual\") (and the [new CLI](https://nixos-and-flakes.thiscute.world/nixos-with-flakes/introduction-to-flakes#the-new-cli-and-the-classic-cli \"NixOS \u0026 Flakes Book\"))\r\n[Nixpkgs](https://github.com/NixOS/nixpkgs/tree/nixos-unstable \"GitHub\") is the git repository containing many packages. A *[channel](https://nixos.wiki/wiki/Nix_channels \"NixOS Wiki\")* is a branch of a repository such as nixpkgs; the current nixpkgs stable channel is 24.05. Use `# nix-channel --list` to see `nixos https://nixos.org/channels/nixos-24.05`; my NixOS is currently following the nixpkgs stable channel. Before flakes existed, packages in NixOS had to be *imperatively* (opposite of *declaratively*) updated through using commands like `# nix-channel --update`, and using commands was required for adding new channels to use and update packages outside the nixpkgs repository (such as Home Manager with commands like `nix-channel --add https://github.com/branch-of-home-manager`).\r\n\r\nGreat resources for understanding flakes:\r\n* [Nix flakes explained](https://youtu.be/S3VBi6kHw5c \"YouTube\"): Using flakes to create a nix shell.\r\n* [Ultimate NixOS Guide | Flakes | Home-manager](https://www.youtube.com/watch?v=a67Sv4Mbxmc\u0026t=360s \"YouTube\"): Advantages of flakes and using flakes to configure NixOS.\r\n* [NixOS with Flakes](https://nixos-and-flakes.thiscute.world/nixos-with-flakes/nixos-with-flakes-enabled \"NixOS \u0026 Flakes Book\"): General guides for flakes, modules, and Home Manager.\r\n* [Intro Flake Config Setup for New NixOS Users](https://librephoenix.com/2023-10-21-intro-flake-config-setup-for-new-nixos-users#org990add0 \"LibrePhoenix's Tech Nest Blog\"): Structure and syntax of a flake explained.\r\n* [Ultimate Nix Flakes Guide](https://youtu.be/JCeYq72Sko0 \"YouTube\"): Comprehensive guide for flakes.\r\n\r\nNix is the programming language used primarily by NixOS. Flakes are simply Nix programs (`flake.nix` files) that have specific agreed upon structures making them do specific things. They all have *input* and *output* parts. This [flake template](https://github.com/NixOS/templates/blob/master/full/flake.nix \"GitHub\") lists common inputs and outputs and their use cases. Briefly speaking:\r\n* [Inputs](https://nixos-and-flakes.thiscute.world/other-usage-of-flakes/inputs \"NixOS \u0026 Flakes Book\") can be git repositories, local paths, or other flakes.\r\n* [Outputs](https://nixos-and-flakes.thiscute.world/other-usage-of-flakes/outputs \"NixOS \u0026 Flakes Book\") can be pretty much anything; some are recognized and used by NixOS.\r\n\r\n`flake.lock` files are automatically created with `flake.nix` files. `flake.lock` files store information about the exact versions of the input(s) at the time the lock file was created (or updated). Therefore, the outputs of `flake.nix` with `flake.lock` are *deterministic* and *reproducible* since the inputs are *locked*.\\\r\nAn output for flakes used by NixOS is `nixosConfigurations`. So, I can declaratively set a flake's input as the nixpkgs unstable channel and its output as OS configurations. The `flake.lock` file generated with this flake specifies the version of the channel. I can use [`# nix flake update`](https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-flake-update#name \"Nix Reference Manual\") to update the `flake.lock` file; I no longer use `# nix-channel --update`.\r\n\r\nEnable flakes for NixOS:\r\n1. Flakes is still an experimental feature; enable it by adding in `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n     \r\n   + nix.settings.experimental-features = [ \"nix-command\" \"flakes\" ];\r\n\r\n   + programs = {\r\n   +   git.enable = true;\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n1. Connect to internet. Use `# nixos-rebuild switch`.\r\n\r\nSwitch system configuration to a flake:\r\n1. Use `$ cd /etc/nixos` then [`# nix flake init`](https://nix.dev/manual/nix/2.18/command-ref/new-cli/nix3-flake-init#name \"Nix Reference Manual\") to create or initialize a flake file in `/etc/nixos`.\\\r\n   Note: Use `$ ls` to see `configuration.nix  flake.nix  hardware-configuration.nix`.\r\n1. Edit `flake.nix`:\r\n   ```nix\r\n   {\r\n     description = \"NixOS configuration flake\";\r\n\r\n     inputs = {\r\n       nixpkgs.url = \"github:nixos/nixpkgs/nixos-unstable\";\r\n     };\r\n\r\n     outputs = { nixpkgs, ... }: {\r\n       nixosConfigurations.ZHAN = nixpkgs.lib.nixosSystem {\r\n         system = \"x86_64-linux\";\r\n         modules = [\r\n           ./configuration.nix\r\n         ];\r\n       };\r\n     };\r\n   }\r\n   ```\r\n   The input is the nixpkgs unstable channel, the git repository. The output is `nixosConfigurations` of `ZHAN`. `ZHAN` is my hostname; with the flakes experimental feature enabled, [`# nixos-rebuild switch`](https://nixos.wiki/wiki/Nixos-rebuild#with_Flakes \"NixOS Wiki\") by default looks for the file `/etc/nixos/flake.nix` and builds the `nixosConfigurations` item matching the current hostname of the OS. To specify a different flake directory and hostname, use `# nixos-rebuild switch --flake /path/to/flake#hostname`. `configuration.nix` is included; `.` is a navigation shortcut for the current directory (on a side note, `..` is the *parent* directory). \r\n1. Connect to internet. Use `# nixos-rebuild switch`. Wait a few minutes.\\\r\n   A `flake.lock` file is generated in `/etc/nixos`; use `$ ls` to see `configuration.nix  flake.lock  flake.nix  hardware-configuration.nix`.\r\n\r\n### Installing [Home Manager](https://nix-community.github.io/home-manager/index.xhtml#ch-introduction \"Home Manager Manual\")\r\nFiles or directories that have names beginning with `.` like the directory `/home/tim/.config/` are called *dotfiles*. Dotfiles are hidden by default; use `$ ls -a` to see them. Dotfiles typically store configuration settings.\\\r\nHome Manager translates `.nix` files to dotfiles and creates *symlinks* (similar to shortcuts in Windows) for the dotfiles for programs like Firefox and Hyprland to use. This allows me to declare configurations for user specific programs with `.nix` files so I don't have to edit dotfiles, just like how I declare settings in `configuration.nix` for the OS. Home Manager also supports rollbacks.\\\r\nNote: Home Manager can be used to declare or install packages for specific users, but that's [not useful](https://discourse.nixos.org/t/why-does-home-manager-also-have-an-option-to-install-user-packages/33982 \"NixOS Help\") for me.\\\r\nHome Manager can be installed [2 different ways](https://www.youtube.com/watch?v=IiyBeR-Guqw\u0026t=198s \"YouTube\") in NixOS:\r\n* Standalone: Manage dotfiles independent from the OS. No root permission required. Works on other Linux distributions.\r\n* NixOS Module: Manage dotfiles through the OS for all users. Root permission required.\r\n\r\nInstall Home Manager as a NixOS module:\r\n1. Edit `flake.nix`:\r\n   ```diff\r\n   {\r\n     description = \"NixOS configuration flake\";\r\n   \r\n     inputs = {\r\n       nixpkgs.url = \"github:nixos/nixpkgs/nixos-unstable\";\r\n       \r\n   +   home-manager.url = \"github:nix-community/home-manager\";\r\n   +   home-manager.inputs.nixpkgs.follows = \"nixpkgs\";\r\n     };\r\n   \r\n   - outputs = { nixpkgs, ... }: {\r\n   + outputs = { nixpkgs, home-manager, ... }: {\r\n       nixosConfigurations.ZHAN = nixpkgs.lib.nixosSystem {\r\n         system = \"x86_64-linux\";\r\n         modules = [\r\n           ./configuration.nix\r\n   +       home-manager.nixosModules.home-manager\r\n   +       {\r\n   +         home-manager.useGlobalPkgs = true;\r\n   +         home-manager.useUserPackages = true;\r\n   +         home-manager.users.tim = import ./home.nix;\r\n   +       }\r\n         ];\r\n       };\r\n     };\r\n   }\r\n   ```\r\n   Since Home Manager [isn't](https://discourse.nixos.org/t/why-isnt-more-of-home-manager-merged-into-nixpkgs/6096/12 \"NixOS Help\") part of the nixpkgs repository, it is installed through adding its channel in the inputs of the flake. `home-manager.inputs.nixpkgs.follows = \"nixpkgs\";` [reduces](https://drakerossman.com/blog/how-to-add-home-manager-to-nixos#how-to-add-home-manager-to-your-system:~:text=The%20home%2Dmanager,scenario%20is%20unlikely \"Drake Rossman's Website\") the number of inputs the flake depends on; packages installed through Home Manager will still be installed from the same `nixos-unstable` branch used for `configuration.nix`. [`useGlobalPkgs`](https://nix-community.github.io/home-manager/nixos-options.xhtml#nixos-opt-home-manager.useGlobalPkgs \"Home Manager Manual\") and [`useUserPackages`](https://nix-community.github.io/home-manager/nixos-options.xhtml#nixos-opt-home-manager.useUserPackages \"Home Manager Manual\") explained [here](https://nix-community.github.io/home-manager/index.xhtml#sec-install-nixos-module \"Home Manager Manual\"). Since Home Manager is inside `modules` of ``nixosSystem`, Home Manager will be rebuilt whenever the system is rebuilt, which is an effect of installing Home Manager as a NixOS module.\\ \r\n   Note: To install Home Manager standalone with flakes, `homeConfigurations.ZHAN = home-manager.lib.homeManagerConfiguration { # ... }` would be used inside `flake.nix` right beside `nixosConfigurations.ZHAN = nixpkgs.lib.nixosSystem { # ... }`. \r\n1. Create and edit `/etc/nixos/home.nix` (unlike non-flake setups, `home.nix` must be present [before](https://nix-community.github.io/home-manager/index.xhtml#sec-flakes-prerequisites \"Home Manager Manual\") the flake is built):\r\n   ```nix\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     home = {\r\n       username = \"tim\";\r\n       homeDirectory = \"/home/tim\";\r\n       stateVersion = \"24.05\";\r\n     };\r\n\r\n     programs.home-manager.enable = true;\r\n   }\r\n   ```\r\n   Note: `home.nix` is in the same directory as `flake.nix` because `import ./home.nix` is specified in the flake.\r\n1. Connect to internet. Use `# nixos-rebuild switch`.\\\r\n   `flake.lock` is automatically updated and now contains version information about both `nixpkgs` and `home-manager`.\\\r\n   See [available options](https://nix-community.github.io/home-manager/options.xhtml \"Home Manager Manual\") to edit `home.nix`.\r\n\r\n### iwlwifi Boot Bug (Jul 8, 2024)\r\nProblem:\r\n* During boot, error messages appear (filtered to only `iwlwifi`):\r\n   \u003cdetails\u003e\u003csummary\u003eMessages\u003c/summary\u003e\r\n\r\n   ```\r\n   [    5.962536] iwlwifi 0000:00:14.3: enabling device (0000 -\u003e 0002)\r\n   [    5.963629] iwlwifi 0000:00:14.3: Detected crf-id 0x2816, cnv-id 0x1000100 wfpm id 0x80000000\r\n   [    5.963635] iwlwifi 0000:00:14.3: PCI dev 9df0/0034, rev=0x312, rfid=0x105110\r\n   [    5.980414] iwlwifi 0000:00:14.3: WRT: Overriding region id 0\r\n   [    5.980417] iwlwifi 0000:00:14.3: WRT: Overriding region id 1\r\n   [    5.980419] iwlwifi 0000:00:14.3: WRT: Overriding region id 2\r\n   [    5.980420] iwlwifi 0000:00:14.3: WRT: Overriding region id 3\r\n   [    5.980421] iwlwifi 0000:00:14.3: WRT: Overriding region id 4\r\n   [    5.980422] iwlwifi 0000:00:14.3: WRT: Overriding region id 6\r\n   [    5.980423] iwlwifi 0000:00:14.3: WRT: Overriding region id 8\r\n   [    5.980424] iwlwifi 0000:00:14.3: WRT: Overriding region id 9\r\n   [    5.980425] iwlwifi 0000:00:14.3: WRT: Overriding region id 10\r\n   [    5.980426] iwlwifi 0000:00:14.3: WRT: Overriding region id 11\r\n   [    5.980427] iwlwifi 0000:00:14.3: WRT: Overriding region id 15\r\n   [    5.980428] iwlwifi 0000:00:14.3: WRT: Overriding region id 16\r\n   [    5.980429] iwlwifi 0000:00:14.3: WRT: Overriding region id 18\r\n   [    5.980430] iwlwifi 0000:00:14.3: WRT: Overriding region id 19\r\n   [    5.980431] iwlwifi 0000:00:14.3: WRT: Overriding region id 20\r\n   [    5.980432] iwlwifi 0000:00:14.3: WRT: Overriding region id 21\r\n   [    5.980433] iwlwifi 0000:00:14.3: WRT: Overriding region id 28\r\n   [    5.980875] iwlwifi 0000:00:14.3: loaded firmware version 46.7e3e4b69.0 9000-pu-b0-jf-b0-46.ucode op_mode iwlmvm\r\n   [    6.495945] iwlwifi 0000:00:14.3: Detected Intel(R) Wireless-AC 9560 160MHz, REV=0x312\r\n   [   11.906805] iwlwifi 0000:00:14.3: Failed to load firmware chunk!\r\n   [   11.906930] iwlwifi 0000:00:14.3: iwlwifi transaction failed, dumping registers\r\n   [   11.906975] iwlwifi 0000:00:14.3: iwlwifi device config registers:\r\n   [   11.907150] iwlwifi 0000:00:14.3: 00000000: 9df08086 00100406 02800011 00800000 f4210004 00000000 00000000 00000000\r\n   [   11.907205] iwlwifi 0000:00:14.3: 00000020: 00000000 00000000 00000000 00348086 00000000 000000c8 00000000 000001ff\r\n   [   11.907259] iwlwifi 0000:00:14.3: 00000040: 00928010 10000ec0 00100c10 00000000 00000000 00000000 00000000 00000000\r\n   [   11.907336] iwlwifi 0000:00:14.3: 00000060: 00000000 00080812 00000405 00000000 00000000 00000000 00000000 00000000\r\n   [   11.907389] iwlwifi 0000:00:14.3: 00000080: 000f0011 00002000 00003000 00000000 00000000 00000000 00000000 00000000\r\n   [   11.907441] iwlwifi 0000:00:14.3: 000000a0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000\r\n   [   11.907494] iwlwifi 0000:00:14.3: 000000c0: 00000000 00000000 c823d001 0d000008 00814005 fee00478 00000000 00000000\r\n   [   11.907546] iwlwifi 0000:00:14.3: 000000e0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000\r\n   [   11.907599] iwlwifi 0000:00:14.3: 00000100: 14c00000 ff000000 000000ff 00462031 00000000 00002000 00000000 00000000\r\n   [   11.907652] iwlwifi 0000:00:14.3: 00000120: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000\r\n   [   11.907704] iwlwifi 0000:00:14.3: 00000140: 00000000 00000000 00000000 16410018 00000000 0001001e 00481e1f 00000000\r\n   [   11.907755] iwlwifi 0000:00:14.3: iwlwifi device memory mapped registers:\r\n   [   11.907814] iwlwifi 0000:00:14.3: 00000000: 18c89002 00000040 00000000 08000000 00000000 00000000 00000000 00000000\r\n   [   11.907868] iwlwifi 0000:00:14.3: 00000020: 00000010 0c000005 00000312 d55555d5 d55555d5 d55555d5 80008040 001f0042\r\n   [   11.907946] iwlwifi 0000:00:14.3: Could not load the [0] uCode section\r\n   [   11.907991] iwlwifi 0000:00:14.3: Failed to start INIT ucode: -110\r\n   [   11.908029] iwlwifi 0000:00:14.3: WRT: Collecting data: ini trigger 13 fired (delay=0ms).\r\n   [   12.158282] iwlwifi 0000:00:14.3: Not valid error log pointer 0x00000000 for Init uCode\r\n   [   12.158301] iwlwifi 0000:00:14.3: IML/ROM dump:\r\n   [   12.158308] iwlwifi 0000:00:14.3: 0x00000003 | IML/ROM error/state\r\n   [   12.158339] iwlwifi 0000:00:14.3: 0x00000001 | IML/ROM data1\r\n   [   12.158350] iwlwifi 0000:00:14.3: Fseq Registers:\r\n   [   12.158374] iwlwifi 0000:00:14.3: 0x14163D33 | FSEQ_ERROR_CODE\r\n   [   12.158383] iwlwifi 0000:00:14.3: 0x00000000 | FSEQ_TOP_INIT_VERSION\r\n   [   12.158393] iwlwifi 0000:00:14.3: 0xA538284A | FSEQ_CNVIO_INIT_VERSION\r\n   [   12.158402] iwlwifi 0000:00:14.3: 0x0000A384 | FSEQ_OTP_VERSION\r\n   [   12.158412] iwlwifi 0000:00:14.3: 0x371909C7 | FSEQ_TOP_CONTENT_VERSION\r\n   [   12.158421] iwlwifi 0000:00:14.3: 0xB6FEED1F | FSEQ_ALIVE_TOKEN\r\n   [   12.158430] iwlwifi 0000:00:14.3: 0x6565DF70 | FSEQ_CNVI_ID\r\n   [   12.158439] iwlwifi 0000:00:14.3: 0xA4EAB9C6 | FSEQ_CNVR_ID\r\n   [   12.158448] iwlwifi 0000:00:14.3: 0x01000100 | CNVI_AUX_MISC_CHIP\r\n   [   12.158460] iwlwifi 0000:00:14.3: 0x01300202 | CNVR_AUX_MISC_CHIP\r\n   [   12.158838] iwlwifi 0000:00:14.3: 0x0000485B | CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM\r\n   [   12.159245] iwlwifi 0000:00:14.3: 0xA5A5A5A2 | CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR\r\n   [   12.159658] iwlwifi 0000:00:14.3: 0x3BF53F5D | FSEQ_PREV_CNVIO_INIT_VERSION\r\n   [   12.160056] iwlwifi 0000:00:14.3: 0xE6DA90F4 | FSEQ_WIFI_FSEQ_VERSION\r\n   [   12.160471] iwlwifi 0000:00:14.3: 0x50154F5B | FSEQ_BT_FSEQ_VERSION\r\n   [   12.160847] iwlwifi 0000:00:14.3: 0x6543892F | FSEQ_CLASS_TP_VERSION\r\n   [   12.653870] iwlwifi 0000:00:14.3: Master Disable Timed Out, 100 usec\r\n   [   12.665455] iwlwifi 0000:00:14.3: Failed to run INIT ucode: -110\r\n   [   12.678376] iwlwifi 0000:00:14.3: retry init count 0\r\n   [   12.679991] iwlwifi 0000:00:14.3: Detected Intel(R) Wireless-AC 9560 160MHz, REV=0x312\r\n   [   18.050795] iwlwifi 0000:00:14.3: Failed to load firmware chunk!\r\n   [   18.052671] iwlwifi 0000:00:14.3: Could not load the [0] uCode section\r\n   [   18.054516] iwlwifi 0000:00:14.3: Failed to start INIT ucode: -110\r\n   [   18.056094] iwlwifi 0000:00:14.3: WRT: Collecting data: ini trigger 13 fired (delay=0ms).\r\n   [   18.305373] iwlwifi 0000:00:14.3: Not valid error log pointer 0x00000000 for Init uCode\r\n   [   18.305769] iwlwifi 0000:00:14.3: IML/ROM dump:\r\n   [   18.306161] iwlwifi 0000:00:14.3: 0x00000003 | IML/ROM error/state\r\n   [   18.306594] iwlwifi 0000:00:14.3: 0x00000001 | IML/ROM data1\r\n   [   18.307015] iwlwifi 0000:00:14.3: Fseq Registers:\r\n   [   18.307461] iwlwifi 0000:00:14.3: 0x14163D33 | FSEQ_ERROR_CODE\r\n   [   18.307884] iwlwifi 0000:00:14.3: 0x00000000 | FSEQ_TOP_INIT_VERSION\r\n   [   18.308271] iwlwifi 0000:00:14.3: 0xA538284A | FSEQ_CNVIO_INIT_VERSION\r\n   [   18.308696] iwlwifi 0000:00:14.3: 0x0000A384 | FSEQ_OTP_VERSION\r\n   [   18.309121] iwlwifi 0000:00:14.3: 0x371909C7 | FSEQ_TOP_CONTENT_VERSION\r\n   [   18.309558] iwlwifi 0000:00:14.3: 0xB6FEED1F | FSEQ_ALIVE_TOKEN\r\n   [   18.309980] iwlwifi 0000:00:14.3: 0x6565DF70 | FSEQ_CNVI_ID\r\n   [   18.310400] iwlwifi 0000:00:14.3: 0xA4EAB9C6 | FSEQ_CNVR_ID\r\n   [   18.310821] iwlwifi 0000:00:14.3: 0x01000100 | CNVI_AUX_MISC_CHIP\r\n   [   18.311207] iwlwifi 0000:00:14.3: 0x01300202 | CNVR_AUX_MISC_CHIP\r\n   [   18.311646] iwlwifi 0000:00:14.3: 0x0000485B | CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM\r\n   [   18.312098] iwlwifi 0000:00:14.3: 0xA5A5A5A2 | CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR\r\n   [   18.312526] iwlwifi 0000:00:14.3: 0x3BF53F5D | FSEQ_PREV_CNVIO_INIT_VERSION\r\n   [   18.312939] iwlwifi 0000:00:14.3: 0xE6DA90F4 | FSEQ_WIFI_FSEQ_VERSION\r\n   [   18.313313] iwlwifi 0000:00:14.3: 0x50154F5B | FSEQ_BT_FSEQ_VERSION\r\n   [   18.313741] iwlwifi 0000:00:14.3: 0x6543892F | FSEQ_CLASS_TP_VERSION\r\n   [   18.510910] iwlwifi 0000:00:14.3: Master Disable Timed Out, 100 usec\r\n   [   18.522493] iwlwifi 0000:00:14.3: Failed to run INIT ucode: -110\r\n   [   18.535348] iwlwifi 0000:00:14.3: retry init count 1\r\n   [   18.537039] iwlwifi 0000:00:14.3: Detected Intel(R) Wireless-AC 9560 160MHz, REV=0x312\r\n   [   23.682797] iwlwifi 0000:00:14.3: Failed to load firmware chunk!\r\n   [   23.684352] iwlwifi 0000:00:14.3: Could not load the [0] uCode section\r\n   [   23.685890] iwlwifi 0000:00:14.3: Failed to start INIT ucode: -110\r\n   [   23.688076] iwlwifi 0000:00:14.3: WRT: Collecting data: ini trigger 13 fired (delay=0ms).\r\n   [   23.937339] iwlwifi 0000:00:14.3: Not valid error log pointer 0x00000000 for Init uCode\r\n   [   23.937743] iwlwifi 0000:00:14.3: IML/ROM dump:\r\n   [   23.938118] iwlwifi 0000:00:14.3: 0x00000003 | IML/ROM error/state\r\n   [   23.938538] iwlwifi 0000:00:14.3: 0x00000001 | IML/ROM data1\r\n   [   23.939130] iwlwifi 0000:00:14.3: Fseq Registers:\r\n   [   23.939589] iwlwifi 0000:00:14.3: 0x14163D33 | FSEQ_ERROR_CODE\r\n   [   23.939991] iwlwifi 0000:00:14.3: 0x00000000 | FSEQ_TOP_INIT_VERSION\r\n   [   23.940395] iwlwifi 0000:00:14.3: 0xA538284A | FSEQ_CNVIO_INIT_VERSION\r\n   [   23.940932] iwlwifi 0000:00:14.3: 0x0000A384 | FSEQ_OTP_VERSION\r\n   [   23.941293] iwlwifi 0000:00:14.3: 0x371909C7 | FSEQ_TOP_CONTENT_VERSION\r\n   [   23.941783] iwlwifi 0000:00:14.3: 0xB6FEED1F | FSEQ_ALIVE_TOKEN\r\n   [   23.942136] iwlwifi 0000:00:14.3: 0x6565DF70 | FSEQ_CNVI_ID\r\n   [   23.942526] iwlwifi 0000:00:14.3: 0xA4EAB9C6 | FSEQ_CNVR_ID\r\n   [   23.943049] iwlwifi 0000:00:14.3: 0x01000100 | CNVI_AUX_MISC_CHIP\r\n   [   23.943441] iwlwifi 0000:00:14.3: 0x01300202 | CNVR_AUX_MISC_CHIP\r\n   [   23.943921] iwlwifi 0000:00:14.3: 0x0000485B | CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM\r\n   [   23.944328] iwlwifi 0000:00:14.3: 0xA5A5A5A2 | CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR\r\n   [   23.944795] iwlwifi 0000:00:14.3: 0x3BF53F5D | FSEQ_PREV_CNVIO_INIT_VERSION\r\n   [   23.945148] iwlwifi 0000:00:14.3: 0xE6DA90F4 | FSEQ_WIFI_FSEQ_VERSION\r\n   [   23.945541] iwlwifi 0000:00:14.3: 0x50154F5B | FSEQ_BT_FSEQ_VERSION\r\n   [   23.946069] iwlwifi 0000:00:14.3: 0x6543892F | FSEQ_CLASS_TP_VERSION\r\n   [   24.143873] iwlwifi 0000:00:14.3: Master Disable Timed Out, 100 usec\r\n   [   24.155544] iwlwifi 0000:00:14.3: Failed to run INIT ucode: -110\r\n   [   24.169271] iwlwifi 0000:00:14.3: retry init count 2\r\n   ```\r\n   \u003c/details\u003e\r\n* After boot, using `$ nmcli device wifi list` shows nothing. \r\n\r\nFix:\r\n1. Enter HP startup menu.\r\n1. Select BIOS Setup (\u003ckbd\u003eF10\u003c/kbd\u003e).\\\r\n   Go to Advanced tab.\\\r\n   Select Built-In Device Options.\\\r\n   Uncheck Wireless Network Device (WLAN).\r\n1. Boot into NixOS. No iwlwifi logs appear.\r\n1. Reboot to enter HP startup menu again.\r\n1. Check Wireless Network Device (WLAN).\r\n1. Boot into NixOS again.\\\r\n   Wifi works again; using `$ nmcli device wifi list` shows that I am connected.\r\n\r\nPossible cause:\\\r\nI did not completely shut down Windows 10 before booting into NixOS. Upon shutting down NixOS and booting into Windows 10, I see that Astrill VPN is still connected. So, Astrill VPN may have been connected while I first booted into NixOS; I disconnected Astrill VPN and shut down Windows 10, but upon booting into NixOS afterwards, the problem persisted.\r\n\r\n### Using Zsh\r\nIn `configuration.nix`, add:\r\n```diff\r\n{ pkgs, ... }:\r\n\r\n{\r\n  # ...\r\n\r\n  users = {\r\n    # ...\r\n+   defaultUserShell = pkgs.zsh;\r\n  };\r\n\r\n  programs = {\r\n    # ...\r\n+   zsh = {\r\n+     enable = true;\r\n+     autosuggestions.enable = true;\r\n+   };\r\n  };\r\n\r\n  # ...\r\n}\r\n```\r\nConnect to internet. Use `# nixos-rebuild switch` and reboot. Use `$ echo $SHELL` to see `/run/current-system/sw/bin/zsh`.\\\r\nNavigate in the zsh menu to generate `/home/tim/.zshrc`:\r\n```zsh\r\n# Lines configured by zsh-newuser-install\r\n# End of lines configured by zsh-newuser-install\r\n# The following lines were added by compinstall\r\nzstyle :compinstall filename '/home/tim/.zshrc'\r\n\r\nautoload -Uz compinit\r\ncompinit\r\n# End of lines added by compinstall\r\n```\r\nSince I don't need to further configure zsh yet, I do not use Home Manager for zsh.\r\n\r\n### Using [Hyprland](https://wiki.hyprland.org/ \"Hyprland Wiki\")\r\nHyprland can be installed 2 ways:\r\n* From the branch of nixpkgs defined in the flake input.\r\n* From the Hyprland git repository by defining a separate flake input.\r\n\r\nSince I am following the `nixos-unstable` branch of nixpkgs, the Hyprland package from there will likely be up to date with Hyprland's own git repository; I do not have to define a separate flake input.\\\r\nNote: There is a distinction between installing a package, and enabling or configuring it. By default, declarations like `programs.hyprland.enable = true;` in `configuration.nix` and `wayland.windowManager.hyprland.enable = true;` in `home.nix` installs *and* enables Hyprland. However, if Hyprland is already installed, either through a nixpkgs branch or through Hyprland's own git repository, I can tell NixOS (`programs.hyprland.package = ...`) and Home Manager (`wayland.windowManager.hyprland.package = ...`) to use it. Since I am installing Hyprland from nixpkgs, I do not have to explicitly specify the package.\\\r\nInstall Hyprland (and kitty) from nixpkgs for all users:\r\n1. In `configuration.nix`, add:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n   + environment = {\r\n   +   systemPackages = with pkgs; [\r\n   +     kitty\r\n   +   ];\r\n   +   sessionVariables.NIXOS_OZONE_WL = \"1\";\r\n   + };\r\n\r\n     programs = {\r\n       # ...\r\n   +   hyprland.enable = true;\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n   [kitty](https://search.nixos.org/packages?channel=24.05\u0026show=kitty\u0026from=0\u0026size=50\u0026sort=relevance\u0026type=packages\u0026query=kitty \"NixOS.org Search\") is the [default](https://wiki.hyprland.org/Getting-Started/Master-Tutorial/#install-hyprland \"Hyprland Wiki\") terminal emulator. Following [wiki](https://wiki.hyprland.org/Nix/ \"Hyprland Wiki\"), only 1 environment variable is defined. `XWayland` is enabled by [default](https://search.nixos.org/options?channel=unstable\u0026show=programs.hyprland.xwayland.enable \"NixOS.org\").\\\r\n   Note: Notice the `{ pkgs, ... }` at the start of `configuration.nix` and `home.nix`. Nix is a functional language; `configuration.nix` and `home.nix` are both functions, and `pkgs` and `...` are parameters. NixOS passes `configuration.nix` and `home.nix` the parameters during rebuild. `...` lets Nix know to have any parameters that might be needed, while `pkgs` is specifically included so that `pkgs` is defined when it is used in `systemPackages = with pkgs; [ # ... ]`. As `home.nix` does not have any usage of `pkgs` so far, technically, the first line of `home.nix` can be stripped down to just `{ ... }:`; however, `pkgs` will very likely be used in `home.nix` at some point. For more information about the Nix language, see [here](https://youtu.be/HiTgbsFlPzs \"YouTube\").\r\n1. Connect to internet. Use `# nixos-rebuild switch`.\r\n1. Reboot. Use `$ Hyprland` to see that Hyprland works. No crashes.\r\n\r\nFixing kitty and xdg-desktop-portal:\r\n1. In Hyprland, use `$ kitty` to see `[0.139] [glfw error 65544]: process_desktop_settings: failed with error: [org.freedesktop.DBus.Error.UnknownMethod] No such interface \"org.freedesktop.portal.Settings\" on object at path /org/freedesktop/portal/desktop`. A new terminal appears, but as soon as I use \u003ckbd\u003ectrl\u003c/kbd\u003e+\u003ckbd\u003ec\u003c/kbd\u003e in the original terminal, the new terminal disappears. \r\n1. Using `$ systemctl --user status dbus` shows no abnormalities, but using `$ systemctl --user status xdg-desktop-portal.service` shows (incomplete):\r\n   ```\r\n   systemd[1111]: Starting Portal service...\r\n   .xdg-desktop-po[1240]: Failed to load RealtimeKit property: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.RealtimeKit1 was not provided by any .service files\r\n   .xdg-desktop-po[1240]: Failed to load RealtimeKit property: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.RealtimeKit1 was not provided by any .service files\r\n   .xdg-desktop-po[1240]: Failed to load RealtimeKit property: GDBus.Error:org.freedesktop.DBus.Error.ServiceUnknown: The name org.freedesktop.RealtimeKit1 was not provided by any .service files\r\n   .xdg-desktop-po[1187]: No skeleton to export\r\n   systemd[1111]: Started Portal service.\r\n   ```\r\n1. Kitty's error can be fixed by adding xdg-desktop-portal-gtk to the system. This can seemingly be done 2 ways: either with `environment.systemPackages` or with `xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];`. Both ways install xdg-desktop-portal-gtk, and I choose the second option.\\\r\n   Note: Using `$ systemctl --user status xdg-desktop-portal-hyprland.service` shows that the Hyprland version of xdg-desktop-portal is already running without any issues; I guess kitty either is not using this Hyprland version or does not work with it. Although, I do not mind installing the GTK version of xdg-desktop-portal, since it is recommended on the [Hyprland wiki](https://wiki.hyprland.org/Useful-Utilities/xdg-desktop-portal-hyprland/).\r\n1. xdg-desktop-portal's RealtimeKit error can be fixed by adding `security.rtkit.enable = true;` to `configuration.nix`. `No skeleton to export` can also be fixed by adding xdg-desktop-portal-gtk.\\\r\n   After changing these two options, a new error appears when using `$ systemctl --user status xdg-desktop-portal.service` (incomplete):\r\n   ```\r\n   systemd[1143]: Starting Portal service...\r\n   .xdg-desktop-po[1220]: Failed connect to PipeWire: Couldn't connect to PipeWire\r\n   systemd[1143]: Started Portal service.\r\n   ```\r\n   This pipewire error can be fixed by adding `services.pipewire.enable = true;` to `configuration.nix`. After doing so, no xdg-desktop-portal errors occur.\r\n1. All additions to `configuration.nix` as a result of the errors:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     services = {\r\n       # ...\r\n   +   pipewire.enable = true;\r\n     };\r\n   \r\n   + security.rtkit.enable = true;\r\n\r\n   + xdg.portal = {\r\n   +   enable = true;\r\n   +   extraPortals = [ pkgs.xdg-desktop-portal-gtk ];\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n1. Connect to internet. Use `# nixos-rebuild switch`.\r\n\r\nUsing [Home Manager](https://nix-community.github.io/home-manager/options.xhtml#opt-wayland.windowManager.hyprland.enable \"Home Manager Manual\") to configure [Hyprland](https://wiki.hyprland.org/Configuring/Configuring-Hyprland/ \"Hyprland Wiki\"):\r\n1. Edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n   + wayland.windowManager.hyprland = {\r\n   +   enable = true;\r\n   +   settings = {\r\n   +     bind = [\r\n   +       \"ALT, TAB, cyclenext\"\r\n   +       \"ALT, TAB, alterzorder, top\"\r\n   +       \"SUPER, T, exec, kitty\"\r\n   +       \"SUPER, W, killactive\"\r\n   +       \"SUPER, Q, togglefloating\"\r\n   +       \"SUPER, F, fullscreenstate, 2 0\"\r\n   +       \"SUPER, K, exit\"\r\n   +       \"SUPER, tab, workspace, e+1\"\r\n   +       \"SUPER_SHIFT, tab, movetoworkspace, e+1\"\r\n   +       \"SUPER, E, movetoworkspace, emptyn\"\r\n   +     ];\r\n   +     bindm = [\r\n   +       \"SHIFT, mouse:272, movewindow\"\r\n   +       \"CTRL, mouse:272, resizewindow\"\r\n   +     ];\r\n   +     bezier = [\r\n   +       \"linear, 0.5, 0.5, 0.5, 0.5\"\r\n   +       \"snappyOut1, 0, 0.85, 0, 1\"\r\n   +       \"snappyOut2, 0, 0.6, 0.15, 1\"\r\n   +       \"expoOut, 0.16, 1, 0.3, 1\"\r\n   +     ];\r\n   +     animation = [\r\n   +       \"windowsIn, 1, 5, snappyOut1, popin 20%\"\r\n   +       \"windowsOut, 1, 8, snappyOut2, popin 80%\"\r\n   +       \"windowsMove, 1, 5, snappyOut1\"\r\n   +       \"fadeOut, 1, 4, expoOut\"\r\n   +       \"fadeLayers, 1, 4, expoOut\"\r\n   +       \"border, 1, 4, expoOut\"\r\n   +       \"borderangle, 1, 6, expoOut, once\"\r\n   +       \"workspaces, 1, 3, snappyOut1, slide\"\r\n   +     ];\r\n   +     general = {\r\n   +       border_size = 2;\r\n   +       gaps_in = 4;\r\n   +       gaps_out = 10;\r\n   +       \"col.active_border\" = \"rgba(225,225,225,1) rgba(255,255,255,0.65) 45deg\";\r\n   +       \"col.inactive_border\" = \"rgba(107,127,148,0.5)\";\r\n   +       resize_on_border = true;\r\n   +     };\r\n   +     decoration = {\r\n   +       rounding = 8;\r\n   +       shadow = {\r\n   +         range = 6;\r\n   +         render_power = 1;\r\n   +         color = \"rgba(102,196,204,0.1)\";\r\n   +         color_inactive = \"rgba(51,51,51,0.1)\";\r\n   +       };\r\n   +       blur = {\r\n   +         size = 4;\r\n   +         passes = 3;\r\n   +       };\r\n   +     };\r\n   +     input = {\r\n   +       repeat_delay = 500;\r\n   +       sensitivity = \"0.3\";\r\n   +       accel_profile = \"flat\";\r\n   +       touchpad = {\r\n   +         disable_while_typing = false;\r\n   +         natural_scroll = true;\r\n   +         tap-and-drag = false;\r\n   +         scroll_factor = 0.15;\r\n   +       };\r\n   +     };\r\n   +     gestures = {\r\n   +       workspace_swipe = true;\r\n   +     };\r\n   +     misc = {\r\n   +       disable_hyprland_logo = true;\r\n   +       disable_splash_rendering = true;\r\n   +       animate_manual_resizes = true;\r\n   +       animate_mouse_windowdragging = true;\r\n   +       background_color = 000000;\r\n   +       middle_click_paste = false;\r\n   +     };\r\n   +     windowrule = [\r\n   +       \"scrolltouchpad 1.0, class:kitty\"\r\n   +     ];\r\n   +   };\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   Since I am using Hyprland from `pkgs.hyprland`, I do not need to specify `wayland.windowManager.hyprland.package` for Home Manager.\\\r\n   Options that have syntax similar to Nix need to be wrapped in `\"\"`.\\\r\n   When defining colors with `rgba()`, there must be no whitespace.\\\r\n   Although trackpad (libinput) configuration can be done through `configuration.nix`, that [doesn't work](https://discourse.nixos.org/t/xorg-libinput-configuration-seems-to-be-ignored/15504 \"NixOS Help\") for me (`/etc/X11/xorg.conf` isn't generated), so I use Hyprland's options instead.\\\r\n   On the [Hyprland wiki](https://wiki.hyprland.org/Configuring/Variables/#touchpad:~:text=bool-,false,-Touchdevice), `touch-and-drag`'s default is marked as `false`, but in reality it's default is actually `true`, so I explicitly set it.\\\r\n   The `windowrule` parameter [`title:[regex]`](https://wiki.hyprland.org/Configuring/Window-Rules/#syntax \"Hyprland Wiki\") is not specified because Kitty changes the title based on the previous command visible through using `$ hyprctl clients`.\r\n1. Connect to internet. Use `# nixos-rebuild switch`.\\\r\n   An error occurs since a configuration file for Hyprland was automatically generated when installing Hyprland. Home Manager will not overwrite this existing configuration file.\r\n1. Use `$ rm ~/.config/hypr/hyprland.conf`, then `# nixos-rebuild switch` again.\\\r\n   Now, the configurations from `home.nix` appear.\\\r\n   Note: Home Manager creates a symlink at `~/.config/hypr/hyprland.conf`. I can remove this symlink, and when I use `# nixos-rebuild switch`, Home Manager will generate the symlink according to `home.nix` again. \r\n\r\nUsing [Home Manager](https://nix-community.github.io/home-manager/options.xhtml#opt-programs.kitty.enable \"Home Manager Manual\") to configure [kitty](https://sw.kovidgoyal.net/kitty/conf/ \"Kitty Documentation\"):\r\n1. Edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n   + programs.kitty = {\r\n   +   enable = true;\r\n   +   settings = {\r\n   +     font_size = \"9.5\";\r\n   +     cursor_shape = \"beam\";\r\n   +     cursor_shape_unfocused = \"beam\";\r\n   +     cursor_stop_blinking_after = 0;\r\n   +     scrollback_fill_enlarged_window = true;\r\n   +     mouse_hide_wait = -1;\r\n   +     show_hyperlink_targets = true;\r\n   +     clear_all_mouse_actions = true;\r\n   +     enable_audio_bell = false;\r\n   +     confirm_os_window_close = 0;\r\n   +     background_opacity = \"0.3\";\r\n   +     selection_background = \"#ffffff\";\r\n   +     clear_all_shortcuts = true;\r\n   +   };  \r\n   +   extraConfig = ''\r\n   +     mouse_map left press ungrabbed mouse_selection normal\r\n   +     mouse_map left doublepress ungrabbed mouse_selection word\r\n   +     mouse_map left triplepress ungrabbed mouse_selection line\r\n   +     map ctrl+c copy_or_interrupt\r\n   +     map ctrl+x copy_and_clear_or_interrupt\r\n   +     map ctrl+v paste_from_clipboard\r\n   +     map ctrl+equal change_font_size all +1.0\r\n   +     map ctrl+minus change_font_size all -1.0\r\n   +   '';\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   The `programs.kitty.shellIntegration.enableZshIntegration` Home Manager option is not set because it does not actually achieve [shell integration](https://sw.kovidgoyal.net/kitty/shell-integration/#shell-integration \"Kitty Documentation\"). Although kitty uses `\"yes\"` and `\"no\"`, Home Manager converts `true` and `false` to the strings. `''` defines multi-line strings in nix.\r\n1. Connect to internet. Use `# nixos-rebuild switch`.\r\n\r\n### Using Firefox (WIP)\r\nIn nixpkgs, `*-bin` means precompiled binary; `*-unwrapped` means not wrapped by NixOS.\r\n1. To install `firefox` for all users, edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     programs = {\r\n       # ...\r\n   +   firefox = {\r\n   +     enable = true;\r\n   +     policies = {\r\n   +       DisablePocket = true;\r\n   +       ExtensionSettings = ;\r\n   +       FirefoxHome = {\r\n   +         Search = false;\r\n   +         TopSites = false;\r\n   +         SponsoredTopSites = false;\r\n   +         Highlights = false;\r\n   +         Pocket = false;\r\n   +         SponsoredPocket = false;\r\n   +       };\r\n   +       Homepage = {\r\n   +         URL = \"https://redacted.myschoolapp.com/app/student\";\r\n   +         StartPage = \"previous-session\";\r\n   +       };\r\n   +       OverrideFirstRidePage = \"\";\r\n   +       Permissions = ;\r\n   +     };\r\n   +     preferences = {\r\n   +       \"browser.tabs.tabmanager.enabled\" = false;\r\n   +       \"browser.tabs.inTitlebar\" = 0;\r\n   +       \"browser.uidensity\" = 1;\r\n   +       \"browser.urlbar.shortcuts.tabs\" = false;\r\n   +       \"browser.urlbar.suggest.engines\" = false;\r\n   +       \"browser.urlbar.suggest.topsites\" = false;\r\n   +       \"browser.urlbar.suggest.calculator\" = true;\r\n   +       \"browser.urlbar.unitConversion.enabled\" = true;\r\n   +       \"browser.vpn_promo.enabled\" = false;\r\n   +     };\r\n   +     preferencesStatus = \"user\";\r\n   +   };\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n   [Policies](https://mozilla.github.io/policy-templates/ \"Mozilla's GitHub\") (view in Firefox internal page with URL `about:policies`; stored in file(s) in `/nix/store/`) are usually declared to allow administrators to set and lock browser settings. `programs.firefox.policies` is declared in `configuration.nix` because the Home Manager option `programs.firefox.policies` does not work. Other profile specific Home Manager options in `programs.firefox.profiles` work.\\\r\n   Note: The Firefox policy `NoDefaultBookmarks` seems good, but actually breaks Home Manager's `programs.firefox.profiles.\u003cname\u003e.bookmarks` option. When any option under `programs.firefox.profiles` (like `programs.firefox.profiles.\u003cname\u003e.bookmarks`) fails, all other options under `programs.firefox.profiles` fail; no error messages are displayed, but the configurations have no effect. When `programs.firefox.profiles.\u003cname\u003e.bookmarks` works, it silently overrides the default Firefox bookmarks.\\\r\n   The `programs.firefox.preferences` option is equivalent to `programs.firefox.policies = { Preferences = {} }`; the defined [`preferences`](https://mozilla.github.io/policy-templates/#preferences \"Mozilla's GitHub\") policy can be seen in `about:policies`. The preferences policy is a way of configuring the options viewable in `about:config`; a user specific way of configuring options in `about:config` is through Home Manager's `programs.firefox.profiles.\u003cname\u003e.settings`, which stores options in `~/.mozilla/firefox/\u003cname\u003e/user.js`. `user.js` defines overrides to `~/.mozilla/firefox/\u003cname\u003e/prefs.js`; Firefox modifies `prefs.js` when options are changed directly through `about:config`. So, to modify `about:config` options for all users, using a policy through `configuration.nix` is the only way, and to modify `about:config` options for a specific user, using Home Manager's option `programs.firefox.profiles.\u003cname\u003e.settings` is the only way (there is no option for modifying `prefs.js` directly). Also, Home Manager's option `programs.firefox.profiles.\u003cname\u003e.extraConfig` modifies `user.js` as well, as seen in Home Manager's [`mkFirefoxModule.nix`](https://github.com/nix-community/home-manager/blob/afc892db74d65042031a093adb6010c4c3378422/modules/programs/firefox/mkFirefoxModule.nix#L847 \"GitHub\").\\\r\n   Note: While [not all](https://searchfox.org/mozilla-central/source/toolkit/modules/Troubleshoot.sys.mjs#19 \"Firefox Source (Searchfox.org)\") options are viewable in `about:config`, nearly all Firefox options are found in [`firefox.js`](https://searchfox.org/mozilla-release/source/browser/app/profile/firefox.js \"Firefox Source (Searchfox.org)\"), [`all.js`](https://searchfox.org/mozilla-release/source/modules/libpref/init/all.js \"Firefox Source (Searchfox.org)\"), [`StaticPrefList.yaml`](https://searchfox.org/mozilla-release/source/modules/libpref/init/StaticPrefList.yaml \"Firefox Source (Searchfox.org)\"), and [MozillaZine](https://kb.mozillazine.org/About:config_entries).\\\r\n   Note: Firefox View (`about:firefoxview`) [cannot](https://bugzilla.mozilla.org/show_bug.cgi?id=1817794 \"Bugzilla\") be disabled with any configuration options, and can only be hidden. When opening `about:firefoxview`, the tab manager button appears, even though the `browser.tabs.tabmanager.enabled` value is already set to `false`.\r\n1. Connect to internet. Use `# nixos-rebuild switch`.\\\r\n   Use `$ firefox` to see that Firefox works.\\\r\n   In the terminal, minor error messages appear:\r\n   ```\r\n   [Parent 4325, Main Thread] WARNING: ../gdk/wayland/gdkcursor-wayland.c:243 cursor image size (9x16) not an integermultiple of scale (2): 'glib warning', file /builds/worker/checkouts/gecko/toolkit/xre/nsSigHandlers.cpp:187\r\n   \r\n   (firefox:4325): Gdk-WARNING **: 05:23:33.059: ../gdk/wayland/gdkcursor-wayland.c:243 cursor image size (9x16) not an integermultiple of scale (2)\r\n   Gdk-Message: 05:23:36.908: Unable to load pointer from the cursor theme\r\n   Gdk-Message: 05:27:02.544: Unable to load col-resize from the cursor theme\r\n   ```\r\n   Although Hyprland has Hyprcursor which is superior to XCursor, some applications like Firefox [don't support](https://wiki.hyprland.org/Hypr-Ecosystem/hyprcursor/#important-notes \"Hyprland Wiki\") Hyprcursor and will fall back to XCursor. I don't have any Hyprcursor themes installed, so Hyprland is also falling back to XCursor. I don't have any custom XCursor themes installed. To customize the cursor in XCursor, edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     environment = {\r\n       systemPackages = with pkgs; [\r\n         # ...\r\n   +     capitaine-cursors\r\n       ];\r\n       # ...\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n   And edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     home = {\r\n       # ...\r\n   +   pointerCursor = {\r\n   +     package = pkgs.capitaine-cursors;\r\n   +     name = \"capitaine-cursors\";\r\n   +     size = 22;\r\n   +     gtk.enable = true;\r\n   +     x11.enable = true;\r\n   +     x11.defaultCursor = \"default\";\r\n   +   };\r\n     };\r\n\r\n   + gtk = {\r\n   +   enable = true;\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   [`home.pointerCursor`](https://github.com/nix-community/home-manager/blob/master/modules/config/home-cursor.nix \"GitHub\") sets up many cursor configurations; it sets up `XCURSOR` environment variables which configure the cursor on Hyprland without Hyprcursor. Configuring environment variables need a reboot to apply.\\\r\n   `home.pointerCursor.package` must be declared because it doesn't have a default.\\\r\n   For programs like Firefox that use GDK (backbone of GTK, the GUI toolkit), cursor configurations must be configured through GTK. GTK configuration can be done through graphical apps like [`nwg-look`](https://wiki.hyprland.org/Getting-Started/Master-Tutorial/#themes \"Hyprland Wiki\"), but there are Home Manager options for GTK. GTK cursor configurations (`home.pointerCursor.gtk.enable = true;`) only apply when `gtk.enable = true;`.\\\r\n   Although `pkgs.capitaine-cursors` includes light and dark versions, the dark version seems to be the default, so I don't configure that manually.\\\r\n   After connecting to internet and using `# nixos-rebuild switch`, running Firefox shows no error messages.\r\n1. To use Home Manager to configure Firefox, edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n   + programs.firefox = {\r\n   +   enable = true;\r\n   +   profiles.tim1 = {\r\n   +     name = \"School\";\r\n   +     id = 0;\r\n   +     bookmarks = [\r\n   +       {\r\n   +         toolbar = true;\r\n   +         bookmarks = [\r\n   +           {\r\n   +             name = \"Gmail\";\r\n   +             url = \"https://mail.google.com\";\r\n   +             keyword = \"m\";\r\n   +           }\r\n   +           {\r\n   +             name = \"Drive\";\r\n   +             url = \"https://drive.google.com/drive/u/0/my-drive\";\r\n   +             keyword = \"d\";\r\n   +           }\r\n   +           {\r\n   +             name = \"Claude\";\r\n   +             url = \"https://claude.ai/chats\";\r\n   +             keyword = \"c\";\r\n   +           }\r\n   +         ];\r\n   +       }\r\n   +     ];\r\n   +     extensions = ;\r\n   +     settings = {\r\n   +       \"middlemouse.paste\" = false;\r\n   +       \"findbar.highlightAll\" = true;\r\n   +     };\r\n   +     extraConfig = ''\r\n   +     '';\r\n   +     search.engines = {\r\n   +       \"Bing CN\" = {\r\n   +         urls = [{ template = \"https://cn.bing.com/search?q={searchTerms}\u0026ensearch=1\"; }];\r\n   +         definedAliases = [ \"@b\" ];\r\n   +         iconURL = \"https://img.icons8.com/fluency/48/bing--v4.png\";\r\n   +       };\r\n   +       \"Bing\".metaData.hidden = true;\r\n   +       \"DuckDuckGo\".metaData.hidden = true;\r\n   +       \"Wikipedia (en)\".metaData.hidden = true;\r\n   +     };\r\n   +     userChrome = ''\r\n   +     '';\r\n   +     userContent = ''\r\n   +     '';\r\n   +   };\r\n   +   profiles.test = {\r\n   +     id = 1;\r\n   +   };\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   Note: Installing `firefox-bin` instead of `firefox` does not seem to interfere with its configuration through Home Manager. I specified `programs.firefox.package = pkgs.firefox-bin` in `home.nix`, matching the package in `configuration.nix`; yet, when I first used `# nixos-rebuild switch`, a download of a Firefox package began. I updated `/etc/nixos/flake.lock`, used `# nixos-rebuild switch` *without* any Firefox configurations in `home.nix`, and then used `# nixos-rebuild switch` *with* Firefox configurations including `programs.firefox.package = pkgs.firefox-bin` in `home.nix`; during this rebuild no Firefox package was downloaded. Using `$ nix-store -q --references /run/current-system/sw | grep firefox` shows only one Firefox. A possible explanation could be that Home Manager queries a different *version* of the unstable branch of nixpkgs than the OS; Home Manager follows the same branch as the OS, as defined in `flake.nix` `home-manager.inputs.nixpkgs.follows = \"nixpkgs\";`, but a different version of the branch. So, during rebuild, Home Manager sees that in its version of the nixos-unstable branch of nixpkgs there is `pkgs.firefox-bin` of a different version than the `pkgs.firefox-bin` already installed in the system, so Home Manager tries to install the newer `pkgs.firefox-bin` from the version of the nixos-unstable branch of nixpkgs that it follows. So, when I update the version of the nixos-unstable branch of nixpkgs that the OS follows by updating `/etc/nixos/flake.lock` to possibly match the version that Home Manager is following, Home Manager does not install another Firefox anymore. One reason to suspect this is that before `/etc/nixos/flake.lock` was updated, Firefox version 127.x.x was installed, and after updating, it changed to version 128.0.3.\\\r\n   Firefox generates profiles on first launch, not instillation. This means that if I delete the profile directories and use `# nixos-rebuild switch` *without* modifying `home.nix`, reopening Firefox will generate the default profile instead of the profiles defined in `programs.firefox.profiles`.\\\r\n   `programs.firefox.profiles.\u003cname\u003e.id` must be declared when multiple profiles are declared.\\\r\n   The syntax inside `programs.firefox.profiles.\u003cname\u003e.bookmarks` does not allow `;`'s after `{}`'s. The [`toolbar`](https://github.com/nix-community/home-manager/blob/afc892db74d65042031a093adb6010c4c3378422/modules/programs/firefox/mkFirefoxModule.nix#L475 \"GitHub\") option defines the sub-bookmarks within the bookmark (functioning as directory) as toolbar bookmarks. This is the pseudo-structure: `profileBookmarks = { menuBookmark1, menuBookmark2, toolbarBookmarks = { toolbarBookmark1, toolbarBookmark2, ... }, menuBookmark3, ... }`. The `keyword` option redirects typing the string in the address bar to the bookmark.\\\r\n   Configurations inside `programs.firefox.profiles.\u003cname\u003e.settings` are all configurations not available through the [preferences](https://mozilla.github.io/policy-templates/#preferences \"Mozilla's GitHub\") policy in `configuration.nix`.\\\r\n   `programs.firefox.profiles.\u003cname\u003e.search.force` does not function as described in the [documentation](https://nix-community.github.io/home-manager/options.xhtml#opt-programs.firefox.profiles._name_.search.force \"Home Manager Manual\"); the default search engines (Google, Bing, DuckDuckGo, Wikipedia (en)) still appear with the option set to `true`. On seemingly every launch, Firefox regenerates the file `~/.mozilla/firefox/\u003cname\u003e/search.json.mozlz4`, replacing Home Manager's symlink, adding the default search engines back into the file; the issue is [not resolved](https://github.com/nix-community/home-manager/issues/3698#issuecomment-1863664311 \"GitHub\"). The [`SearchEngines`](https://mozilla.github.io/policy-templates/#searchengines-this-policy-is-only-available-on-the-esr \"Mozilla's GitHub\") policy exists for Firefox ESR, and for security [reasons](https://github.com/mozilla/policy-templates/issues/706#issuecomment-1976702696 \"GitHub\") it will not be supported for rapid release. Default search engines are hidden with [metadata attributes](https://searchfox.org/mozilla-central/source/toolkit/components/search/nsISearchService.idl#128,144,470,479 \"Firefox Source (Searchfox.org)\") in `home.nix`; default engines cannot be removed completely, although [uninstalling](https://github.com/mozilla/policy-templates/issues/484 \"GitHub\") them through extension related policies could work. `programs.firefox.profiles.\u003cname\u003e.search.privateDefault` does not work, but the default is Google.\\\r\n   Remove the directories `~/.mozilla` and `~/.cache/mozilla`. Connect to internet. Use `# nixos-rebuild switch`.\r\n\r\n### Hosting Configurations on GitHub \r\nSince the `nixos-rebuild` command [allows](https://nixos.wiki/wiki/Flakes#Using_nix_flakes_with_NixOS:~:text=To%20switch%20a,fast%20%5C%0A%20%20switch \"NixOS Wiki\") using a flake from remote locations, not just `/etc/nixos`, all files in `/etc/nixos` can be moved to a GitHub repository for the system to rebuild from. To do this, upload all the files (`flake.nix` `flake.lock` `configuration.nix` `hardware-configuration.nix` `home.nix`) in `/etc/nixos` to a GitHub repository. From now on, use `# nixos-rebuild switch --flake github:0dpe/Linux-Journey#ZHAN --refresh` instead of just `# nixos-rebuild switch`, and rebuilds always require internet access. All files in `/etc/nixos` can be removed.\\\r\nNote: The [`--refresh`](https://www.reddit.com/r/NixOS/comments/1c2wh5j/nixosrebuild_doesnt_do_anything/ \"Reddit\") flag is required for `nixos-rebuild` to use the repository all the time. Without the flag, `nixos-rebuild` only checks the repository once in a one hour duration.\\\r\nFor shortening the command, add in `configuration.nix`:\r\n```diff\r\n{ pkgs, ... }:\r\n\r\n{\r\n  # ...\r\n\r\n  environment = {\r\n    # ...\r\n+   shellAliases = {\r\n+     rebuild = \"sudo nixos-rebuild switch --flake github:0dpe/Linux-Journey#ZHAN --refresh\";\r\n+   };\r\n  };\r\n\r\n  # ...\r\n}\r\n```\r\nNote: `environment.shellAliases` requires a reboot to take effect.\\\r\nTo automatically update the `flake.lock` file in the GitHub repository, add a GitHub action to the repository. Create and edit `.github/workflows/Update Flake Lock.yml`:\r\n```yml\r\nname: Update Flake Lock\r\n\r\non:\r\n  workflow_dispatch:\r\n  schedule:\r\n    - cron: '0 0 * * 0'\r\n\r\njobs:\r\n  update-flake-lock:\r\n    runs-on: ubuntu-latest\r\n    steps:\r\n  \r\n      - name: Checkout Repository\r\n        uses: actions/checkout@v4\r\n    \r\n      - name: Install Nix\r\n        uses: DeterminateSystems/nix-installer-action@main\r\n    \r\n      - name: Update flake.lock\r\n        uses: DeterminateSystems/update-flake-lock@main\r\n        with:\r\n          pr-title: \"Update Flake Lock\"\r\n```\r\nNote: To manually update the `flake.lock` file, use `$ nix flake update --flake github:0dpe/Linux-Journey --output-lock-file ~/flake.lock` and replace the old `flake.lock` in the repository with the new `~/flake.lock`.\r\n\r\n### Controlling Screen Backlight\r\nPackages like `light` and `brightnessctl` work on Wayland and make changing screen brightness easy, but there is a simpler way to change screen brightness. The file `/sys/class/backlight/intel_backlight/brightness` contains an integer that defines the screen brightness. Use `$ cat /sys/class/backlight/intel_backlight/max_brightness` to see the max brightness is 24000 (a number \u003c188 makes the backlight flicker or turn off). When the file `brightness` is modified, the screen brightness changes accordingly. However, the file `brightness` has permissions `-rw-r--r--` (file type, permissions(owner, group, others)), so only the root user can modify it. Use `$ sudo tee /sys/class/backlight/intel_backlight/brightness \u003c\u003c\u003c MY_NUMBER` to modify the file manually.\\\r\nNotes: Using `$ sudo echo MY_NUMBER \u003e /sys/class/backlight/intel_backlight/max_brightness` does not work because `sudo` elevates the command that follows it (`echo` in this case), not the redirector operator `\u003e` which is handled by the command shell (zsh for me). `sudo` here does not affect the command shell's operations; `\u003e` is supposed to write the output of `echo MY_NUMBER` to the file `brightness` but it's operated by the command shell which doesn't have permission. Using `# echo MY_NUMBER \u003e /sys/class/backlight/intel_backlight/max_brightness` works because while using commands as root, all operations, including the command shell's operations, are performed with root privileges. Also, to use the command without root, use `$ sudo sh -c 'echo MY_NUMBER \u003e /sys/class/backlight/intel_backlight/max_brightness'`. `\u003c\u003c\u003c` (*here string*) is also a command shell operation, but in `$ sudo tee /sys/class/backlight/intel_backlight/brightness \u003c\u003c\u003c MY_NUMBER` `tee` actually does the writing, and `tee` has elevated privileges. `\u003c\u003c\u003c` only passes the string to `tee` for `tee` to modify the file `brightness`.\r\n1. To allow modification of the file `brightness` without `sudo` for all users, edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n\r\n     services = {\r\n       # ...\r\n   +   udev.extraRules = ''\r\n   +     ACTION==\"add\", SUBSYSTEM==\"backlight\", KERNEL==\"intel_backlight\", MODE=\"0666\", RUN+=\"${pkgs.coreutils}/bin/chmod a+w /sys/class/backlight/%k/brightness\"\r\n   +   '';\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n   `udev` is enabled by default.\\\r\n   After rebuild the system and then rebooting, `/sys/class/backlight/intel_backlight/brightness` has permissions `-rw-rw-rw-`.\r\n1. To bind dynamic commands to keybinds to change screen brightness in Hyprland, edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n     wayland.windowManager.hyprland = {\r\n       # ...\r\n       settings = {\r\n         # ...\r\n   +     binde = [\r\n   +       \"SUPER, MINUS, exec, val=$(\u003c /sys/class/backlight/intel_backlight/brightness); tee /sys/class/backlight/intel_backlight/brightness \u003c\u003c\u003c $((val \u003c= 4188 ? 188 : val - 4000))\"\r\n   +       \"SUPER, EQUAL, exec, val=$(\u003c /sys/class/backlight/intel_backlight/brightness); tee /sys/class/backlight/intel_backlight/brightness \u003c\u003c\u003c $((val \u003e= 20000 ? 24000 : val + 4000))\"\r\n   +     ];\r\n         # ...\r\n       };\r\n     };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n1. Rebuild the system.\r\n\r\n### Using a Display (Login) Manager\r\nSince I only have one user and one window manager or desktop environment, I do not need a graphical display manager, or any display manager at all.\r\n1. To automate typing in the username, edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     services = {\r\n       # ...\r\n   +   getty.extraArgs = [ \"--skip-login\" \"--login-options\" \"tim\" ];\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n   [`getty`](https://en.wikipedia.org/wiki/Getty_(Unix) \"Wikipedia\") (get-tty) manages TTYs.\\\r\n   `services.getty.autologinUser` is not used because it skips the password too.\r\n1. To start Hyprland automatically after login, edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n   + programs.zsh = {\r\n   +   enable = true;\r\n   +   profileExtra = ''\r\n   +     if [ -z \"''${DISPLAY}\" ] \u0026\u0026 [ \"''${XDG_VTNR}\" -eq 1 ]; then\r\n   +       exec Hyprland\r\n   +     fi\r\n   +   '';\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   Note: Options similar to `programs.zsh.profileExtra` exist for `configuration.nix`, but they are system wide.\\\r\n   Zsh executes a few files in a [specific order](https://github.com/sambacha/dotfiles2/blob/master/.github/shell-startup.png \"Zsh Config Files Flowchart\") on startup. the `.zprofile` file is executed on all login startups.\\\r\n   `-z` checks for zero length; if Hyprland is already running, `${DISPLAY}` will have length. In nix, `$`s inside multi-line strings can be escaped with `''`. `${XDG_VTNR}` indicates TTY#; `-eq` means \"equal\".\\\r\n   Remove `/home/tim/.zshrc`, then rebuild the system.\r\n\r\n### Using swww\r\nThe swww wallpaper manager does not have a configuration file; all configurations are done through commands.\r\n1. To install swww, edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     environment = {\r\n       systemPackages = with pkgs; [\r\n         # ...\r\n   +     swww\r\n       ];\r\n       # ...\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n1. Use `$ mkdir /home/tim/Wallpapers` to create a directory for the wallpapers.\r\n1. To autostart swww and automatically randomize wallpapers, edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     home = {\r\n       # ...\r\n   +   file = {\r\n   +     \".swwwRandomizer\" = {\r\n   +       enable = true;\r\n   +       executable = true;\r\n   +       text = ''\r\n   +         #!/usr/bin/env zsh\r\n   +         used=()\r\n   +         while :; do\r\n   +           all=(''$1/*)\r\n   +           [[ ''$#used -eq ''$#all ]] \u0026\u0026 used=(''$selected)\r\n   +           unused=(''${all:|used})\r\n   +           selected=''${unused[''$RANDOM % ''$#unused + 1]}\r\n   +           random_pos=(''$(seq 0.1 .1 0.9 | shuf))\r\n   +           swww img ''$selected \\\r\n   +             --resize crop \\\r\n   +             -t grow \\\r\n   +             --transition-pos ''$random_pos[1],''$random_pos[2] \\\r\n   +             --transition-duration 4 \\\r\n   +             --transition-fps 60 \\\r\n   +             -f Nearest\r\n   +           used+=(''$selected)\r\n   +           sleep ''$2\r\n   +         done\r\n   +       '';\r\n   +     };\r\n   +   };\r\n     };\r\n\r\n     # ...\r\n\r\n     wayland.windowManager.hyprland = {\r\n       # ...\r\n       settings = {\r\n         # ...\r\n   +     exec-once = [\r\n   +       \"swww-daemon --no-cache\"\r\n   +       \"swww clear 000000 \u0026\u0026 ~/.swwwRandomizer /home/tim/Wallpapers 3600\"\r\n   +     ];\r\n       };\r\n     };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   Home Manager's [`home.file.\u003cname\u003e.target`](https://nix-community.github.io/home-manager/options.xhtml#opt-home.file._name_.target \"Home Manager Manual\") option defines the path and name of the generated symlink or file relative to `~`. This option defaults to `~/\u003cname\u003e` when undefined.\\\r\n   Although the zsh script can be run as a one-line command with `$ zsh -c \"command\"`, using Hyprland's `exec-once` to execute the command on Hyprland startup does not seem to work. Also, the NixOS option [`writeShellApplication`](https://nixos.org/manual/nixpkgs/unstable/#trivial-builder-writeShellApplication \"NixOS Manual\") might be worth exploring for system wide scripts.\\\r\n   Pseudocode for the script:\r\n   1. [Shebang](https://en.wikipedia.org/wiki/Shebang_(Unix) \"Wikipedia\") for NixOS.\r\n   1. Define `used` as an empty array.\\\r\n      Putting spaces before and after the equal sign `=` would result in a syntax error.\r\n   1. While true, loop:\\\r\n      `:` stands for `true`. Semicolons `;` are mandatory for compacting the script into a single line; they are optional with newlines.\r\n      1. Define `all` as an array of files inside `$1/*`.\r\n         `$` indicates a variable. The variable `1` is the first argument passed to the script when it is run, like so: `$ ~/.swwwRandomizer first_argument`. Using `$ ~/.swwwRandomizer /home/tim/Wallpapers` simplifies to `(/home/tim/Wallpapers/*)`. The wildcard `*` lists all files in the directory.\r\n      1. Length of `used` equals length of `all` and redefine `used` as an array with only `selected`.\\\r\n         Double brackets `[[ ]]` are used for testing conditions. `#` tests for the length of the array variable. `\u0026\u0026`, the logical AND, only runs the second command if the first returns `true`. `selected` is defined later in the script; putting it here will never cause an error unless `all` is defined as an empty array. Putting `selected` ensures that images never get picked twice in a row after all images have been used.\\\r\n         Note: `$#var` works in zsh, but not bash. In bash, curly braces `{}` are required: `${#var}`.\r\n      1. Define `unused` as an array of `all` without `used`.\\\r\n         `{}` are required for zsh to group commands. `:|` removes anything inside the second array from the first array. `:|` needs to be inside the *parameter expansion* `${}`. Otherwise, `:|` in `unused=($all:|$used)` would be interpreted as a pipe operator followed by a colon.\r\n      1. Define `selected` as the path of the ((`$RANDOM` modulo length of `unused`) + 1)th file of `unused`.\\\r\n         `$RANDOM` is a pre-defined command shell variable that returns a random integer between 0 and 32767. The modulo operator `%` returns the remainder from dividing `$RANDOM` by the length of `unused`. Since zsh indexing start at one, not zero, one is added to the remainder to accurately calculate the index, which is denoted with brackets `[]`.\r\n      1. Define `random_pos` as the array of the sequence of 0.1 to 0.9 with step 0.1 shuffled.\\\r\n         The set of inner parentheses `$()` capture *command substitution*. The pipe operator `|` feeds the output of the first command as input to the second command.\r\n      1. Execute `swww img` with the image with path `selected`.\\\r\n         Back slashes `\\` are used to separate one line commands to multiple lines. Use `swww img --help` to see all image display and transition options. `--resize fit` shrinks the image until the entire image is displayed; `--resize crop` enlarges the image until the screen is filled. `-t grow` transition animation type is a growing circle. `-t any` randomizes the position of the circle, but it also randomizes between `grow` and `outer` (shrinking circle) animations, so it is not used. `--transition-pos` values separated by commas are float percentage values; arbitrarily the first and second floats of the shuffled `random_pos` array are used. `-f Nearest` is the fastest filter; best for pixel art.\r\n      1. Append `selected` to the `used` array.\r\n      1. Pause for variable `2` seconds.\r\n   1. End of loop.\r\n\r\n   The `--no-cache` flag is declared when starting `swww-daemon` because swww [does not yet](https://github.com/LGFae/swww/issues/336 \"GitHub\") remember options such as filter and resize for cached images.\\\r\n   Using `$ swww-daemon` for the first time on instillation or using `$ swww-daemon --no-cache` (to clear cache, use `$ swww clear-cache`) and then using `$ swww img /path/to/any/image` displays a black wallpaper. Using `$ swww query` shows that swww has attempted to display an image. Using any swww command to attempt to display something again fixes the black wallpaper. So, `swww clear 000000` is executed once in the start to arbitrarily display black. Putting `swww clear 000000` right after the shebang inside the script yields inconsistent results, indicating that the command is run too quickly, maybe before swww daemon has completely started, so `\u0026\u0026` is necessary in `exec-once`.\\\r\n   Rebuild the system.\r\n\r\n### Customizing Zsh Prompt\r\n[Oh My Posh](https://ohmyposh.dev/docs/ \"Oh My Posh Documentation\") is used for making shells look better. \r\n1. To install Oh My Posh, edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     environment = {\r\n       systemPackages = with pkgs; [\r\n         # ...\r\n   +     oh-my-posh\r\n       ];\r\n       # ...\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n1. To use Home Manager to configure Oh My Posh, edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n   + programs.oh-my-posh = {\r\n   +   enable = true;\r\n   +   settings = {\r\n   +     \"$schema\" = \"https://raw.githubusercontent.com/JanDeDobbeleer/oh-my-posh/main/themes/schema.json\";\r\n   +     final_space = true;\r\n   +     blocks = [\r\n   +       {\r\n   +         type = \"prompt\";\r\n   +         alignment = \"left\";\r\n   +         segments = [\r\n   +           {\r\n   +             type = \"session\";\r\n   +             style = \"plain\";\r\n   +             foreground = \"white\";\r\n   +             template = \"{{ .UserName }}\";\r\n   +           }\r\n   +           {\r\n   +             type = \"path\";\r\n   +             style = \"plain\";\r\n   +             foreground = \"white\";\r\n   +             properties = {\r\n   +               style = \"full\";\r\n   +             };\r\n   +           }\r\n   +           {\r\n   +             type = \"text\";\r\n   +             style = \"plain\";\r\n   +             foreground = \"white\";\r\n   +             template = \"❱\";\r\n   +           }\r\n   +         ];\r\n   +       }\r\n   +       {\r\n   +         type = \"rprompt\";\r\n   +         alignment = \"right\";\r\n   +         overflow = \"break\";\r\n   +         segments = [\r\n   +           {\r\n   +             type = \"executiontime\";\r\n   +             style = \"plain\";\r\n   +             foreground = \"white\";\r\n   +           }\r\n   +         ];\r\n   +       }\r\n   +     ];\r\n   +   };\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   While Oh My Posh's documentation suggests to edit `.zshrc`, Home Manager automatically does that. `❱` is `\\u2771`; use `$ echo \"\\u2771\"` to see the symbol.\r\n1. Rebuild the system.\r\n\r\n### Controlling Audio \u0026 Bluetooth\r\nFor Linux systems, [PipeWire](https://docs.pipewire.org/index.html \"PipeWire Documentation\") is used for managing audio. PipeWire is more modern compared to PulseAudio and JACK. While `services.pipewire.enable = true;` is already in my `configuration.nix`, adding some extra options is recommended.\\\r\n[BlueZ](https://www.bluez.org/about/) is the official standard bluetooth package.\r\n1. Edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     services = {\r\n       # ...\r\n   -   pipewire.enable = true;\r\n   +   pipewire = {\r\n   +     enable = true;\r\n   +     wireplumber.enable = true;\r\n   +     pulse.enable = true;\r\n   +     alsa.enable = true;\r\n   +     alsa.support32Bit = true;\r\n   +   };\r\n       # ...\r\n     };\r\n\r\n   + hardware = {\r\n   +   bluetooth = {\r\n   +     enable = true;\r\n   +     powerOnBoot = true;\r\n   +   };\r\n   + };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   [WirePlumber](https://pipewire.pages.freedesktop.org/wireplumber/index.html \"WirePlumber Documentation\") is PipeWire's *session manager*, a daemon that manages PipeWire.\\\r\n   `services.pipewire.pulse.enable = true;` allows PulseAudio applications to work with PipeWire. Likewise, ALSA configurations allow ALSA compatibility.\\\r\n   `hardware.bluetooth` configures BlueZ. To use bluetooth, use `$ bluetoothctl`; use `[bluetooth]# scan on`, `[bluetooth]# pair F8:4E:17:D3:E7:4A`, and `[bluetooth]# connect F8:4E:17:D3:E7:4A` to connect to `F8:4E:17:D3:E7:4A`. Use `[bluetooth]# trust F8:4E:17:D3:E7:4A` to automatically connect. Using `[bluetooth]# quit` will not terminate the connection. Use `$ bluetoothctl devices [Paired/Bonded/Trusted/Connected]` to see paired, bonded, trusted, or connected devices.\r\n1. To bind the buttons \u003ckbd\u003eXF86AudioMute\u003c/kbd\u003e, \u003ckbd\u003eXF86AudioLowerVolume\u003c/kbd\u003e, and \u003ckbd\u003eXF86AudioRaiseVolume\u003c/kbd\u003e to WirePlumber commands to manage volume through Hyprland, edit `home.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n     wayland.windowManager.hyprland = {\r\n       # ...\r\n       settings = {\r\n         # ...\r\n         binde = [\r\n           # ...\r\n   +       \", XF86AudioMute, exec, wpctl set-mute @DEFAULT_SINK@ toggle\"\r\n   +       \", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_SINK@ 2%-\"\r\n   +       \", XF86AudioRaiseVolume, exec, wpctl get-volume @DEFAULT_SINK@ | awk '{if ($2 \u003c 2.20) system(\\\"wpctl set-volume @DEFAULT_SINK 2%+\\\")}'\"\r\n         ];\r\n         # ...\r\n       };\r\n     };\r\n\r\n     # ...\r\n   }\r\n   ```\r\n   Note: `wpctl get-volume @DEFAULT_SINK@ | awk '{if ($2 \u003c 2.20) system(\\\"wpctl set-volume @DEFAULT_SINK 2%+\\\")}'` or `$ wpctl get-volume @DEFAULT_SINK@ | awk '{if ($2 \u003c 2.20) system(\"wpctl set-volume @DEFAULT_SINK@ 2%+\")}'` raises the volume by 0.02 if the volume is lower than 2.20. Through testing, it seems that while values can go above 2.20 to infinity, values above 2.20 do not actually make the speakers louder.\r\n1. Rebuild the system.\r\n\r\n### Using Fonts\r\n1. Edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n\r\n   {\r\n     # ...\r\n\r\n   + fonts = {\r\n   +   enableDefaultPackages = false;\r\n   +   packages = with pkgs; [\r\n   +     nerd-fonts.go-mono\r\n   +     nerd-fonts.roboto-mono\r\n   +     nerd-fonts.lilex\r\n   +     nerd-fonts.jetbrains-mono\r\n   +     nerd-fonts.dejavu-sans-mono\r\n   +     noto-fonts\r\n   +     twemoji-color-font\r\n   +   ];\r\n   +   fontconfig.defaultFonts = {\r\n   +     serif = [ \"Noto Serif\" ];\r\n   +     sansSerif = [ \"Noto Sans\" ];\r\n   +     monospace = [ \"DejaVuSansM Nerd Font Mono\" ];\r\n   +     emoji = [ \"Twitter Color Emoji\" ];\r\n   +   };\r\n   + };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n   [`fonts.enableDefaultPackages`](https://search.nixos.org/options?channel=unstable\u0026show=fonts.enableDefaultPackages \"NixOS.org\") installs some fonts like DejaVu; DejaVu was the font used by kitty before this configuration was set to `false` (use `$ kitty +list-fonts` to see the fonts available to kitty). If this configuration was set to `false` and no other fonts are in `fonts.packages`, then kitty's font rendering breaks.\\\r\n   Names in `fonts.fontconfig.defaultFonts` are found by finding the TrueType file and using [`$ fc-query font.ttf | grep '^\\s\\+family:' | cut -d'\"' -f2`](https://nixos.wiki/wiki/Fonts#:~:text=%24%20fc%2Dquery%20DejaVuSans.ttf%20%7C%20grep%20%27%5E%5Cs%5C%2Bfamily%3A%27%20%7C%20cut%20%2Dd%27%22%27%20%2Df2 \"NixOS Wiki\"). To find the location of the TrueType file, use `# find / -iname \"*font*\"`.\\\r\n   Note: Many symbols in Nerd Fonts have `\\Uxxxxx` unicodes like `\\Uf00af`. Using `$ echo \"\\uf00af\"` does not work since there are more than 4 characters in `f00af`. To see it in the terminal, either use `$ echo \"\\Uf00af\"` (with uppercase `U`) or convert `f00af`. This is a python script that converts Nerd Font unicodes:\r\n   ```python\r\n   try:\r\n       hex_input = input(\"Enter code from Nerd Fonts (like 'f00af'): \").strip().lower()\r\n       try:\r\n           hex_input = int(hex_input, 16)\r\n           char = chr(hex_input)\r\n       except ValueError as e:\r\n           raise ValueError(f\"Invalid code point: {hex_input}\") from e\r\n       utf8_bytes = char.encode('utf-8')\r\n       print(''.join([f'\\\\x{byte:02x}' for byte in utf8_bytes]))\r\n   except ValueError as e:\r\n       print(f\"Error: {e}\")\r\n   ```\r\n   For `f00af`, the script should output `\\xf3\\xb0\\x82\\xaf`. Use `$ echo \"\\xf3\\xb0\\x82\\xaf\"` and the symbol should render.\r\n1. Rebuild the system.\r\n\r\n### Managing Colors\r\n[Nix Colors](https://github.com/Misterio77/nix-colors \"GitHub\") exposes color schemes in the [Base16](https://tinted-theming.github.io/tinted-gallery \"Tinted Gallery\") framework for use in `.nix` files. Each Base16 theme contains 16 colors; there are many hand crafted themes, and Nix Colors has functionality for generating Base16 themes from images or wallpapers. \r\n1. Nix Colors is not in nixpkgs, so to install it, edit `flake.nix`:\r\n   ```diff\r\n   {\r\n     description = \"NixOS configuration flake\";\r\n   \r\n     inputs = {\r\n       nixpkgs.url = \"github:nixos/nixpkgs/nixos-unstable\";\r\n   \r\n       home-manager.url = \"github:nix-community/home-manager\";\r\n       home-manager.inputs.nixpkgs.follows = \"nixpkgs\";\r\n   \r\n   +   nix-colors.url = \"github:misterio77/nix-colors\";\r\n     };\r\n   \r\n   - outputs = { nixpkgs, home-manager, ... }: {\r\n   + outputs = { nixpkgs, home-manager, ... }@inputs: {\r\n       nixosConfigurations.ZHAN = nixpkgs.lib.nixosSystem {\r\n         system = \"x86_64-linux\";\r\n   +     specialArgs = { inherit inputs; };\r\n         modules = [\r\n           ./configuration.nix\r\n           home-manager.nixosModules.home-manager\r\n           {\r\n             home-manager.useGlobalPkgs = true;\r\n             home-manager.useUserPackages = true;\r\n             home-manager.users.tim = import ./home.nix;\r\n   +         home-manager.extraSpecialArgs = { inherit inputs; };\r\n           }\r\n         ];\r\n       };\r\n     };\r\n   }\r\n   ```\r\n   [`@inputs`](https://youtu.be/HiTgbsFlPzs?t=274 \"YouTube\") here puts all the parameters in `{ nixpkgs, home-manager, ... }` inside `inputs`. [`specialArgs`](https://discourse.nixos.org/t/how-do-specialargs-work/50615/4 \"NixOS Help\") is a set of arguments passed to the `modules`; including `inputs` inside `specialArgs` passes `inputs` to  `configuration.nix`. Home Manager's version of `specialArgs` named [`extraSpecialArgs`](https://github.com/nix-community/home-manager/blob/4e12151c9e014e2449e0beca2c0e9534b96a26b4/nixos/common.nix#L16 \"GitHub\") passes `inputs` to `home.nix`.\\\r\n   Note: Trying to use `inputs` in `home.nix` without `extraSpecialArgs` in `flake.nix` results in an infinite recursion error for some reason. Trying to use `inputs` in `home.nix` without `specialArgs` in `flake.nix` results in no error. Trying to use `inputs` in `configuration.nix` without `specialArgs` in `flake.nix` also results in the same infinite recursion error.\r\n1. Edit `home.nix` to use Nix Colors:\r\n   ```diff\r\n   -{ pkgs, ... }:\r\n   +{ pkgs, inputs, config, lib, ... }:\r\n\r\n   +let\r\n   + hexToRgba = color: opacity: \r\n   +   let\r\n   +     r = lib.fromHexString (builtins.substring 0 2 color);\r\n   +     g = lib.fromHexString (builtins.substring 2 2 color);\r\n   +     b = lib.fromHexString (builtins.substring 4 2 color);\r\n   +   in\r\n   +   \"${builtins.toString r},${builtins.toString g},${builtins.toString b}\";\r\n   +in\r\n   {\r\n   + imports = [\r\n   +   inputs.nix-colors.homeManagerModules.default\r\n   + ];\r\n   \r\n   + colorScheme = inputs.nix-colors.colorSchemes.tokyo-night-terminal-dark;\r\n   \r\n     # ...\r\n   \r\n     wayland.windowManager.hyprland = {\r\n       # ...\r\n       settings = {\r\n         # ...\r\n         general = {\r\n           # ...\r\n   -       \"col.active_border\" = \"rgba(225,225,225,1) rgba(255,255,255,0.650) 45deg\";\r\n   +       \"col.active_border\" = \"rgba(${hexToRgba config.colorScheme.palette.base07},1) rgba(${hexToRgba config.colorScheme.palette.base07},0.65) 45deg\";\r\n   -       \"col.inactive_border\" = \"rgba(107,127,148,0.5)\";\r\n   +       \"col.inactive_border\" = \"rgba(${hexToRgba config.colorScheme.palette.base03},0.6)\";\r\n           # ...\r\n         };\r\n         decoration = {\r\n           # ...\r\n           shadow = {\r\n             # ...\r\n   -         color = \"rgba(102,196,204,0.1)\";\r\n   +         color = \"rgba(${hexToRgba config.colorScheme.palette.base05},0.2)\";\r\n   -         color_inactive = \"rgba(51,51,51,0.1)\";\r\n   +         color_inactive = \"rgba(${hexToRgba config.colorScheme.palette.base03},0.2)\";\r\n           };\r\n         };\r\n         # ...\r\n       };\r\n     };\r\n\r\n     # ...\r\n\r\n     programs.oh-my-posh = {\r\n       # ...\r\n       settings = {\r\n         # ...\r\n         blocks = [\r\n           {\r\n             type = \"prompt\";\r\n             alignment = \"left\";\r\n             segments = [\r\n               {\r\n                 type = \"session\";\r\n                 style = \"plain\";\r\n   -             foreground = \"white\";\r\n   +             foreground = \"#${config.colorScheme.palette.base0D}\";\r\n                 template = \"{{ .UserName }}\";\r\n               }\r\n               {\r\n                 type = \"path\";\r\n                 style = \"plain\";\r\n   -             foreground = \"white\";\r\n   +             foreground = \"#${config.colorScheme.palette.base0C}\";\r\n                 properties = {\r\n                   style = \"full\";\r\n                 };\r\n               }\r\n               {\r\n                 type = \"text\";\r\n                 style = \"plain\";\r\n   -             foreground = \"white\";\r\n   +             foreground = \"#${config.colorScheme.palette.base05}\";\r\n                 template = \"❱\";\r\n               }\r\n             ];\r\n           }\r\n           {\r\n             type = \"rprompt\";\r\n             alignment = \"right\";\r\n             overflow = \"break\";\r\n             segments = [\r\n               {\r\n                 type = \"executiontime\";\r\n                 style = \"plain\";\r\n   -             foreground = \"white\";\r\n   +             foreground = \"#${config.colorScheme.palette.base04}\";\r\n               }\r\n             ];\r\n           }\r\n         ];\r\n       };\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n1. Update `flake.lock` and rebuild the system.\r\n\r\n### Using [Waybar](https://github.com/Alexays/Waybar \"GitHub\")\r\n1. To install Waybar, edit `configuration.nix`:\r\n   ```diff\r\n   { pkgs, ... }:\r\n   \r\n   {\r\n     # ...\r\n   \r\n     programs = {\r\n       # ...\r\n   +   waybar.enable = true;\r\n     };\r\n   \r\n     # ...\r\n   }\r\n   ```\r\n1. To use Home Manager to configure Waybar, edit `home.nix`:\r\n   ```diff\r\n   { pkgs, inputs, config, ... }:\r\n\r\n   # ...\r\n   {\r\n     # ...\r\n\r\n     wayland.windowManager.hyprland = {\r\n       # ...\r\n       settings = {\r\n         # ...\r\n   +     layerrule = [\r\n   +       \"blur, waybar\"\r\n   +       \"ignorealpha 0, waybar\"\r\n   +     ];\r\n         # ...\r\n       };\r\n     };\r\n\r\n     # ...\r\n\r\n   + programs.waybar = {\r\n   +   enable = true;\r\n   +   settings.bar = {\r\n   +     reload_style_on_change = true;\r\n   +     layer = \"top\";\r\n   +     position = \"top\";\r\n   +     modules-left = [ \"hyprland/workspaces\" ];\r\n   +     modules-right = [ \"wireplumber\" \"bluetooth\" \"network\" \"battery\" \"clock\" ];\r\n   +     spacing = 0;\r\n   +     \"hyprland/workspaces\" = {\r\n   +       show-special = true;\r\n   +       format = \"\";\r\n   +     };\r\n   +     wireplumber = {\r\n   +       format = \"{volume}%\u003cspan size='80%'\u003e \u003c/span\u003e\u003cspan size='135%' line_height='0.1' rise='-1200'\u003e󰕾\u003c/span\u003e\";\r\n   +       format-muted = \"{volume}%\u003cspan size='80%'\u003e \u003c/span\u003e\u003cspan size='135%' line_height='0.1' rise='-1200'\u003e󰸈\u003c/span\u003e\";\r\n   +       on-click = \"/run/current-system/sw/bin/wpctl set-mute @DEFAULT_SINK@ toggle\";\r\n   +       scroll-step = \"0.1\";\r\n   +       tooltip = false;\r\n   +     };\r\n   +     bluetooth = {\r\n   +       format-disabled = \"Controller Disabled\";\r\n   +       format-off = \"\u003cspan size='120%' line_height='0.1' rise='-6800'\u003e󰂲\u003c/span\u003e\";\r\n   +       format-on = \"󰂯\";\r\n   +       format-connected = \"{device_alias} 󰂯\";\r\n   +       on-click-right = \"/run/current-system/sw/bin/bluetoothctl power $(bluetoothctl show | grep -q 'Powered: yes' \u0026\u0026 echo off || echo on)\";\r\n   +       on-click = \"/run/current-system/sw/bin/bluetoothctl connect F8:4E:17:D3:E7:4A\";\r\n   +       tooltip-format-off = \"{controller_alias} {status}\";\r\n   +       tooltip-format-on = \"{controller_alias} {status}\";\r\n   +       tooltip-format-connected = \"{controller_alias} {status}\\n{device_enumerate}\";\r\n   +       tooltip-format-enumerate-connected = \"{device_alias} {device_address}\";\r\n   +     };\r\n   +     network = {\r\n   +       interval = 10;\r\n   +       format-wifi = \"{essid}\u003cspan size='80%'\u003e \u003c/span\u003e\u003cspan size='135%' line_height='0.1' rise='-1200'\u003e{icon}\u003c/span\u003e\";\r\n   +       format-disconnected = \"\u003cspan size='135%' line_height='0.1' rise='-6000'\u003e󰤮\u003c/span\u003e\";\r\n   +       format-icons = [ \"󰤟\" \"󰤢\" \"󰤥\" \"󰤨\" ];\r\n   +       tooltip-format-wifi = \"{bandwidthUpBytes} 󰕒\\n{bandwidthDownBytes} 󰇚\";\r\n   +       tooltip-format-disconnected = \"Disconnected\";\r\n   +     };\r\n   +     battery = {\r\n   +       interval = 10;\r\n   +       bat = \"BAT0\";\r\n   +       full-at = 97;\r\n   +       format = \"{capacity}%\u003cspan size='80%'\u003e \u003c/span\u003e\u003cspan size='92%' line_height='0.1' rise='500'\u003e{icon}\u003c/span\u003e\";\r\n   +       format-charging = \"{capacity}%\u003cspan size='80%'\u003e \u003c/span\u003e\u003cspan size='92%' line_height='0.1' rise='500'\u003e{icon}\u003c/span\u003e\u003cspan size='20%'\u003e \u003c/span\u003e\u003cspan size='90%' line_height='0.1' rise='600'\u003e󱐋\u003c/span\u003e\";\r\n   +       format-icons = [ \"󰁺\" \"󰁻\" \"󰁼\" \"󰁽\" \"󰁾\" \"󰁿\" \"󰂀\" \"󰂁\" \"󰂂\" \"󰁹\" ];\r\n   +       states = {\r\n   +         low = 20;\r\n   +       };\r\n   +       tooltip = false;\r\n   +     };\r\n   +     clock = {\r\n   +       format = \"{:%R}\";\r\n   +       format-alt = \"{:%b %d %R}\";\r\n   +       tooltip-format = \"{calendar}\";\r\n   +       calendar = {\r\n   +         mode = \"month\";\r\n   +         format = {\r\n   +           today = \"\u003cu\u003e\u003cb\u003e{}\u003c/b\u003e\u003c/u\u003e\";\r\n   +         };\r\n   +       };\r\n   +     };\r\n   +   };\r\n   +   style = ''\r\n   +     * {\r\n   +       all: unset;\r\n   +       font: 12px \"JetBrainsMonoNL Nerd Font Mono\", monospace;\r\n   +     }\r\n   +     tooltip {\r\n   +       background: rgba(${hexToRgba config.colorScheme.palette.base00}, 0.3);\r\n   +       text-shadow: #${config.colorScheme.palette.base00} 0em 0em 0.4em;\r\n   +       border-radius: 9px;\r\n   +     }\r\n   +     .modules-right {\r\n   +       color: #${config.colorScheme.palette.base07};\r\n   +       background: rgba(${hexToRgba config.colorScheme.palette.base00}, 0.3);\r\n   +       text-shadow: rgba(${hexToRgba config.colorScheme.palette.base00}, 0.4) 0em 0em 0.4em;\r\n   +       margin: 7px 9px 0px 0px;\r\n   +       padding-top: 0.45em;\r\n   +       padding-bottom: 0.45em;\r\n   +       border-radius: 9px;\r\n   +     }\r\n   +     .modules-left {\r\n   +       color: rgba(${hexToRgba config.colorScheme.palette.base07}, 0.4);\r\n   +       background: rgba(${hexToRgba config.colorScheme.palet","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0dpe%2Flinux-journey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F0dpe%2Flinux-journey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F0dpe%2Flinux-journey/lists"}