diff --git a/flake.nix b/flake.nix index f9b61ef..1e18614 100644 --- a/flake.nix +++ b/flake.nix @@ -63,9 +63,25 @@ # inputs.nixpkgs.follows = "nixpkgs-unstable"; #}; }; - outputs = { self, nur, nixpkgs, nixos-hardware, nixos-wsl, nixpkgs-unstable - , agenix, home-manager, home-manager-unstable, nix-colors, nixos-cosmic - , nixvim, nixos-generators, stylix, disko, flake-utils, ... }@inputs: + outputs = + { self + , nur + , nixpkgs + , nixos-hardware + , nixos-wsl + , nixpkgs-unstable + , agenix + , home-manager + , home-manager-unstable + , nix-colors + , nixos-cosmic + , nixvim + , nixos-generators + , stylix + , disko + , flake-utils + , ... + }@inputs: let inherit (self) outputs; system = "x86_64-linux"; @@ -82,30 +98,41 @@ defaultModules = [ ./modules agenix.nixosModules.default overlays ]; merge = list: builtins.foldl' (acc: elem: nixpkgs.lib.recursiveUpdate acc elem) { } - list; + list; # helper function to create a machine - mkHost = { modules, specialArgs ? { - pkgsVersion = nixpkgs-unstable; - home-manager-version = home-manager-unstable; - }, system ? "x86_64-linux", minimal ? false, graphical ? true }: + mkHost = + { modules + , specialArgs ? { + pkgsVersion = nixpkgs-unstable; + home-manager-version = home-manager-unstable; + } + , system ? "x86_64-linux" + , minimal ? false + , graphical ? true + }: let lib = specialArgs.pkgsVersion.lib; in specialArgs.pkgsVersion.lib.nixosSystem { inherit system; modules = modules ++ defaultModules ++ lib.lists.optionals (!minimal) [ specialArgs.home-manager-version.nixosModules.home-manager ] ++ lib.lists.optionals (!minimal && graphical) [ - ./modules/graphical - stylix.nixosModules.stylix - ./modules/graphical/stylix.nix - nixos-cosmic.nixosModules.default - ./modules/graphical/cosmic.nix - ]; + ./modules/graphical + stylix.nixosModules.stylix + ./modules/graphical/stylix.nix + nixos-cosmic.nixosModules.default + ./modules/graphical/cosmic.nix + ]; specialArgs = specialArgs // { inherit inputs outputs; }; }; - mkStableServer = { modules, specialArgs ? { - pkgsVersion = nixpkgs; - home-manager-version = home-manager; - }, system ? "x86_64-linux", minimal ? false }: + mkStableServer = + { modules + , specialArgs ? { + pkgsVersion = nixpkgs; + home-manager-version = home-manager; + } + , system ? "x86_64-linux" + , minimal ? false + }: let lib = specialArgs.pkgsVersion.lib; in specialArgs.pkgsVersion.lib.nixosSystem { inherit system; @@ -141,7 +168,8 @@ }; }; }); - in { + in + { overlays = import ./overlays.nix { inherit inputs; }; nixosConfigurations = { diff --git a/home-manager/code.nix b/home-manager/code.nix index 7fdb289..0200ae4 100644 --- a/home-manager/code.nix +++ b/home-manager/code.nix @@ -1,22 +1,24 @@ { osConfig, config, pkgs, inputs, lib, ... }: { config = lib.mkIf osConfig.custom.graphical.code.enable rec { - home.activation.makeVSCodeConfigWritable = let - configDirName = { - "vscode" = "Code"; - "vscode-insiders" = "Code - Insiders"; - "vscodium" = "VSCodium"; - }.${programs.vscode.package.pname}; - configPath = - "${config.xdg.configHome}/${configDirName}/User/settings.json"; - in { - after = [ "writeBoundary" ]; - before = [ ]; - data = '' - if [ -e "$(readlink ${configPath})" ]; then - install -m 0640 "$(readlink ${configPath})" ${configPath} - fi - ''; - }; + home.activation.makeVSCodeConfigWritable = + let + configDirName = { + "vscode" = "Code"; + "vscode-insiders" = "Code - Insiders"; + "vscodium" = "VSCodium"; + }.${programs.vscode.package.pname}; + configPath = + "${config.xdg.configHome}/${configDirName}/User/settings.json"; + in + { + after = [ "writeBoundary" ]; + before = [ ]; + data = '' + if [ -e "$(readlink ${configPath})" ]; then + install -m 0640 "$(readlink ${configPath})" ${configPath} + fi + ''; + }; programs.vscode = { enable = true; package = pkgs.vscodium; diff --git a/home-manager/direnv.nix b/home-manager/direnv.nix index 6f228fe..69f2d87 100644 --- a/home-manager/direnv.nix +++ b/home-manager/direnv.nix @@ -1,8 +1,8 @@ -{ config, pkgs, inputs, ...}: +{ config, pkgs, inputs, ... }: { - programs.direnv = { - enable = true; - enableZshIntegration = true; - nix-direnv.enable = true; - }; + programs.direnv = { + enable = true; + enableZshIntegration = true; + nix-direnv.enable = true; + }; } diff --git a/home-manager/firefox/config/browser-features.nix b/home-manager/firefox/config/browser-features.nix index 1c82fa9..103e83d 100644 --- a/home-manager/firefox/config/browser-features.nix +++ b/home-manager/firefox/config/browser-features.nix @@ -122,9 +122,9 @@ "pdfjs.enableScripting" = true; # copied these from a blog - "browser.newtabpage.activity-stream.feeds.telemetry" = false; + "browser.newtabpage.activity-stream.feeds.telemetry" = false; "browser.newtabpage.activity-stream.feeds.asrouterfeed" = false; - "browser.newtabpage.activity-stream.telemetry" = false; + "browser.newtabpage.activity-stream.telemetry" = false; "browser.ping-centre.telemetry" = false; "devtools.onboarding.telemetry.logged" = false; "accessibility.force_disabled" = 1; diff --git a/home-manager/firefox/default.nix b/home-manager/firefox/default.nix index 6e844e8..58e2f7c 100644 --- a/home-manager/firefox/default.nix +++ b/home-manager/firefox/default.nix @@ -58,7 +58,8 @@ let }; }; }; -in { +in +{ stylix = lib.mkIf osConfig.custom.graphical.stylix.enable { targets.firefox = { profileNames = [ "default" ]; diff --git a/home-manager/floorp/default.nix b/home-manager/floorp/default.nix index 66d344f..e49e2c4 100644 --- a/home-manager/floorp/default.nix +++ b/home-manager/floorp/default.nix @@ -58,7 +58,8 @@ let }; }; }; -in { +in +{ programs.floorp = { enable = true; policies = { diff --git a/home-manager/gitconfig.nix b/home-manager/gitconfig.nix index a1ea5fd..d3c03d8 100644 --- a/home-manager/gitconfig.nix +++ b/home-manager/gitconfig.nix @@ -1,4 +1,4 @@ -{ config, pkgs, inputs, ...}: +{ config, pkgs, inputs, ... }: { home.file.".gitconfig" = { enable = true; diff --git a/home-manager/hyprland/hyprland-settings.nix b/home-manager/hyprland/hyprland-settings.nix index 45b2baf..e8d9a96 100644 --- a/home-manager/hyprland/hyprland-settings.nix +++ b/home-manager/hyprland/hyprland-settings.nix @@ -12,7 +12,8 @@ let ''; monitor1 = if isPc then "DP-1" else if isLaptop then "eDP-1" else "eDP-1"; monitor2 = "HDMI-A-1"; -in { +in +{ config = lib.mkIf cfg.enable { home.file.".config/hypr/hyprshade.toml".source = @@ -29,21 +30,22 @@ in { # # See https://wiki.hyprland.org/Configuring/Monitors/ - monitor = if isPc then [ - "${monitor2},1920x1080@60,0x0,1" - "${monitor1},2560x1440@144,1920x0,1" - "Unknown-1,disable" - ] else if isLaptop then [ - # laptop - "eDP-1,1920x1080@60,0x0,1" - #"DP-3,1920x1080@60,1920x0,1" - #",preferred,auto,1,mirror,eDP-1" - ",preferred,auto,auto" - ] else - [ - # Default + monitor = + if isPc then [ + "${monitor2},1920x1080@60,0x0,1" + "${monitor1},2560x1440@144,1920x0,1" + "Unknown-1,disable" + ] else if isLaptop then [ + # laptop + "eDP-1,1920x1080@60,0x0,1" + #"DP-3,1920x1080@60,1920x0,1" + #",preferred,auto,1,mirror,eDP-1" ",preferred,auto,auto" - ]; + ] else + [ + # Default + ",preferred,auto,auto" + ]; workspace = lib.lists.optionals (osConfig.networking.hostName == "kop-pc") [ @@ -181,90 +183,92 @@ in { "$mainMod" = "SUPER"; # Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more - bind = let - rofi = "${pkgs.rofi-wayland}/bin/rofi"; - kitty = "${pkgs.kitty}/bin/kitty"; - #dolphin = "${pkgs.dolphin}/bin/dolphin"; - thunar = "${pkgs.xfce.thunar}/bin/thunar"; - wl-copy = "${pkgs.wl-clipboard}/bin/wl-copy"; - wl-paste = "${pkgs.wl-clipboard}/bin/wl-paste"; - grim = "${pkgs.grim}/bin/grim"; - slurp = "${pkgs.slurp}/bin/slurp"; - swww = "${pkgs.swww}/bin/swww"; - pdfgrep = "${pkgs.pdfgrep}/bin/pdfgrep"; - brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl"; - #swaylock = "${pkgs.swaylock}/bin/swaylock"; - hyprlock = "${pkgs.hyprlock}/bin/hyprlock"; - playerctl = "${pkgs.playerctl}/bin/playerctl"; - in [ - "$mainMod, Q, exec, ${kitty}" - "$mainMod, C, killactive" - #"$mainMod, L, exec, ${swaylock} -f -c 000000" - "$mainMod, L, exec, ${hyprlock}" - "$mainMod, M, exit," - "$mainMod, E, exec, ${thunar}" - "$mainMod, F, fullscreen" - "$mainMod, V, togglefloating" - "$mainMod, I, exec, ${rofi} -show drun -show-icons" - '' - $mainMod, S, exec, cat ~/songs | shuf -n 1 | sed "s/^/b.p /g" | ${wl-copy}'' - "$mainMod, R, exec, ${swww} img $(ls -d /synced/default/dinge/Bg/* | shuf -n 1)" - "$mainMod, W, exec, ${swww} img ${config.stylix.image}" - " , Print, exec, ${grim} -g \"$(${slurp} -d)\" - | ${wl-copy}" - '' - $mainMod, Print, exec, ${grim} -g "$(${slurp} -d)" /tmp/$(date +'%s_grim.png')'' - '' - Shift_L, Print, exec, ${grim} -g "$(${slurp} -d)" ~/Pictures/$(date +'%s_grim.png')'' - "$mainMod, SPACE, exec, ${rofi} -modi drun -show drun -config ~/.config/rofi/rofidmenu.rasi" - " , XF86MonBrightnessUp, exec, ${brightnessctl} s +5%" - " , XF86MonBrightnessDown, exec, ${brightnessctl} s 5%-" - " , XF86AudioPlay, exec, ${playerctl} play-pause" - " , XF86AudioNext, exec, ${playerctl} next" - " , XF86AudioPrev, exec, ${playerctl} previous" - "$mainMod, P, pseudo" # dwindle - "$mainMod, J, togglesplit" # dwindle - # Move focus with mainMod + arrow keys - "$mainMod, left, movefocus, l" - "$mainMod, right, movefocus, r" - "$mainMod, up, movefocus, u" - "$mainMod, down, movefocus, d" - "$mainMod SHIFT, left, resizeactive, -30 0" - "$mainMod SHIFT, right, resizeactive, 30 0" - "$mainMod SHIFT, up, resizeactive, 0 -30" - "$mainMod SHIFT, down, resizeactive, 0 30" + bind = + let + rofi = "${pkgs.rofi-wayland}/bin/rofi"; + kitty = "${pkgs.kitty}/bin/kitty"; + #dolphin = "${pkgs.dolphin}/bin/dolphin"; + thunar = "${pkgs.xfce.thunar}/bin/thunar"; + wl-copy = "${pkgs.wl-clipboard}/bin/wl-copy"; + wl-paste = "${pkgs.wl-clipboard}/bin/wl-paste"; + grim = "${pkgs.grim}/bin/grim"; + slurp = "${pkgs.slurp}/bin/slurp"; + swww = "${pkgs.swww}/bin/swww"; + pdfgrep = "${pkgs.pdfgrep}/bin/pdfgrep"; + brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl"; + #swaylock = "${pkgs.swaylock}/bin/swaylock"; + hyprlock = "${pkgs.hyprlock}/bin/hyprlock"; + playerctl = "${pkgs.playerctl}/bin/playerctl"; + in + [ + "$mainMod, Q, exec, ${kitty}" + "$mainMod, C, killactive" + #"$mainMod, L, exec, ${swaylock} -f -c 000000" + "$mainMod, L, exec, ${hyprlock}" + "$mainMod, M, exit," + "$mainMod, E, exec, ${thunar}" + "$mainMod, F, fullscreen" + "$mainMod, V, togglefloating" + "$mainMod, I, exec, ${rofi} -show drun -show-icons" + '' + $mainMod, S, exec, cat ~/songs | shuf -n 1 | sed "s/^/b.p /g" | ${wl-copy}'' + "$mainMod, R, exec, ${swww} img $(ls -d /synced/default/dinge/Bg/* | shuf -n 1)" + "$mainMod, W, exec, ${swww} img ${config.stylix.image}" + " , Print, exec, ${grim} -g \"$(${slurp} -d)\" - | ${wl-copy}" + '' + $mainMod, Print, exec, ${grim} -g "$(${slurp} -d)" /tmp/$(date +'%s_grim.png')'' + '' + Shift_L, Print, exec, ${grim} -g "$(${slurp} -d)" ~/Pictures/$(date +'%s_grim.png')'' + "$mainMod, SPACE, exec, ${rofi} -modi drun -show drun -config ~/.config/rofi/rofidmenu.rasi" + " , XF86MonBrightnessUp, exec, ${brightnessctl} s +5%" + " , XF86MonBrightnessDown, exec, ${brightnessctl} s 5%-" + " , XF86AudioPlay, exec, ${playerctl} play-pause" + " , XF86AudioNext, exec, ${playerctl} next" + " , XF86AudioPrev, exec, ${playerctl} previous" + "$mainMod, P, pseudo" # dwindle + "$mainMod, J, togglesplit" # dwindle + # Move focus with mainMod + arrow keys + "$mainMod, left, movefocus, l" + "$mainMod, right, movefocus, r" + "$mainMod, up, movefocus, u" + "$mainMod, down, movefocus, d" + "$mainMod SHIFT, left, resizeactive, -30 0" + "$mainMod SHIFT, right, resizeactive, 30 0" + "$mainMod SHIFT, up, resizeactive, 0 -30" + "$mainMod SHIFT, down, resizeactive, 0 30" - # Switch workspaces with mainMod + [0-9] - "$mainMod, 1, workspace, 1" - "$mainMod, 2, workspace, 2" - "$mainMod, 3, workspace, 3" - "$mainMod, 4, workspace, 4" - "$mainMod, 5, workspace, 5" - "$mainMod, 6, workspace, 6" - "$mainMod, 7, workspace, 7" - "$mainMod, 8, workspace, 8" - "$mainMod, 9, workspace, 9" - "$mainMod, 0, workspace, 10" + # Switch workspaces with mainMod + [0-9] + "$mainMod, 1, workspace, 1" + "$mainMod, 2, workspace, 2" + "$mainMod, 3, workspace, 3" + "$mainMod, 4, workspace, 4" + "$mainMod, 5, workspace, 5" + "$mainMod, 6, workspace, 6" + "$mainMod, 7, workspace, 7" + "$mainMod, 8, workspace, 8" + "$mainMod, 9, workspace, 9" + "$mainMod, 0, workspace, 10" - # Move active window to a workspace with mainMod + SHIFT + [0-9] - "$mainMod SHIFT, 1, movetoworkspace, 1" - "$mainMod SHIFT, 2, movetoworkspace, 2" - "$mainMod SHIFT, 3, movetoworkspace, 3" - "$mainMod SHIFT, 4, movetoworkspace, 4" - "$mainMod SHIFT, 5, movetoworkspace, 5" - "$mainMod SHIFT, 6, movetoworkspace, 6" - "$mainMod SHIFT, 7, movetoworkspace, 7" - "$mainMod SHIFT, 8, movetoworkspace, 8" - "$mainMod SHIFT, 9, movetoworkspace, 9" - "$mainMod SHIFT, 0, movetoworkspace, 10" + # Move active window to a workspace with mainMod + SHIFT + [0-9] + "$mainMod SHIFT, 1, movetoworkspace, 1" + "$mainMod SHIFT, 2, movetoworkspace, 2" + "$mainMod SHIFT, 3, movetoworkspace, 3" + "$mainMod SHIFT, 4, movetoworkspace, 4" + "$mainMod SHIFT, 5, movetoworkspace, 5" + "$mainMod SHIFT, 6, movetoworkspace, 6" + "$mainMod SHIFT, 7, movetoworkspace, 7" + "$mainMod SHIFT, 8, movetoworkspace, 8" + "$mainMod SHIFT, 9, movetoworkspace, 9" + "$mainMod SHIFT, 0, movetoworkspace, 10" - # Scroll through existing workspaces with mainMod + scroll - "$mainMod, mouse_down, workspace, e+1" - "$mainMod, mouse_up, workspace, e-1" + # Scroll through existing workspaces with mainMod + scroll + "$mainMod, mouse_down, workspace, e+1" + "$mainMod, mouse_up, workspace, e-1" - # "ALT, Tab, cyclenext," - # "ALT, Tab, bringactivetotop," - ]; + # "ALT, Tab, cyclenext," + # "ALT, Tab, bringactivetotop," + ]; bindm = [ # Move/resize windows with mainMod + LMB/RMB and dragging @@ -318,44 +322,46 @@ in { "xrandr --monitor ${monitor1} --primary" ]; }; - extraConfig = let - wl-copy = "${pkgs.wl-clipboard}/bin/wl-copy"; - wl-paste = "${pkgs.wl-clipboard}/bin/wl-paste"; - dunstify = "${pkgs.dunst}/bin/dunstify"; - dunstctl = "${pkgs.dunst}/bin/dunstctl"; - pdfgrep = "${pkgs.pdfgrep}/bin/pdfgrep --cache"; - path = "/synced/fh/os-hardening/**/slides"; - in '' - bind = $mainMod, A, submap, notes + extraConfig = + let + wl-copy = "${pkgs.wl-clipboard}/bin/wl-copy"; + wl-paste = "${pkgs.wl-clipboard}/bin/wl-paste"; + dunstify = "${pkgs.dunst}/bin/dunstify"; + dunstctl = "${pkgs.dunst}/bin/dunstctl"; + pdfgrep = "${pkgs.pdfgrep}/bin/pdfgrep --cache"; + path = "/synced/fh/os-hardening/**/slides"; + in + '' + bind = $mainMod, A, submap, notes - submap = notes - # below - bind = $mainMod, B, exec, ${wl-paste} | xargs -I {} ${pdfgrep} -B 15 -h -i "{}" ${path}/*.pdf | sed 's/[ \t]*$//' | ${wl-copy} - # above - bind = $mainMod, A, exec, ${wl-paste} | xargs -I {} ${pdfgrep} -A 15 -h -i "{}" ${path}/*.pdf | sed 's/[ \t]*$//' | ${wl-copy} - # context - bind = $mainMod, C, exec, ${wl-paste} | xargs -I {} ${pdfgrep} -C 15 -h -i "{}" ${path}/*.pdf | sed 's/[ \t]*$//' | ${wl-copy} - # trim - bind = $mainMod, T, exec, ${wl-paste} | sed 's/[ \t]*$//' | sed 's/^[ \t]*//' | sed '/^[[:space:]]*$/d' | ${wl-copy} - bind = $mainMod, N, exec, ${dunstify} "$(${wl-paste})" - bind = $mainMod, D, exec, ${dunstctl} close-all - # I win - bind = $mainMod, P, exec, ${wl-paste} | sgpt --model="gpt-4o" "Respond with the correct answer to the following question." | ${wl-copy} - # notes + submap = notes + # below + bind = $mainMod, B, exec, ${wl-paste} | xargs -I {} ${pdfgrep} -B 15 -h -i "{}" ${path}/*.pdf | sed 's/[ \t]*$//' | ${wl-copy} + # above + bind = $mainMod, A, exec, ${wl-paste} | xargs -I {} ${pdfgrep} -A 15 -h -i "{}" ${path}/*.pdf | sed 's/[ \t]*$//' | ${wl-copy} + # context + bind = $mainMod, C, exec, ${wl-paste} | xargs -I {} ${pdfgrep} -C 15 -h -i "{}" ${path}/*.pdf | sed 's/[ \t]*$//' | ${wl-copy} + # trim + bind = $mainMod, T, exec, ${wl-paste} | sed 's/[ \t]*$//' | sed 's/^[ \t]*//' | sed '/^[[:space:]]*$/d' | ${wl-copy} + bind = $mainMod, N, exec, ${dunstify} "$(${wl-paste})" + bind = $mainMod, D, exec, ${dunstctl} close-all + # I win + bind = $mainMod, P, exec, ${wl-paste} | sgpt --model="gpt-4o" "Respond with the correct answer to the following question." | ${wl-copy} + # notes - bind = $mainMod, 2, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = $mainMod, 3, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = $mainMod, 4, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = $mainMod, 5, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = $mainMod, 6, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = $mainMod, 7, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = $mainMod, 8, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = $mainMod, 0, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 2, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 3, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 4, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 5, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 6, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 7, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 8, exec, cat ~/Nextcloud/test.txt | ${wl-copy} + bind = $mainMod, 0, exec, cat ~/Nextcloud/test.txt | ${wl-copy} - bind = , escape, submap, reset - submap = reset + bind = , escape, submap, reset + submap = reset - ''; + ''; #experimental:explicit_sync = true }; }; diff --git a/home-manager/hyprland/hyprland-xwaylandvideobridge.nix b/home-manager/hyprland/hyprland-xwaylandvideobridge.nix index c2a821c..a75fc7d 100644 --- a/home-manager/hyprland/hyprland-xwaylandvideobridge.nix +++ b/home-manager/hyprland/hyprland-xwaylandvideobridge.nix @@ -1,22 +1,22 @@ { config, osConfig, pkgs, inputs, lib, ... }: with lib; let - cfg = osConfig.custom.graphical.hyprland.videobridge; + cfg = osConfig.custom.graphical.hyprland.videobridge; in { config = lib.mkIf cfg.enable { - wayland.windowManager.hyprland.settings.windowrulev2 = [ - "opacity 0.0 override 0.0 override,class:^(xwaylandvideobridge)$" - "noanim,class:^(xwaylandvideobridge)$" - "noinitialfocus,class:^(xwaylandvideobridge)$" - "maxsize 1 1,class:^(xwaylandvideobridge)$" - "noblur,class:^(xwaylandvideobridge)$" - ]; + wayland.windowManager.hyprland.settings.windowrulev2 = [ + "opacity 0.0 override 0.0 override,class:^(xwaylandvideobridge)$" + "noanim,class:^(xwaylandvideobridge)$" + "noinitialfocus,class:^(xwaylandvideobridge)$" + "maxsize 1 1,class:^(xwaylandvideobridge)$" + "noblur,class:^(xwaylandvideobridge)$" + ]; - systemd.user.services.xwaylandvideobridge = { - Unit.Description = "XWaylandVideoBridge"; - Service.ExecStart = lib.getExe pkgs.unstable.xwaylandvideobridge; - Install.WantedBy = ["graphical-session.target"]; - }; + systemd.user.services.xwaylandvideobridge = { + Unit.Description = "XWaylandVideoBridge"; + Service.ExecStart = lib.getExe pkgs.unstable.xwaylandvideobridge; + Install.WantedBy = [ "graphical-session.target" ]; + }; }; } diff --git a/home-manager/hyprland/waybar.nix b/home-manager/hyprland/waybar.nix index c49f617..d904d02 100644 --- a/home-manager/hyprland/waybar.nix +++ b/home-manager/hyprland/waybar.nix @@ -2,239 +2,241 @@ with lib; let cfg = osConfig.custom.graphical.hyprland; in { - config = let - # styles from https://github.com/khaneliman/khanelinix/blob/8375f8cfbe5bfd87565b4dc34c9d30630c17336d/modules/home/desktop/addons/waybar/default.nix - base16 = config.stylix.base16Scheme; - readAndReplace = path: replace: builtins.readFile (pkgs.replaceVars path replace); - # base 1, 7, 0 - #theme = readAndReplace ./styles/theme.css { BASE="#5c4133"; BORDER="#fef1de"; TEXT="#dab353";}; - theme = builtins.readFile ./styles/theme.css; - style = builtins.readFile ./styles/style.css; - notificationsStyle = builtins.readFile ./styles/notifications.css; - powerStyle = builtins.readFile ./styles/power.css; - statsStyle = builtins.readFile ./styles/stats.css; - workspacesStyle = builtins.readFile ./styles/workspaces.css; - in lib.mkIf cfg.enable { + config = + let + # styles from https://github.com/khaneliman/khanelinix/blob/8375f8cfbe5bfd87565b4dc34c9d30630c17336d/modules/home/desktop/addons/waybar/default.nix + base16 = config.stylix.base16Scheme; + readAndReplace = path: replace: builtins.readFile (pkgs.replaceVars path replace); + # base 1, 7, 0 + #theme = readAndReplace ./styles/theme.css { BASE="#5c4133"; BORDER="#fef1de"; TEXT="#dab353";}; + theme = builtins.readFile ./styles/theme.css; + style = builtins.readFile ./styles/style.css; + notificationsStyle = builtins.readFile ./styles/notifications.css; + powerStyle = builtins.readFile ./styles/power.css; + statsStyle = builtins.readFile ./styles/stats.css; + workspacesStyle = builtins.readFile ./styles/workspaces.css; + in + lib.mkIf cfg.enable { - home.file.".config/waybar" = { - recursive = true; - source = ../../.config/waybar; - }; - programs.waybar = { - enable = true; - #systemd.enable = true; - #systemd.target = "sway-session.target"; - settings.main = { - layer = "top"; - position = "bottom"; - #output = lib.mapAttrsToList (n: v: v.monitor) outputs; - height = 25; - spacing = 4; - modules-left = [ - "hyprland/workspaces" - #"hyprland/window" - ]; - modules-center = [ ]; - modules-right = [ "group/stats" "group/other" ]; - "group/stats" = { - "orientation" = "horizontal"; - "modules" = [ "network" "cpu" "memory" "temperature" ] + home.file.".config/waybar" = { + recursive = true; + source = ../../.config/waybar; + }; + programs.waybar = { + enable = true; + #systemd.enable = true; + #systemd.target = "sway-session.target"; + settings.main = { + layer = "top"; + position = "bottom"; + #output = lib.mapAttrsToList (n: v: v.monitor) outputs; + height = 25; + spacing = 4; + modules-left = [ + "hyprland/workspaces" + #"hyprland/window" + ]; + modules-center = [ ]; + modules-right = [ "group/stats" "group/other" ]; + "group/stats" = { + "orientation" = "horizontal"; + "modules" = [ "network" "cpu" "memory" "temperature" ] ++ lib.optionals osConfig.custom.hardware.nvidia.enable [ "custom/nvidia" ] ++ lib.optionals osConfig.custom.hardware.amd-gpu.enable [ "custom/amd-gpu" ]; - }; - "group/other" = { - "orientation" = "horizontal"; - "modules" = - [ "tray" "backlight" "pulseaudio" "mpris" "battery" "clock" ]; - }; - "cpu" = { - "format" = " {usage}%"; - "tooltip" = true; - }; - "disk" = { "format" = " {percentage_used}%"; }; - "memory" = { "format" = "󰍛 {}%"; }; - - "idle_inhibitor" = { - "format" = "{icon} "; - "format-icons" = { - "activated" = ""; - "deactivated" = ""; }; - }; - - "keyboard-state" = { - "numlock" = true; - "capslock" = true; - "format" = "{icon} {name}"; - "format-icons" = { - "locked" = ""; - "unlocked" = ""; + "group/other" = { + "orientation" = "horizontal"; + "modules" = + [ "tray" "backlight" "pulseaudio" "mpris" "battery" "clock" ]; }; - }; - - "network" = { - "interval" = 2; - "format-wifi" = " 󰜮 {bandwidthDownBytes} 󰜷 {bandwidthUpBytes}"; - "format-ethernet" = "󰈀 󰜮 {bandwidthDownBytes} 󰜷 {bandwidthUpBytes}"; - "tooltip-format" = " {ifname} via {gwaddr}"; - "format-linked" = "󰈁 {ifname} (No IP)"; - "format-disconnected" = " Disconnected"; - "format-alt" = "{ifname}: {ipaddr}/{cidr}"; - }; - "pulseaudio" = { - "format" = "{volume}% {icon}"; - "format-bluetooth" = "{volume}% {icon}"; - "format-muted" = ""; - "format-icons" = { - "headphone" = " "; - "hands-free" = " "; - "headset" = " "; - "phone" = ""; - "portable" = ""; - "car" = ""; - "default" = [ "" "" ]; + "cpu" = { + "format" = " {usage}%"; + "tooltip" = true; }; - "scroll-step" = 1; - "on-click" = "${pkgs.pavucontrol}/bin/pavucontrol"; - "ignored-sinks" = [ "Easy Effects Sink" ]; - }; + "disk" = { "format" = " {percentage_used}%"; }; + "memory" = { "format" = "󰍛 {}%"; }; - "pulseaudio/slider" = { - "min" = 0; - "max" = 100; - "orientation" = "horizontal"; - }; - "temperature".critical-threshold = 80; - "temperature".format = "{temperatureC}°C "; - "temperature".interval = 5; - "temperature".hwmon-path = - lib.mkIf (osConfig.networking.hostName == "nix-laptop") - "/sys/class/hwmon/hwmon6/temp1_input"; - "backlight".format = "{percent}% {icon}"; - "backlight".states = [ 0 50 ]; - "backlight".format-icons = [ "" "" ]; - "battery".states.good = 95; - "battery".interval = 5; - "battery".states.warning = 30; - "battery".states.critical = 15; - "battery".format = "{capacity}% / {power:.2}W {icon}"; - "battery".format-icons = [ "" "" "" "" "" ]; - "clock" = { - format = "{:%F %H:%M}"; - tooltip-format = "{calendar}"; - "calendar" = { - "mode" = "year"; - "mode-mon-col" = 3; - "weeks-pos" = "right"; - "on-scroll" = 1; - "format" = { - "months" = "{}"; - "days" = "{}"; - "weeks" = "W{}"; - "weekdays" = "{}"; - "today" = "{}"; + "idle_inhibitor" = { + "format" = "{icon} "; + "format-icons" = { + "activated" = ""; + "deactivated" = ""; + }; + }; + + "keyboard-state" = { + "numlock" = true; + "capslock" = true; + "format" = "{icon} {name}"; + "format-icons" = { + "locked" = ""; + "unlocked" = ""; + }; + }; + + "network" = { + "interval" = 2; + "format-wifi" = " 󰜮 {bandwidthDownBytes} 󰜷 {bandwidthUpBytes}"; + "format-ethernet" = "󰈀 󰜮 {bandwidthDownBytes} 󰜷 {bandwidthUpBytes}"; + "tooltip-format" = " {ifname} via {gwaddr}"; + "format-linked" = "󰈁 {ifname} (No IP)"; + "format-disconnected" = " Disconnected"; + "format-alt" = "{ifname}: {ipaddr}/{cidr}"; + }; + "pulseaudio" = { + "format" = "{volume}% {icon}"; + "format-bluetooth" = "{volume}% {icon}"; + "format-muted" = ""; + "format-icons" = { + "headphone" = " "; + "hands-free" = " "; + "headset" = " "; + "phone" = ""; + "portable" = ""; + "car" = ""; + "default" = [ "" "" ]; + }; + "scroll-step" = 1; + "on-click" = "${pkgs.pavucontrol}/bin/pavucontrol"; + "ignored-sinks" = [ "Easy Effects Sink" ]; + }; + + "pulseaudio/slider" = { + "min" = 0; + "max" = 100; + "orientation" = "horizontal"; + }; + "temperature".critical-threshold = 80; + "temperature".format = "{temperatureC}°C "; + "temperature".interval = 5; + "temperature".hwmon-path = + lib.mkIf (osConfig.networking.hostName == "nix-laptop") + "/sys/class/hwmon/hwmon6/temp1_input"; + "backlight".format = "{percent}% {icon}"; + "backlight".states = [ 0 50 ]; + "backlight".format-icons = [ "" "" ]; + "battery".states.good = 95; + "battery".interval = 5; + "battery".states.warning = 30; + "battery".states.critical = 15; + "battery".format = "{capacity}% / {power:.2}W {icon}"; + "battery".format-icons = [ "" "" "" "" "" ]; + "clock" = { + format = "{:%F %H:%M}"; + tooltip-format = "{calendar}"; + "calendar" = { + "mode" = "year"; + "mode-mon-col" = 3; + "weeks-pos" = "right"; + "on-scroll" = 1; + "format" = { + "months" = "{}"; + "days" = "{}"; + "weeks" = "W{}"; + "weekdays" = "{}"; + "today" = "{}"; + }; + }; + }; + "mpris" = { + "format" = "{player_icon} {dynamic}"; + "format-paused" = "{status_icon} {dynamic}"; + "title-len" = 35; + "dynamic-len" = 35; + "player-icons" = { + "default" = "▶"; + "mpv" = "🎵"; + }; + "status-icons" = { "paused" = "⏸"; }; + }; + "custom/nvidia" = { + "format" = "{}"; + "interval" = 5; + "exec" = "~/.config/waybar/nvidia.sh"; + "exec-if" = "nvidia-smi"; + }; + "custom/amd-gpu" = { + "format" = "{}"; + "interval" = 5; + "exec" = "~/.config/waybar/amd-gpu.sh"; + }; + "tray".icon-size = 21; + "tray".spacing = 10; + "hyprland/window" = { + "format" = "{}"; + "separate-outputs" = true; + }; + + "hyprland/workspaces" = { + "disable-scroll" = true; + "all-outputs" = false; + "active-only" = false; + "on-click" = "activate"; + "format" = "{icon} {windows}"; + "format-icons" = { + "1" = "󰎤"; + "2" = "󰎧"; + "3" = "󰎪"; + "4" = "󰎭"; + "5" = "󰎱"; + "6" = "󰎳"; + "7" = "󰎶"; + "8" = "󰎹"; + "9" = "󰎼"; + "10" = "󰽽"; + "urgent" = "󱨇"; + "default" = ""; + "empty" = "󱓼"; + }; + # "format-window-separator" = "->"; + "window-rewrite-default" = ""; + "window-rewrite" = { + "class" = "󰢁"; + "class" = "󰈎"; + "class" = "󰊤"; + "class" = ""; + "class" = ""; + "class" = "󰒱"; + "class" = "󰨞"; + "class" = "󰨞"; + "code-url-handler" = "󰨞"; + "class" = "󰙯"; + "class" = ""; + "class" = ""; + "class" = ""; + "class title<.*github.*>" = ""; + "class title<.*twitch|youtube|plex|tntdrama|bally sports.*>" = + ""; + "class" = ""; + "class" = ""; + "class" = "󱂷"; + "class" = "󰄄"; + "class" = ""; + "class<.pitivi-wrapped>" = "󱄢"; + "class" = ""; + "class" = ""; + "class" = "󰢹"; + "class" = "󰕼"; + "class" = "󰉋"; + "class" = "󰉋"; + "class" = ""; + "title" = ""; + "class" = "󰽉"; + "class" = ""; + "class" = "󱎏"; + "class" = "󱎐"; + "class" = "󰊻"; + "class" = "󰍳"; + "class" = "󰍳"; + "class" = "󰛮"; + "class" = ""; + "class" = ""; + "class" = ""; }; }; }; - "mpris" = { - "format" = "{player_icon} {dynamic}"; - "format-paused" = "{status_icon} {dynamic}"; - "title-len" = 35; - "dynamic-len" = 35; - "player-icons" = { - "default" = "▶"; - "mpv" = "🎵"; - }; - "status-icons" = { "paused" = "⏸"; }; - }; - "custom/nvidia" = { - "format" = "{}"; - "interval" = 5; - "exec" = "~/.config/waybar/nvidia.sh"; - "exec-if" = "nvidia-smi"; - }; - "custom/amd-gpu" = { - "format" = "{}"; - "interval" = 5; - "exec" = "~/.config/waybar/amd-gpu.sh"; - }; - "tray".icon-size = 21; - "tray".spacing = 10; - "hyprland/window" = { - "format" = "{}"; - "separate-outputs" = true; - }; - - "hyprland/workspaces" = { - "disable-scroll" = true; - "all-outputs" = false; - "active-only" = false; - "on-click" = "activate"; - "format" = "{icon} {windows}"; - "format-icons" = { - "1" = "󰎤"; - "2" = "󰎧"; - "3" = "󰎪"; - "4" = "󰎭"; - "5" = "󰎱"; - "6" = "󰎳"; - "7" = "󰎶"; - "8" = "󰎹"; - "9" = "󰎼"; - "10" = "󰽽"; - "urgent" = "󱨇"; - "default" = ""; - "empty" = "󱓼"; - }; - # "format-window-separator" = "->"; - "window-rewrite-default" = ""; - "window-rewrite" = { - "class" = "󰢁"; - "class" = "󰈎"; - "class" = "󰊤"; - "class" = ""; - "class" = ""; - "class" = "󰒱"; - "class" = "󰨞"; - "class" = "󰨞"; - "code-url-handler" = "󰨞"; - "class" = "󰙯"; - "class" = ""; - "class" = ""; - "class" = ""; - "class title<.*github.*>" = ""; - "class title<.*twitch|youtube|plex|tntdrama|bally sports.*>" = - ""; - "class" = ""; - "class" = ""; - "class" = "󱂷"; - "class" = "󰄄"; - "class" = ""; - "class<.pitivi-wrapped>" = "󱄢"; - "class" = ""; - "class" = ""; - "class" = "󰢹"; - "class" = "󰕼"; - "class" = "󰉋"; - "class" = "󰉋"; - "class" = ""; - "title" = ""; - "class" = "󰽉"; - "class" = ""; - "class" = "󱎏"; - "class" = "󱎐"; - "class" = "󰊻"; - "class" = "󰍳"; - "class" = "󰍳"; - "class" = "󰛮"; - "class" = ""; - "class" = ""; - "class" = ""; - }; - }; + style = + "${theme}${style}${notificationsStyle}${powerStyle}${statsStyle}${workspacesStyle}"; }; - style = - "${theme}${style}${notificationsStyle}${powerStyle}${statsStyle}${workspacesStyle}"; }; - }; } diff --git a/home-manager/i3.nix b/home-manager/i3.nix index a6871d8..ad94000 100644 --- a/home-manager/i3.nix +++ b/home-manager/i3.nix @@ -56,8 +56,8 @@ in { modules-left = "i3 xwindow"; modules-center = ""; modules-right = [ "music network memory cpu cpu-wattage cpu-temp" ] - ++ lib.optionals osConfig.custom.hardware.nvidia.enable [ "nvidia-gpu" ] - ++ lib.optionals osConfig.custom.hardware.amd-gpu.enable [ "amd-gpu" ] + ++ lib.optionals osConfig.custom.hardware.nvidia.enable [ "nvidia-gpu" ] + ++ lib.optionals osConfig.custom.hardware.amd-gpu.enable [ "amd-gpu" ] ++ [ "pulseaudio date tray" ]; cursor-click = "pointer"; cursor-scroll = "ns-resize"; @@ -68,33 +68,34 @@ in { # wm-restack = "i3"; # override-redirect = true; }; - "module/i3" = let padding = 2; - in { - type = "internal/i3"; - pin-workspaces = true; - show-urgent = true; - strip-wsnumbers = true; - index-sort = true; - enable-click = true; - wrapping-scroll = true; - fuzzy-match = true; - format = " "; - label-focused = "%name%"; - label-focused-foreground = config.stylix.base16Scheme.base01; - label-focused-background = config.stylix.base16Scheme.base05; - label-focused-underline = config.stylix.base16Scheme.base03; - label-focused-padding = padding; - label-unfocused = "%name%"; - label-unfocused-padding = padding; - label-visible = "%name%"; - label-visible-underline = config.stylix.base16Scheme.base01; - label-visible-padding = padding; - label-urgent = "%name%"; - label-urgent-foreground = config.stylix.base16Scheme.base00; - label-urgent-background = config.stylix.base16Scheme.base08; - label-urgent-underline = config.stylix.base16Scheme.base0F; - label-urgent-padding = padding; - }; + "module/i3" = + let padding = 2; + in { + type = "internal/i3"; + pin-workspaces = true; + show-urgent = true; + strip-wsnumbers = true; + index-sort = true; + enable-click = true; + wrapping-scroll = true; + fuzzy-match = true; + format = " "; + label-focused = "%name%"; + label-focused-foreground = config.stylix.base16Scheme.base01; + label-focused-background = config.stylix.base16Scheme.base05; + label-focused-underline = config.stylix.base16Scheme.base03; + label-focused-padding = padding; + label-unfocused = "%name%"; + label-unfocused-padding = padding; + label-visible = "%name%"; + label-visible-underline = config.stylix.base16Scheme.base01; + label-visible-padding = padding; + label-urgent = "%name%"; + label-urgent-foreground = config.stylix.base16Scheme.base00; + label-urgent-background = config.stylix.base16Scheme.base08; + label-urgent-underline = config.stylix.base16Scheme.base0F; + label-urgent-padding = padding; + }; "module/xworkspaces" = { type = "internal/xworkspaces"; label-active = "%name%"; @@ -198,7 +199,7 @@ in { }; "module/amd-gpu" = { type = "custom/script"; - format-foreground = "ed1c24"; + format-foreground = "ed1c24"; label = "%output:0:35:...%"; exec = "~/.config/polybar/amd-gpu.sh"; interval = 3; diff --git a/home-manager/kde-path.nix b/home-manager/kde-path.nix index c5f866a..8bf1743 100644 --- a/home-manager/kde-path.nix +++ b/home-manager/kde-path.nix @@ -1,47 +1,47 @@ { config, ... }: { - home.file."path.sh" = { - enable = true; - recursive = true; - executable = true; - text = '' - #!/usr/bin/env sh - if [ "$XDG_SESSION_TYPE" = "wayland" ]; then - export MOZ_DBUS_REMOTE="1" - export KITTY_ENABLE_WAYLAND="1" - export _JAVA_AWT_WM_NONREPARENTING="1" - export MOZ_ENABLE_WAYLAND="1" - export WLR_NO_HARDWARE_CURSORS="1" - export NIXOS_OZONE_WL="1" + home.file."path.sh" = { + enable = true; + recursive = true; + executable = true; + text = '' + #!/usr/bin/env sh + if [ "$XDG_SESSION_TYPE" = "wayland" ]; then + export MOZ_DBUS_REMOTE="1" + export KITTY_ENABLE_WAYLAND="1" + export _JAVA_AWT_WM_NONREPARENTING="1" + export MOZ_ENABLE_WAYLAND="1" + export WLR_NO_HARDWARE_CURSORS="1" + export NIXOS_OZONE_WL="1" - export LIBVA_DRIVER_NAME="nvidia" - export __GLX_VENDOR_LIBRARY_NAME="nvidia" - export GBM_BACKEND="nvidia-drm" + export LIBVA_DRIVER_NAME="nvidia" + export __GLX_VENDOR_LIBRARY_NAME="nvidia" + export GBM_BACKEND="nvidia-drm" - export XDG_SESSION_TYPE="wayland" - export QT_QPA_PLATFORM="wayland;xcb" - export ELECTRON_OZONE_PLATFORM_HINT="wayland" - fi - ''; - target = ".config/plasma-workspace/env/path.sh"; - }; - # home.file."path.desktop" = { - # enable = true; - # recursive = true; - # executable = true; - # text = '' - # [Desktop Entry] - # Type=Application - # Exec=${config.xdg.configHome}/autostart/path.sh - # Hidden=false - # NoDisplay=false - # X-GNOME-Autostart-enabled=true - # Name[en_US]=Login Script - # Name=Login Script - # Comment[en_US]=Launches login script and sets environment variables - # Comment=Launches login script and sets environment variables - # ''; - # target = ".config/autostart/path.desktop"; - # }; + export XDG_SESSION_TYPE="wayland" + export QT_QPA_PLATFORM="wayland;xcb" + export ELECTRON_OZONE_PLATFORM_HINT="wayland" + fi + ''; + target = ".config/plasma-workspace/env/path.sh"; + }; + # home.file."path.desktop" = { + # enable = true; + # recursive = true; + # executable = true; + # text = '' + # [Desktop Entry] + # Type=Application + # Exec=${config.xdg.configHome}/autostart/path.sh + # Hidden=false + # NoDisplay=false + # X-GNOME-Autostart-enabled=true + # Name[en_US]=Login Script + # Name=Login Script + # Comment[en_US]=Launches login script and sets environment variables + # Comment=Launches login script and sets environment variables + # ''; + # target = ".config/autostart/path.desktop"; + # }; } diff --git a/home-manager/kitty.nix b/home-manager/kitty.nix index bcbbfbf..a251c2b 100644 --- a/home-manager/kitty.nix +++ b/home-manager/kitty.nix @@ -1,4 +1,4 @@ -{ config, pkgs, inputs, lib, ...}: +{ config, pkgs, inputs, lib, ... }: { programs.kitty = { enable = true; diff --git a/home-manager/lf.nix b/home-manager/lf.nix index 7608f35..e8f45e1 100644 --- a/home-manager/lf.nix +++ b/home-manager/lf.nix @@ -1,16 +1,16 @@ -{ config, pkgs, inputs, ...}: +{ config, pkgs, inputs, ... }: { - programs.lf = { - enable = true; - previewer.source = pkgs.writeShellScript "pv.sh" '' - #!/bin/sh - case "$(${pkgs.file}/bin/file -Lb --mime-type -- "$1")" in - #image/*|video/*) ${pkgs.chafa}/bin/chafa -f sixel -s "$2x$3" --animate false $1;; - application/x-tar) tar tf "$1";; - application/vnd.rar) ${pkgs.p7zip}/bin/7z l "$1";; - application/x-7z-compressed) ${pkgs.p7zip}/bin/7z l "$1";; - *) ${pkgs.ctpv}/bin/ctpv "$1";; - esac - ''; - }; + programs.lf = { + enable = true; + previewer.source = pkgs.writeShellScript "pv.sh" '' + #!/bin/sh + case "$(${pkgs.file}/bin/file -Lb --mime-type -- "$1")" in + #image/*|video/*) ${pkgs.chafa}/bin/chafa -f sixel -s "$2x$3" --animate false $1;; + application/x-tar) tar tf "$1";; + application/vnd.rar) ${pkgs.p7zip}/bin/7z l "$1";; + application/x-7z-compressed) ${pkgs.p7zip}/bin/7z l "$1";; + *) ${pkgs.ctpv}/bin/ctpv "$1";; + esac + ''; + }; } diff --git a/home-manager/mpv.nix b/home-manager/mpv.nix index 3e3ea9c..837327e 100644 --- a/home-manager/mpv.nix +++ b/home-manager/mpv.nix @@ -1,4 +1,4 @@ -{ config, pkgs, inputs, ...}: +{ config, pkgs, inputs, ... }: { programs.mpv = { enable = true; diff --git a/home-manager/nixvim/auto-pairs.nix b/home-manager/nixvim/auto-pairs.nix index 4d94d45..448282c 100644 --- a/home-manager/nixvim/auto-pairs.nix +++ b/home-manager/nixvim/auto-pairs.nix @@ -1,3 +1,3 @@ -{ - plugins.nvim-autopairs = { enable = true; }; +{ + plugins.nvim-autopairs = { enable = true; }; } diff --git a/home-manager/nixvim/config.nix b/home-manager/nixvim/config.nix index 945eadf..1b1db37 100644 --- a/home-manager/nixvim/config.nix +++ b/home-manager/nixvim/config.nix @@ -1,4 +1,4 @@ -{lib, pkgs, ...}: +{ lib, pkgs, ... }: { enable = true; viAlias = true; diff --git a/home-manager/nixvim/default.nix b/home-manager/nixvim/default.nix index 97b2f62..9179dba 100644 --- a/home-manager/nixvim/default.nix +++ b/home-manager/nixvim/default.nix @@ -30,7 +30,8 @@ let ]; merged = builtins.foldl' (acc: elem: lib.recursiveUpdate acc elem) { } configs; -in { +in +{ home.sessionVariables = { EDITOR = "nvim"; }; programs.nixvim = merged; } diff --git a/home-manager/nixvim/images.nix b/home-manager/nixvim/images.nix index 9789ffd..6a9b650 100644 --- a/home-manager/nixvim/images.nix +++ b/home-manager/nixvim/images.nix @@ -1,4 +1,4 @@ -{pkgs, ...}: +{ pkgs, ... }: { plugins = { image.enable = true; diff --git a/home-manager/nixvim/lsp.nix b/home-manager/nixvim/lsp.nix index c5f6c35..37b8e1c 100644 --- a/home-manager/nixvim/lsp.nix +++ b/home-manager/nixvim/lsp.nix @@ -1,19 +1,28 @@ -{pkgs, ...}: +{ pkgs, ... }: { plugins = { - otter = { # provide lsp functionality for code embedded in other languages + otter = { + # provide lsp functionality for code embedded in other languages enable = true; settings.handle_leading_whitespace = true; }; lsp = { enable = true; + inlayHints = true; servers = { bashls.enable = true; #ccls.enable = true; clangd.enable = true; cssls.enable = true; gopls.enable = true; - nixd.enable = true; + nixd = { + enable = true; + settings = { + nixpkgs.expr = ''import { }''; + formatting.command = [ "nixpkgs-fmt" ]; + options.nixos.expr = ''(builtins.getFlake ("/home/kopatz/projects/github/nix-config")).nixosConfigurations.kop-pc.options''; + }; + }; html.enable = true; dartls.enable = true; ts_ls.enable = true; diff --git a/home-manager/nixvim/none-ls.nix b/home-manager/nixvim/none-ls.nix index 9ca63ec..f57f2bb 100644 --- a/home-manager/nixvim/none-ls.nix +++ b/home-manager/nixvim/none-ls.nix @@ -10,7 +10,7 @@ fantomas.enable = true; gofmt.enable = true; goimports.enable = true; - nixfmt.enable = true; + #nixfmt.enable = true; markdownlint.enable = true; shellharden.enable = true; shfmt.enable = true; diff --git a/home-manager/nixvim/which_key.nix b/home-manager/nixvim/which_key.nix index 652264f..46223c5 100644 --- a/home-manager/nixvim/which_key.nix +++ b/home-manager/nixvim/which_key.nix @@ -1,5 +1,6 @@ -{ +{ opts = { timeoutlen = 500; }; - plugins.which-key = { enable = true; }; } + plugins.which-key = { enable = true; }; +} diff --git a/home-manager/nvim.nix b/home-manager/nvim.nix index f1ba06f..26f36a2 100644 --- a/home-manager/nvim.nix +++ b/home-manager/nvim.nix @@ -1,24 +1,24 @@ -{ config, pkgs, inputs, ...}: +{ config, pkgs, inputs, ... }: { - home.file.".config/nvim" = { - enable = true; - recursive = true; - source = ../.config/nvim; - target = ".config/nvim"; - }; - programs.neovim = { - enable = true; - defaultEditor = true; - extraPackages = with pkgs; [ - gcc - ripgrep - fd - cmake - pyright - nodePackages.eslint - ccls - nodejs_22 - go - ]; - }; + home.file.".config/nvim" = { + enable = true; + recursive = true; + source = ../.config/nvim; + target = ".config/nvim"; + }; + programs.neovim = { + enable = true; + defaultEditor = true; + extraPackages = with pkgs; [ + gcc + ripgrep + fd + cmake + pyright + nodePackages.eslint + ccls + nodejs_22 + go + ]; + }; } diff --git a/home-manager/rofi/default.nix b/home-manager/rofi/default.nix index 1b7a874..0131150 100644 --- a/home-manager/rofi/default.nix +++ b/home-manager/rofi/default.nix @@ -8,7 +8,8 @@ let r = c."${color}-rgb-r"; g = c."${color}-rgb-g"; b = c."${color}-rgb-b"; - in "rgba ( ${r}, ${g}, ${b}, ${opacity} % )"; + in + "rgba ( ${r}, ${g}, ${b}, ${opacity} % )"; mkRgb = mkRgba "100"; rofiOpacity = builtins.toString (builtins.ceil (config.stylix.opacity.popups * 100)); @@ -55,7 +56,8 @@ let alternate-active-text = mkRgb "base0D"; alternate-urgent-text = mkRgb "base08"; }; -in { +in +{ home.file.".config/rofi" = { enable = true; recursive = true; diff --git a/home-manager/stylix.nix b/home-manager/stylix.nix index 5679cc2..6ebdec9 100644 --- a/home-manager/stylix.nix +++ b/home-manager/stylix.nix @@ -1,7 +1,9 @@ { osConfig, pkgs, config, lib, ... }: -let cfg = osConfig.custom.graphical.stylix; +let + cfg = osConfig.custom.graphical.stylix; base16 = config.stylix.base16Scheme; -in { +in +{ config = lib.mkIf cfg.enable { stylix = { enable = true; @@ -17,7 +19,7 @@ in { }; wayland.windowManager.hyprland.settings = lib.mkIf osConfig.custom.graphical.hyprland.enable { - env = ["GTK_THEME,adw-gtk3"]; + env = [ "GTK_THEME,adw-gtk3" ]; general."col.active_border" = lib.mkForce "rgb(${base16.base07}) rgb(${base16.base04}) 45deg"; }; }; diff --git a/home-manager/theme.nix b/home-manager/theme.nix index 2823a07..556a3a0 100644 --- a/home-manager/theme.nix +++ b/home-manager/theme.nix @@ -1,4 +1,4 @@ -{ config, pkgs, inputs, ...}: +{ config, pkgs, inputs, ... }: { home = { pointerCursor = { @@ -10,7 +10,7 @@ }; gtk = { enable = true; - theme = { + theme = { name = "Tokyonight-Dark-BL"; package = pkgs.tokyo-night-gtk; }; diff --git a/home-manager/themes/yorha/colors.nix b/home-manager/themes/yorha/colors.nix index 445a70a..ba2983b 100644 --- a/home-manager/themes/yorha/colors.nix +++ b/home-manager/themes/yorha/colors.nix @@ -1,23 +1,23 @@ { - slug = "yorha"; - name = "yorha"; - author = "flick0 (https://github.com/flick0)"; - palette = { - base00 = "#1e1d1c"; - base01 = "#A39D8F"; - base02 = "#AFA899"; - base03 = "#BBB4A5"; - base04 = "#C3BCAB"; - base05 = "#D2CCB9"; - base06 = "#DBD5C2"; - base07 = "#e8e5da"; - base08 = "#a2a098"; - base09 = "#A39D8F"; - base10 = "#AFA899"; - base11 = "#BBB4A5"; - base12 = "#C3BCAB"; - base13 = "#D2CCB9"; - base14 = "#DBD5C2"; - base15 = "#e8e5da"; - }; + slug = "yorha"; + name = "yorha"; + author = "flick0 (https://github.com/flick0)"; + palette = { + base00 = "#1e1d1c"; + base01 = "#A39D8F"; + base02 = "#AFA899"; + base03 = "#BBB4A5"; + base04 = "#C3BCAB"; + base05 = "#D2CCB9"; + base06 = "#DBD5C2"; + base07 = "#e8e5da"; + base08 = "#a2a098"; + base09 = "#A39D8F"; + base10 = "#AFA899"; + base11 = "#BBB4A5"; + base12 = "#C3BCAB"; + base13 = "#D2CCB9"; + base14 = "#DBD5C2"; + base15 = "#e8e5da"; + }; } diff --git a/modules/cron.nix b/modules/cron.nix index 6c05ec9..45c7141 100644 --- a/modules/cron.nix +++ b/modules/cron.nix @@ -1,5 +1,5 @@ { - services.cron = { - enable = true; - }; + services.cron = { + enable = true; + }; } diff --git a/modules/cursed-ssh-conf-for-3neo.nix b/modules/cursed-ssh-conf-for-3neo.nix index abca1a0..8f61aa5 100644 --- a/modules/cursed-ssh-conf-for-3neo.nix +++ b/modules/cursed-ssh-conf-for-3neo.nix @@ -1,40 +1,40 @@ { services.openssh.enable = true; services.openssh.extraConfig = '' - HostKeyAlgorithms +ssh-rsa - PubkeyAcceptedAlgorithms +ssh-rsa -''; + HostKeyAlgorithms +ssh-rsa + PubkeyAcceptedAlgorithms +ssh-rsa + ''; services.openssh.settings.Macs = [ - "hmac-md5" + "hmac-md5" ]; services.openssh.settings.Ciphers = [ - "3des-cbc" - "aes128-cbc" - "aes192-cbc" - "aes256-cbc" - "aes128-ctr" - "aes192-ctr" - "aes256-ctr" - "aes128-gcm@openssh.com" - "aes256-gcm@openssh.com" - "chacha20-poly1305@openssh.com" + "3des-cbc" + "aes128-cbc" + "aes192-cbc" + "aes256-cbc" + "aes128-ctr" + "aes192-ctr" + "aes256-ctr" + "aes128-gcm@openssh.com" + "aes256-gcm@openssh.com" + "chacha20-poly1305@openssh.com" ]; services.openssh.settings.KexAlgorithms = [ - "diffie-hellman-group1-sha1" - "diffie-hellman-group14-sha1" - "diffie-hellman-group14-sha256" - "diffie-hellman-group16-sha512" - "diffie-hellman-group18-sha512" - "diffie-hellman-group-exchange-sha1" - "diffie-hellman-group-exchange-sha256" - "ecdh-sha2-nistp256" - "ecdh-sha2-nistp384" - "ecdh-sha2-nistp521" - "curve25519-sha256" - "curve25519-sha256@libssh.org" - "sntrup761x25519-sha512@openssh.com" + "diffie-hellman-group1-sha1" + "diffie-hellman-group14-sha1" + "diffie-hellman-group14-sha256" + "diffie-hellman-group16-sha512" + "diffie-hellman-group18-sha512" + "diffie-hellman-group-exchange-sha1" + "diffie-hellman-group-exchange-sha256" + "ecdh-sha2-nistp256" + "ecdh-sha2-nistp384" + "ecdh-sha2-nistp521" + "curve25519-sha256" + "curve25519-sha256@libssh.org" + "sntrup761x25519-sha512@openssh.com" ]; services.atftpd.enable = true; } diff --git a/modules/default.nix b/modules/default.nix index 21d241b..a9207d9 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ...}: +{ pkgs, config, ... }: { imports = [ ./fh diff --git a/modules/ecryptfs.nix b/modules/ecryptfs.nix index 55a1894..fd35e7b 100644 --- a/modules/ecryptfs.nix +++ b/modules/ecryptfs.nix @@ -1,4 +1,4 @@ -{ pkgs, ...}: +{ pkgs, ... }: { environment.systemPackages = with pkgs; [ ecryptfs @@ -6,5 +6,5 @@ security.pam.enableEcryptfs = true; programs.ecryptfs.enable = true; - boot.kernelModules = ["ecryptfs"]; + boot.kernelModules = [ "ecryptfs" ]; } diff --git a/modules/fh/default.nix b/modules/fh/default.nix index 59e291a..6d72116 100644 --- a/modules/fh/default.nix +++ b/modules/fh/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ...}: +{ pkgs, config, ... }: { imports = [ diff --git a/modules/fh/forensik.nix b/modules/fh/forensik.nix index 66fc83a..8567012 100644 --- a/modules/fh/forensik.nix +++ b/modules/fh/forensik.nix @@ -1,11 +1,11 @@ -{ pkgs, ...} : +{ pkgs, ... }: { - environment.systemPackages = with pkgs; [ - regripper - foremost - binwalk - sleuthkit - samdump2 - apktool - ]; + environment.systemPackages = with pkgs; [ + regripper + foremost + binwalk + sleuthkit + samdump2 + apktool + ]; } diff --git a/modules/fh/scanning.nix b/modules/fh/scanning.nix index 242e099..02ee2f1 100644 --- a/modules/fh/scanning.nix +++ b/modules/fh/scanning.nix @@ -1,13 +1,13 @@ -{ pkgs, ...} : +{ pkgs, ... }: { - environment.systemPackages = with pkgs; [ - nmap - gobuster - thc-hydra - seclists - aircrack-ng - hashcat - hashcat-utils - john - ]; + environment.systemPackages = with pkgs; [ + nmap + gobuster + thc-hydra + seclists + aircrack-ng + hashcat + hashcat-utils + john + ]; } diff --git a/modules/fh/writing.nix b/modules/fh/writing.nix index 9ef4073..cc692db 100644 --- a/modules/fh/writing.nix +++ b/modules/fh/writing.nix @@ -1,4 +1,4 @@ -{pkgs, ...}: { +{ pkgs, ... }: { environment.systemPackages = with pkgs; [ typst ]; diff --git a/modules/flatpak.nix b/modules/flatpak.nix index e63b2ac..1ff0c53 100644 --- a/modules/flatpak.nix +++ b/modules/flatpak.nix @@ -1,3 +1,3 @@ { - services.flatpak.enable = true; + services.flatpak.enable = true; } diff --git a/modules/gpg.nix b/modules/gpg.nix index 0643c4d..f6c97b1 100644 --- a/modules/gpg.nix +++ b/modules/gpg.nix @@ -1,4 +1,4 @@ -{pkgs, ...}: +{ pkgs, ... }: { #services.pcscd.enable = true; @@ -9,5 +9,5 @@ }; #environment.systemPackages = with pkgs; [ # pinentry-curses - # ]; + # ]; } diff --git a/modules/graphical/audio.nix b/modules/graphical/audio.nix index 9169883..861fcfa 100644 --- a/modules/graphical/audio.nix +++ b/modules/graphical/audio.nix @@ -1,4 +1,4 @@ -{config, lib, pkgs, ...} : +{ config, lib, pkgs, ... }: with lib; let cfg = config.custom.graphical.audio; @@ -7,11 +7,11 @@ in options.custom.graphical.audio = { enable = mkEnableOption "Enables audio"; }; - + config = mkIf cfg.enable { # Enable sound with pipewire. security.rtkit.enable = true; - + services.pulseaudio.enable = false; services.pipewire = { enable = true; diff --git a/modules/graphical/code.nix b/modules/graphical/code.nix index 50d7523..cdc0edd 100644 --- a/modules/graphical/code.nix +++ b/modules/graphical/code.nix @@ -7,7 +7,7 @@ in options.custom.graphical.code = { enable = mkEnableOption "Enables code"; }; - + config = mkIf cfg.enable { documentation.dev.enable = true; environment.systemPackages = with pkgs; [ @@ -18,7 +18,7 @@ in insomnia nodejs_22 # needed for tabby extension ]; - + #environment.sessionVariables = { # DOTNET_ROOT = "${pkgs.dotnet-sdk_7}"; #}; diff --git a/modules/graphical/cosmic.nix b/modules/graphical/cosmic.nix index 0541b1d..cb79c26 100644 --- a/modules/graphical/cosmic.nix +++ b/modules/graphical/cosmic.nix @@ -6,7 +6,7 @@ in options.custom.graphical.cosmic = { enable = lib.mkEnableOption "Enables cosmic"; }; - + config = lib.mkIf cfg.enable { nix.settings = { substituters = [ "https://cosmic.cachix.org/" ]; diff --git a/modules/graphical/default.nix b/modules/graphical/default.nix index 5b3b6ef..a53e808 100644 --- a/modules/graphical/default.nix +++ b/modules/graphical/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, lib, ...}: +{ pkgs, config, lib, ... }: { imports = [ diff --git a/modules/graphical/emulators.nix b/modules/graphical/emulators.nix index f48abc3..f5f0d3d 100644 --- a/modules/graphical/emulators.nix +++ b/modules/graphical/emulators.nix @@ -1,4 +1,4 @@ -{lib, config, pkgs, inputs, ... }: +{ lib, config, pkgs, inputs, ... }: with lib; let cfg = config.custom.graphical.emulators; @@ -7,7 +7,7 @@ in options.custom.graphical.emulators = { enable = mkEnableOption "Enables emulators"; }; - + config = mkIf cfg.enable { environment.systemPackages = with pkgs; [ snes9x diff --git a/modules/graphical/games.nix b/modules/graphical/games.nix index f3641ef..c04f95e 100644 --- a/modules/graphical/games.nix +++ b/modules/graphical/games.nix @@ -11,7 +11,8 @@ let # hash = "sha256-aWpTUAm9FBuZI2KwEvhSnLB7Mfp5nYgUwvvLF47FIfM="; # }; #}); -in { +in +{ options.custom.graphical.games = { enable = mkEnableOption "Enables games"; enablePreinstalled = mkEnableOption "Enables preinstalled games"; @@ -42,16 +43,16 @@ in { ]; environment.systemPackages = [ pkgs.mangohud ] ++ optionals cfg.enablePreinstalled (with pkgs; [ - #taisei - #osu-lazer-bin - wineWowPackages.unstableFull - winetricks - lutris - prismlauncher - steamtinkerlaunch - tetrio-desktop - #libs - ]) ++ optionals cfg.enableVr (with pkgs; [ beatsabermodmanager ]); + #taisei + #osu-lazer-bin + wineWowPackages.unstableFull + winetricks + lutris + prismlauncher + steamtinkerlaunch + tetrio-desktop + #libs + ]) ++ optionals cfg.enableVr (with pkgs; [ beatsabermodmanager ]); }; } diff --git a/modules/graphical/lxqt.nix b/modules/graphical/lxqt.nix index 163e371..c7c8771 100644 --- a/modules/graphical/lxqt.nix +++ b/modules/graphical/lxqt.nix @@ -1,4 +1,4 @@ -{lib, config, pkgs, ...}: +{ lib, config, pkgs, ... }: with lib; let cfg = config.custom.graphical.lxqt; @@ -7,10 +7,10 @@ in options.custom.graphical.lxqt = { enable = mkEnableOption "Enables lxqt"; }; - + config = mkIf cfg.enable { services.xserver = { - xkb.layout = config.mainUser.layout; + xkb.layout = config.mainUser.layout; xkb.variant = config.mainUser.variant; enable = true; displayManager.sddm.enable = true; diff --git a/modules/graphical/noise-supression.nix b/modules/graphical/noise-supression.nix index 34d8aa9..f2195a4 100644 --- a/modules/graphical/noise-supression.nix +++ b/modules/graphical/noise-supression.nix @@ -1,15 +1,15 @@ -{config, pkgs, lib, ...}: +{ config, pkgs, lib, ... }: let - cfg = config.custom.graphical.noise-supression; + cfg = config.custom.graphical.noise-supression; in { - options.custom.graphical.noise-supression = { - enable = lib.mkEnableOption "Enables noise-supression"; - }; - - config = lib.mkIf cfg.enable { - environment.systemPackages = with pkgs; [ - easyeffects - ]; - }; + options.custom.graphical.noise-supression = { + enable = lib.mkEnableOption "Enables noise-supression"; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + easyeffects + ]; + }; } diff --git a/modules/graphical/obs.nix b/modules/graphical/obs.nix index b879008..37d55a1 100644 --- a/modules/graphical/obs.nix +++ b/modules/graphical/obs.nix @@ -1,4 +1,4 @@ -{lib, config, pkgs, ...}: +{ lib, config, pkgs, ... }: with lib; let cfg = config.custom.graphical.obs; @@ -7,14 +7,14 @@ in options.custom.graphical.obs = { enable = mkEnableOption "Enables obs"; }; - + config = mkIf cfg.enable { # borked in unstable branch #boot = { # kernelModules = ["v4l2loopback"]; # Autostart kernel modules on boot # extraModulePackages = with config.boot.kernelPackages; [v4l2loopback]; # loopback module to make OBS virtual camera work #}; - + environment.systemPackages = with pkgs; [ (wrapOBS { plugins = with obs-studio-plugins; [ diff --git a/modules/graphical/openrgb.nix b/modules/graphical/openrgb.nix index eb68eba..4bbfda4 100644 --- a/modules/graphical/openrgb.nix +++ b/modules/graphical/openrgb.nix @@ -1,4 +1,4 @@ -{config, lib, pkgs, ...}: +{ config, lib, pkgs, ... }: with lib; let cfg = config.custom.graphical.openrgb; @@ -7,7 +7,7 @@ in options.custom.graphical.openrgb = { enable = mkEnableOption "Enables openrgb"; }; - + config = mkIf cfg.enable { services.hardware.openrgb.enable = true; services.hardware.openrgb.package = pkgs.openrgb-with-all-plugins; diff --git a/modules/graphical/shared.nix b/modules/graphical/shared.nix index 7123d6b..8720771 100644 --- a/modules/graphical/shared.nix +++ b/modules/graphical/shared.nix @@ -6,68 +6,70 @@ in { enable = mkEnableOption "Enables shared"; }; - config = let - screenshot = pkgs.writeShellScriptBin "screenshot" '' - ${pkgs.scrot}/bin/scrot -fs - | ${pkgs.xclip}/bin/xclip -selection clipboard -t image/png -i - ''; - in mkIf cfg.enable { - programs.dconf.enable = true; + config = + let + screenshot = pkgs.writeShellScriptBin "screenshot" '' + ${pkgs.scrot}/bin/scrot -fs - | ${pkgs.xclip}/bin/xclip -selection clipboard -t image/png -i + ''; + in + mkIf cfg.enable { + programs.dconf.enable = true; - fonts.fontDir.enable = true; - fonts.packages = with pkgs; [ - #uw-ttyp0 - #corefonts - nerd-fonts.noto - nerd-fonts.hack - #noto-fonts - #noto-fonts-emoji - noto-fonts-cjk-sans - #font-awesome - ]; - services.libinput = { - enable = true; + fonts.fontDir.enable = true; + fonts.packages = with pkgs; [ + #uw-ttyp0 + #corefonts + nerd-fonts.noto + nerd-fonts.hack + #noto-fonts + #noto-fonts-emoji + noto-fonts-cjk-sans + #font-awesome + ]; + services.libinput = { + enable = true; - # disabling mouse acceleration - mouse = { - accelProfile = "flat"; - middleEmulation = false; + # disabling mouse acceleration + mouse = { + accelProfile = "flat"; + middleEmulation = false; + }; }; - }; - programs.kdeconnect.enable = true; - networking.firewall = { - enable = true; - allowedTCPPorts = [ 25565 53317 ]; # localsend - allowedUDPPorts = [ 1194 53317 ]; # openvpn, localsend - allowedTCPPortRanges = [{ - from = 1714; - to = 1764; - } # KDE Connect + programs.kdeconnect.enable = true; + networking.firewall = { + enable = true; + allowedTCPPorts = [ 25565 53317 ]; # localsend + allowedUDPPorts = [ 1194 53317 ]; # openvpn, localsend + allowedTCPPortRanges = [{ + from = 1714; + to = 1764; + } # KDE Connect ]; - allowedUDPPortRanges = [{ - from = 1714; - to = 1764; - } # KDE Connect + allowedUDPPortRanges = [{ + from = 1714; + to = 1764; + } # KDE Connect ]; + }; + + #services.xserver.wacom.enable = true; + services.tumbler.enable = true; # for thumbnails + programs.file-roller.enable = true; + programs.thunar.enable = true; + programs.thunar.plugins = with pkgs.xfce; [ + thunar-archive-plugin + thunar-volman + ]; + services.gvfs.enable = true; # for file manager, trash support, etc. + + # List packages installed in system profile. To search, run: + # $ nix search wget + environment.systemPackages = with pkgs; [ + keepassxc + screenshot + wl-clipboard + xarchiver # archive tool + adwaita-icon-theme + ]; }; - - #services.xserver.wacom.enable = true; - services.tumbler.enable = true; # for thumbnails - programs.file-roller.enable = true; - programs.thunar.enable = true; - programs.thunar.plugins = with pkgs.xfce; [ - thunar-archive-plugin - thunar-volman - ]; - services.gvfs.enable = true; # for file manager, trash support, etc. - - # List packages installed in system profile. To search, run: - # $ nix search wget - environment.systemPackages = with pkgs; [ - keepassxc - screenshot - wl-clipboard - xarchiver # archive tool - adwaita-icon-theme - ]; - }; } diff --git a/modules/graphical/xfce.nix b/modules/graphical/xfce.nix index ca60b07..0846547 100644 --- a/modules/graphical/xfce.nix +++ b/modules/graphical/xfce.nix @@ -1,4 +1,4 @@ -{lib, config, pkgs, ...}: +{ lib, config, pkgs, ... }: with lib; let cfg = config.custom.graphical.xfce; @@ -7,10 +7,10 @@ in options.custom.graphical.xfce = { enable = mkEnableOption "Enables lxqt"; }; - + config = mkIf cfg.enable { services.xserver = { - xkb.layout = config.mainUser.layout; + xkb.layout = config.mainUser.layout; xkb.variant = config.mainUser.variant; enable = true; desktopManager.xfce.enable = true; diff --git a/modules/hardware/firmware.nix b/modules/hardware/firmware.nix index 1f1bf87..fe84d2b 100644 --- a/modules/hardware/firmware.nix +++ b/modules/hardware/firmware.nix @@ -1,4 +1,4 @@ -{config, lib, ...}: +{ config, lib, ... }: with lib; let cfg = config.custom.hardware.firmware; @@ -7,7 +7,7 @@ in options.custom.hardware.firmware = { enable = mkEnableOption "Enables firmware"; }; - + config = mkIf cfg.enable { services.fwupd.enable = true; }; diff --git a/modules/hardware/nvidia.nix b/modules/hardware/nvidia.nix index 0263516..400752e 100644 --- a/modules/hardware/nvidia.nix +++ b/modules/hardware/nvidia.nix @@ -28,94 +28,97 @@ in { }; }; - config = let - # the option was renamed in unstable - nvidiaOption = if (pkgsVersion == inputs.nixpkgs-unstable) then { - hardware.graphics = { - enable = true; - enable32Bit = true; - extraPackages = with pkgs; [ nvidia-vaapi-driver ]; - }; - } else { - hardware.opengl = { - enable = true; - driSupport = true; - driSupport32Bit = true; - }; - }; - nvidia_oc = "${pkgs.nvidia_oc}/bin/nvidia_oc"; - in lib.mkIf cfg.enable (lib.recursiveUpdate nvidiaOption { - boot.kernelParams = - [ "nvidia-drm.fbdev=1" "nvidia.NVreg_PreserveVideoMemoryAllocations=1" ]; - services.xserver.videoDrivers = [ "nvidia" ]; - services.xserver.deviceSection = '' - Option "Coolbits" "24" - ''; - hardware.nvidia = { - # Modesetting is required. - modesetting.enable = true; - # Open drivers with gsp stutters in VR - https://github.com/ValveSoftware/SteamVR-for-Linux/issues/631 - gsp.enable = config.hardware.nvidia.open; - # Nvidia power management. Experimental, and can cause sleep/suspend to fail. - powerManagement.enable = false; - # Fine-grained power management. Turns off GPU when not in use. - # Experimental and only works on modern Nvidia GPUs (Turing or newer). - powerManagement.finegrained = false; - # Use the NVidia open source kernel module (not to be confused with the - # independent third-party "nouveau" open source driver). - # Support is limited to the Turing and later architectures. Full list of - # supported GPUs is at: - # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus - # Only available from driver 515.43.04+ - # GSP must be enabled for this to work. - open = false; - # Enable the Nvidia settings menu, - # accessible via `nvidia-settings`. - nvidiaSettings = true; - # Optionally, you may need to select the appropriate driver version for your specific GPU. + config = + let + # the option was renamed in unstable + nvidiaOption = + if (pkgsVersion == inputs.nixpkgs-unstable) then { + hardware.graphics = { + enable = true; + enable32Bit = true; + extraPackages = with pkgs; [ nvidia-vaapi-driver ]; + }; + } else { + hardware.opengl = { + enable = true; + driSupport = true; + driSupport32Bit = true; + }; + }; + nvidia_oc = "${pkgs.nvidia_oc}/bin/nvidia_oc"; + in + lib.mkIf cfg.enable (lib.recursiveUpdate nvidiaOption { + boot.kernelParams = + [ "nvidia-drm.fbdev=1" "nvidia.NVreg_PreserveVideoMemoryAllocations=1" ]; + services.xserver.videoDrivers = [ "nvidia" ]; + services.xserver.deviceSection = '' + Option "Coolbits" "24" + ''; + hardware.nvidia = { + # Modesetting is required. + modesetting.enable = true; + # Open drivers with gsp stutters in VR - https://github.com/ValveSoftware/SteamVR-for-Linux/issues/631 + gsp.enable = config.hardware.nvidia.open; + # Nvidia power management. Experimental, and can cause sleep/suspend to fail. + powerManagement.enable = false; + # Fine-grained power management. Turns off GPU when not in use. + # Experimental and only works on modern Nvidia GPUs (Turing or newer). + powerManagement.finegrained = false; + # Use the NVidia open source kernel module (not to be confused with the + # independent third-party "nouveau" open source driver). + # Support is limited to the Turing and later architectures. Full list of + # supported GPUs is at: + # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus + # Only available from driver 515.43.04+ + # GSP must be enabled for this to work. + open = false; + # Enable the Nvidia settings menu, + # accessible via `nvidia-settings`. + nvidiaSettings = true; + # Optionally, you may need to select the appropriate driver version for your specific GPU. #package = config.boot.kernelPackages.nvidiaPackages.beta; - package = config.boot.kernelPackages.nvidiaPackages.mkDriver { - version = "570.124.04"; - sha256_64bit = "sha256-G3hqS3Ei18QhbFiuQAdoik93jBlsFI2RkWOBXuENU8Q="; - sha256_aarch64 = ""; - openSha256 = ""; - settingsSha256 = "sha256-LNL0J/sYHD8vagkV1w8tb52gMtzj/F0QmJTV1cMaso8="; - persistencedSha256 = ""; + package = config.boot.kernelPackages.nvidiaPackages.mkDriver { + version = "570.124.04"; + sha256_64bit = "sha256-G3hqS3Ei18QhbFiuQAdoik93jBlsFI2RkWOBXuENU8Q="; + sha256_aarch64 = ""; + openSha256 = ""; + settingsSha256 = "sha256-LNL0J/sYHD8vagkV1w8tb52gMtzj/F0QmJTV1cMaso8="; + persistencedSha256 = ""; + }; }; - }; - environment.systemPackages = with pkgs; [ - vaapiVdpau - libvdpau-va-gl - libva - libva-utils - pkgs.nvidia_oc - (gwe.override { nvidia_x11 = config.hardware.nvidia.package; }) - ]; + environment.systemPackages = with pkgs; [ + vaapiVdpau + libvdpau-va-gl + libva + libva-utils + pkgs.nvidia_oc + (gwe.override { nvidia_x11 = config.hardware.nvidia.package; }) + ]; - environment.sessionVariables = { - # for firefox, see https://github.com/elFarto/nvidia-vaapi-driver/#firefox - MOZ_DISABLE_RDD_SANDBOX = "1"; - LIBVA_DRIVER_NAME = "nvidia"; - }; + environment.sessionVariables = { + # for firefox, see https://github.com/elFarto/nvidia-vaapi-driver/#firefox + MOZ_DISABLE_RDD_SANDBOX = "1"; + LIBVA_DRIVER_NAME = "nvidia"; + }; - systemd.services.nvidiaSetPower = lib.mkIf cfg.powerLimit.enable { - description = - "Increase GPU power limit to ${toString cfg.powerLimit.wattage} watts"; - script = "/run/current-system/sw/bin/nvidia-smi -pl=${ + systemd.services.nvidiaSetPower = lib.mkIf cfg.powerLimit.enable { + description = + "Increase GPU power limit to ${toString cfg.powerLimit.wattage} watts"; + script = "/run/current-system/sw/bin/nvidia-smi -pl=${ toString cfg.powerLimit.wattage }"; - wantedBy = [ "multi-user.target" ]; - }; - systemd.services.nvidiaSetClocks = lib.mkIf cfg.clock.enable { - description = "Set GPU clocks"; - script = - "${nvidia_oc} set -i 0 --min-clock ${toString cfg.clock.min} --max-clock ${ + wantedBy = [ "multi-user.target" ]; + }; + systemd.services.nvidiaSetClocks = lib.mkIf cfg.clock.enable { + description = "Set GPU clocks"; + script = + "${nvidia_oc} set -i 0 --min-clock ${toString cfg.clock.min} --max-clock ${ toString cfg.clock.max } --freq-offset ${toString cfg.clock.offset}"; - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - }; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + }; - }); + }); } diff --git a/modules/hardware/scheduler.nix b/modules/hardware/scheduler.nix index 5d65623..64817dc 100644 --- a/modules/hardware/scheduler.nix +++ b/modules/hardware/scheduler.nix @@ -1,19 +1,19 @@ -{config, lib, ...}: +{ config, lib, ... }: with lib; let - cfg = config.custom.hardware.scheduler; + cfg = config.custom.hardware.scheduler; in { - options.custom.hardware.scheduler = { - enable = mkEnableOption "Enables scheduler"; - }; - - config = mkIf cfg.enable { - services.system76-scheduler = { - enable = true; - }; - - hardware.system76.enableAll = true; + options.custom.hardware.scheduler = { + enable = mkEnableOption "Enables scheduler"; + }; + + config = mkIf cfg.enable { + services.system76-scheduler = { + enable = true; }; + + hardware.system76.enableAll = true; + }; } diff --git a/modules/hardware/ssd.nix b/modules/hardware/ssd.nix index da8888c..2943bc8 100644 --- a/modules/hardware/ssd.nix +++ b/modules/hardware/ssd.nix @@ -1,15 +1,15 @@ -{config, lib, ...}: +{ config, lib, ... }: with lib; let - cfg = config.custom.hardware.ssd; + cfg = config.custom.hardware.ssd; in { - options.custom.hardware.ssd = { - enable = mkEnableOption "Enables fstrim"; - }; - - config = mkIf cfg.enable { - services.fstrim.enable = true; - }; + options.custom.hardware.ssd = { + enable = mkEnableOption "Enables fstrim"; + }; + + config = mkIf cfg.enable { + services.fstrim.enable = true; + }; } diff --git a/modules/hardware/vfio.nix b/modules/hardware/vfio.nix index 8966ea7..d578a54 100644 --- a/modules/hardware/vfio.nix +++ b/modules/hardware/vfio.nix @@ -7,7 +7,7 @@ in options.custom.hardware.vfio = { enable = mkEnableOption "Enables vfio"; }; - + config = mkIf (cfg.enable && config.virtualisation.libvirtd.enable) { boot.kernelParams = [ "amd_iommu=on" "iommu=pt" ]; }; diff --git a/modules/hardware/wooting.nix b/modules/hardware/wooting.nix index 07da869..3aded60 100644 --- a/modules/hardware/wooting.nix +++ b/modules/hardware/wooting.nix @@ -1,40 +1,42 @@ -{ config, pkgs, lib, ...}: +{ config, pkgs, lib, ... }: with lib; -let +let cfg = config.custom.hardware.wooting; in -{ +{ options.custom.hardware.wooting = { enable = mkEnableOption "Enable wooting hardware support"; }; - config = let - wooting-udev = pkgs.stdenv.mkDerivation rec { - pname = "wooting-udev-rules"; - version = "unstable-2023-03-31"; + config = + let + wooting-udev = pkgs.stdenv.mkDerivation rec { + pname = "wooting-udev-rules"; + version = "unstable-2023-03-31"; - # Source: https://help.wooting.io/en/article/wootility-configuring-device-access-for-wootility-under-linux-udev-rules-r6lb2o/ - src = [ ./wooting.rules ]; + # Source: https://help.wooting.io/en/article/wootility-configuring-device-access-for-wootility-under-linux-udev-rules-r6lb2o/ + src = [ ./wooting.rules ]; - dontUnpack = true; + dontUnpack = true; - installPhase = '' - install -Dpm644 $src $out/lib/udev/rules.d/70-wooting.rules - ''; + installPhase = '' + install -Dpm644 $src $out/lib/udev/rules.d/70-wooting.rules + ''; - meta = with lib; { - homepage = "https://help.wooting.io/en/article/wootility-configuring-device-access-for-wootility-under-linux-udev-rules-r6lb2o/"; - description = "udev rules that give NixOS permission to communicate with Wooting keyboards"; - platforms = platforms.linux; - license = "unknown"; - maintainers = with maintainers; [ davidtwco ]; + meta = with lib; { + homepage = "https://help.wooting.io/en/article/wootility-configuring-device-access-for-wootility-under-linux-udev-rules-r6lb2o/"; + description = "udev rules that give NixOS permission to communicate with Wooting keyboards"; + platforms = platforms.linux; + license = "unknown"; + maintainers = with maintainers; [ davidtwco ]; + }; }; - }; - in mkIf cfg.enable { - services.udev.packages = [ wooting-udev ]; + in + mkIf cfg.enable { + services.udev.packages = [ wooting-udev ]; - environment.systemPackages = with pkgs; [ - wootility - ]; - }; + environment.systemPackages = with pkgs; [ + wootility + ]; + }; } diff --git a/modules/hdd-spindown.nix b/modules/hdd-spindown.nix index a7bba6a..933109c 100644 --- a/modules/hdd-spindown.nix +++ b/modules/hdd-spindown.nix @@ -1,7 +1,7 @@ -{ pkgs, ...}: +{ pkgs, ... }: { - powerManagement.powerUpCommands = '' - ${pkgs.hdparm}/sbin/hdparm -B 127 /dev/sd[ab] - ${pkgs.hdparm}/sbin/hdparm -S 120 /dev/sd[ab] - ''; + powerManagement.powerUpCommands = '' + ${pkgs.hdparm}/sbin/hdparm -B 127 /dev/sd[ab] + ${pkgs.hdparm}/sbin/hdparm -S 120 /dev/sd[ab] + ''; } diff --git a/modules/kernel.nix b/modules/kernel.nix index 145006b..c1a56d1 100644 --- a/modules/kernel.nix +++ b/modules/kernel.nix @@ -1,53 +1,54 @@ { pkgs, config, ... }: let -#amdgpu_module_pkg = -# { pkgs, lib, fetchurl, kernel ? pkgs.linuxPackages_latest.kernel, ... }: -# -# pkgs.stdenv.mkDerivation { -# pname = "amdgpu-kernel-module"; -# inherit (kernel) version postPatch nativeBuildInputs; -# src = fetchurl { -# url = -# "https://gitlab.freedesktop.org/agd5f/linux/-/archive/amd-drm-next-6.15-2025-03-14/linux-amd-drm-next-6.15-2025-03-14.tar.gz"; -# # After the first build attempt, look for "hash mismatch" and then 2 lines below at the "got:" line. -# # Use "sha256-....." value here. -# hash = "sha256-/9EvJNBSKteXljrZzmaQkbZ7o4etCe0yFM3JJg/jD7o="; -# }; -# -# kernel_dev = kernel.dev; -# kernelVersion = kernel.modDirVersion; -# -# modulePath = "drivers/gpu/drm/amd/amdgpu"; -# -# buildPhase = '' -# BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build -# -# cp $BUILT_KERNEL/Module.symvers . -# cp $BUILT_KERNEL/.config . -# cp $kernel_dev/vmlinux . -# -# make "-j$NIX_BUILD_CORES" modules_prepare -# make "-j$NIX_BUILD_CORES" M=$modulePath modules -# ''; -# -# installPhase = '' -# make \ -# INSTALL_MOD_PATH="$out" \ -# XZ="xz -T$NIX_BUILD_CORES" \ -# M="$modulePath" \ -# modules_install -# ''; -# -# meta = { -# description = "AMD GPU kernel module"; -# license = lib.licenses.gpl3; -# }; -# }; -# amdgpu_module = pkgs.callPackage amdgpu_module_pkg { -# kernel = config.boot.kernelPackages.kernel; -# }; + #amdgpu_module_pkg = + # { pkgs, lib, fetchurl, kernel ? pkgs.linuxPackages_latest.kernel, ... }: + # + # pkgs.stdenv.mkDerivation { + # pname = "amdgpu-kernel-module"; + # inherit (kernel) version postPatch nativeBuildInputs; + # src = fetchurl { + # url = + # "https://gitlab.freedesktop.org/agd5f/linux/-/archive/amd-drm-next-6.15-2025-03-14/linux-amd-drm-next-6.15-2025-03-14.tar.gz"; + # # After the first build attempt, look for "hash mismatch" and then 2 lines below at the "got:" line. + # # Use "sha256-....." value here. + # hash = "sha256-/9EvJNBSKteXljrZzmaQkbZ7o4etCe0yFM3JJg/jD7o="; + # }; + # + # kernel_dev = kernel.dev; + # kernelVersion = kernel.modDirVersion; + # + # modulePath = "drivers/gpu/drm/amd/amdgpu"; + # + # buildPhase = '' + # BUILT_KERNEL=$kernel_dev/lib/modules/$kernelVersion/build + # + # cp $BUILT_KERNEL/Module.symvers . + # cp $BUILT_KERNEL/.config . + # cp $kernel_dev/vmlinux . + # + # make "-j$NIX_BUILD_CORES" modules_prepare + # make "-j$NIX_BUILD_CORES" M=$modulePath modules + # ''; + # + # installPhase = '' + # make \ + # INSTALL_MOD_PATH="$out" \ + # XZ="xz -T$NIX_BUILD_CORES" \ + # M="$modulePath" \ + # modules_install + # ''; + # + # meta = { + # description = "AMD GPU kernel module"; + # license = lib.licenses.gpl3; + # }; + # }; + # amdgpu_module = pkgs.callPackage amdgpu_module_pkg { + # kernel = config.boot.kernelPackages.kernel; + # }; -in { +in +{ #boot.extraModulePackages = [ amdgpu_module ]; #boot.kernelPackages = pkgs.linuxPackages_latest; #boot.kernelPackages = pkgs.linuxPackages_testing; @@ -62,24 +63,26 @@ in { # }; #}); - boot.kernelPackages = let - amd_drm_next_pkg = { fetchurl, buildLinux, ... }@args: + boot.kernelPackages = + let + amd_drm_next_pkg = { fetchurl, buildLinux, ... }@args: - buildLinux (args // rec { - version = "6.14.0-rc4"; - modDirVersion = version; + buildLinux (args // rec { + version = "6.14.0-rc4"; + modDirVersion = version; - src = fetchurl { - url = - "https://gitlab.freedesktop.org/agd5f/linux/-/archive/amd-drm-next-6.15-2025-03-14/linux-amd-drm-next-6.15-2025-03-14.tar.gz"; - # After the first build attempt, look for "hash mismatch" and then 2 lines below at the "got:" line. - # Use "sha256-....." value here. - hash = "sha256-/9EvJNBSKteXljrZzmaQkbZ7o4etCe0yFM3JJg/jD7o="; - }; - kernelPatches = [ ]; + src = fetchurl { + url = + "https://gitlab.freedesktop.org/agd5f/linux/-/archive/amd-drm-next-6.15-2025-03-14/linux-amd-drm-next-6.15-2025-03-14.tar.gz"; + # After the first build attempt, look for "hash mismatch" and then 2 lines below at the "got:" line. + # Use "sha256-....." value here. + hash = "sha256-/9EvJNBSKteXljrZzmaQkbZ7o4etCe0yFM3JJg/jD7o="; + }; + kernelPatches = [ ]; - extraMeta.branch = "6.14.0-rc4"; - } // (args.argsOverride or { })); - linux_amd_drm_next = pkgs.callPackage amd_drm_next_pkg { }; - in pkgs.recurseIntoAttrs (pkgs.linuxPackagesFor linux_amd_drm_next); + extraMeta.branch = "6.14.0-rc4"; + } // (args.argsOverride or { })); + linux_amd_drm_next = pkgs.callPackage amd_drm_next_pkg { }; + in + pkgs.recurseIntoAttrs (pkgs.linuxPackagesFor linux_amd_drm_next); } diff --git a/modules/logging.nix b/modules/logging.nix index fff02f6..0ebe225 100644 --- a/modules/logging.nix +++ b/modules/logging.nix @@ -1,3 +1,3 @@ { - services.journald.extraConfig = "SystemMaxUse=4G"; + services.journald.extraConfig = "SystemMaxUse=4G"; } diff --git a/modules/misc/backup.nix b/modules/misc/backup.nix index 67dea4a..980bc11 100644 --- a/modules/misc/backup.nix +++ b/modules/misc/backup.nix @@ -4,75 +4,77 @@ let cfg = config.custom.misc.backup; in { - options.custom.misc.backup = { - enable = mkEnableOption "Enables backup"; - small = lib.mkOption { - type = types.listOf types.str; - description = "paths to include in the small backup"; - }; - medium = lib.mkOption { - type = types.listOf types.str; - default = cfg.small; - description = "paths to include in the medium backup"; - }; - large = lib.mkOption { - type = types.listOf types.str; - default = cfg.small // cfg.medium; - description = "paths to include in the large backup"; - }; - excludePaths = lib.mkOption { - type = types.listOf types.str; - default = [ "**/Cache" "**/.cache" "**/__pycache__" "**/node_modules" "**/venv" "*.o" "*.out"]; - description = "paths to exclude from the backup"; - }; - excludePathsRemote = lib.mkOption { - type = types.listOf types.str; - default = cfg.excludePaths ++ [ "**/dont_remotebackup"]; - description = "paths to exclude from the remote backup"; - }; - }; - - config = let - checkStorageSpace = pkgs.writeShellApplication { - name = "checkBackupStorageSpace"; - text = '' - # Check how much space is used by the backup paths - echo "Checking storage space (small) with excluded paths..." - du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePaths)} ${builtins.concatStringsSep " " cfg.small} - echo "Checking storage space (small) with excluded paths (remote)..." - du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePathsRemote)} ${builtins.concatStringsSep " " cfg.small} - echo "Checking storage space (medium) with excluded paths..." - du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePaths)} ${builtins.concatStringsSep " " cfg.medium} - echo "Checking storage space (medium) with excluded paths (remote)..." - du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePathsRemote)} ${builtins.concatStringsSep " " cfg.medium} - echo "Checking storage space (full) with excluded paths..." - du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePaths)} ${builtins.concatStringsSep " " cfg.large} - echo "Checking storage space (full) with excluded paths (remote)..." - du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePathsRemote)} ${builtins.concatStringsSep " " cfg.large} - ''; + options.custom.misc.backup = { + enable = mkEnableOption "Enables backup"; + small = lib.mkOption { + type = types.listOf types.str; + description = "paths to include in the small backup"; + }; + medium = lib.mkOption { + type = types.listOf types.str; + default = cfg.small; + description = "paths to include in the medium backup"; + }; + large = lib.mkOption { + type = types.listOf types.str; + default = cfg.small // cfg.medium; + description = "paths to include in the large backup"; + }; + excludePaths = lib.mkOption { + type = types.listOf types.str; + default = [ "**/Cache" "**/.cache" "**/__pycache__" "**/node_modules" "**/venv" "*.o" "*.out" ]; + description = "paths to exclude from the backup"; + }; + excludePathsRemote = lib.mkOption { + type = types.listOf types.str; + default = cfg.excludePaths ++ [ "**/dont_remotebackup" ]; + description = "paths to exclude from the remote backup"; }; -in mkIf cfg.enable { - environment.systemPackages = with pkgs; [ checkStorageSpace ]; - age.secrets.restic-pw = { - file = ../../secrets/restic-pw.age; }; - age.secrets.restic-s3 = { - file = ../../secrets/restic-s3.age; - }; - age.secrets.restic-gdrive = { - file = ../../secrets/restic-gdrive.age; - }; - services.restic = { - backups = { - #localbackup = { - # initialize = true; - # passwordFile = config.age.secrets.restic-pw.path; - # exclude = cfg.excludePaths; - # paths = cfg.large; - # pruneOpts = [ "--keep-daily 7" "--keep-weekly 3" "--keep-monthly 3" "--keep-yearly 3" ]; - # repository = "/mnt/2tb/restic"; - #}; - localbackup-1tb-ssd = { + + config = + let + checkStorageSpace = pkgs.writeShellApplication { + name = "checkBackupStorageSpace"; + text = '' + # Check how much space is used by the backup paths + echo "Checking storage space (small) with excluded paths..." + du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePaths)} ${builtins.concatStringsSep " " cfg.small} + echo "Checking storage space (small) with excluded paths (remote)..." + du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePathsRemote)} ${builtins.concatStringsSep " " cfg.small} + echo "Checking storage space (medium) with excluded paths..." + du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePaths)} ${builtins.concatStringsSep " " cfg.medium} + echo "Checking storage space (medium) with excluded paths (remote)..." + du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePathsRemote)} ${builtins.concatStringsSep " " cfg.medium} + echo "Checking storage space (full) with excluded paths..." + du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePaths)} ${builtins.concatStringsSep " " cfg.large} + echo "Checking storage space (full) with excluded paths (remote)..." + du -sch ${builtins.concatStringsSep " " (map (x: "--exclude=" + x) cfg.excludePathsRemote)} ${builtins.concatStringsSep " " cfg.large} + ''; + }; + in + mkIf cfg.enable { + environment.systemPackages = with pkgs; [ checkStorageSpace ]; + age.secrets.restic-pw = { + file = ../../secrets/restic-pw.age; + }; + age.secrets.restic-s3 = { + file = ../../secrets/restic-s3.age; + }; + age.secrets.restic-gdrive = { + file = ../../secrets/restic-gdrive.age; + }; + services.restic = { + backups = { + #localbackup = { + # initialize = true; + # passwordFile = config.age.secrets.restic-pw.path; + # exclude = cfg.excludePaths; + # paths = cfg.large; + # pruneOpts = [ "--keep-daily 7" "--keep-weekly 3" "--keep-monthly 3" "--keep-yearly 3" ]; + # repository = "/mnt/2tb/restic"; + #}; + localbackup-1tb-ssd = { initialize = true; passwordFile = config.age.secrets.restic-pw.path; exclude = cfg.excludePaths; @@ -83,33 +85,33 @@ in mkIf cfg.enable { }; pruneOpts = [ "--keep-daily 7" "--keep-weekly 3" "--keep-monthly 3" "--keep-yearly 3" ]; repository = "/1tbssd/restic"; - }; - #localbackup-1tb = { - # initialize = true; - # passwordFile = config.age.secrets.restic-pw.path; - # exclude = cfg.excludePaths; - # paths = cfg.large; - # repository = "/mnt/1tb/restic"; - # pruneOpts = [ "--keep-daily 5" "--keep-weekly 3" "--keep-monthly 3" "--keep-yearly 3" ]; - # timerConfig = { - # OnCalendar = "*-*-03,06,09,12,15,18,21,24,27,30 02:00:00"; - # Persistent = true; - # }; - #}; - remotebackup-gdrive = { + }; + #localbackup-1tb = { + # initialize = true; + # passwordFile = config.age.secrets.restic-pw.path; + # exclude = cfg.excludePaths; + # paths = cfg.large; + # repository = "/mnt/1tb/restic"; + # pruneOpts = [ "--keep-daily 5" "--keep-weekly 3" "--keep-monthly 3" "--keep-yearly 3" ]; + # timerConfig = { + # OnCalendar = "*-*-03,06,09,12,15,18,21,24,27,30 02:00:00"; + # Persistent = true; + # }; + #}; + remotebackup-gdrive = { initialize = true; passwordFile = config.age.secrets.restic-pw.path; exclude = cfg.excludePathsRemote; paths = cfg.medium; - rcloneConfigFile = config.age.secrets.restic-gdrive.path; + rcloneConfigFile = config.age.secrets.restic-gdrive.path; repository = "rclone:it-experts:backup"; pruneOpts = [ "--keep-daily 5" "--keep-weekly 3" "--keep-monthly 3" "--keep-yearly 3" ]; timerConfig = { - OnCalendar = "*-*-03,06,09,12,15,18,21,24,27,30 02:00:00"; - Persistent = true; + OnCalendar = "*-*-03,06,09,12,15,18,21,24,27,30 02:00:00"; + Persistent = true; }; - }; - remotebackup = { + }; + remotebackup = { initialize = true; passwordFile = config.age.secrets.restic-pw.path; environmentFile = config.age.secrets.restic-s3.path; @@ -121,8 +123,8 @@ in mkIf cfg.enable { Persistent = true; }; repository = "s3:s3.us-west-002.backblazeb2.com/kop-bucket"; + }; + }; }; }; - }; - }; } diff --git a/modules/misc/btrfs.nix b/modules/misc/btrfs.nix index c8914cd..6ad2f65 100644 --- a/modules/misc/btrfs.nix +++ b/modules/misc/btrfs.nix @@ -1,4 +1,4 @@ -{config, lib, ...}: +{ config, lib, ... }: with lib; let cfg = config.custom.misc.btrfs; @@ -7,7 +7,7 @@ in options.custom.misc.btrfs = { enable = mkEnableOption "Enables btrfs scrubbing"; }; - + config = mkIf cfg.enable { services.btrfs.autoScrub.enable = true; }; diff --git a/modules/misc/cli-tools.nix b/modules/misc/cli-tools.nix index 9d6c05a..d4002a8 100644 --- a/modules/misc/cli-tools.nix +++ b/modules/misc/cli-tools.nix @@ -4,83 +4,85 @@ let cfg = config.custom.cli-tools; in { options.custom.cli-tools = { enable = mkEnableOption "Enables cli-tools"; }; - config = let - getTotalPowerUsed = pkgs.writeShellScriptBin "total-power" '' - echo "$(sudo cat /sys/class/powercap/*/energy_uj | awk 'BEGIN { sum = 0; } { sum += $1; } END { print sum; }' "$@") / 1000000" | bc | xargs -I _ echo "_ W" - ''; - watchCurrentPowerUsed = pkgs.writeShellScriptBin "watch-current-power" '' - function getCurrentPowerUsed() { - local energy_uj=$(sudo cat $energy_path | awk 'BEGIN { sum = 0; } { sum += $1; } END { print sum; }' "$@") - echo "scale=2; $energy_uj / 1000000" | bc - } + config = + let + getTotalPowerUsed = pkgs.writeShellScriptBin "total-power" '' + echo "$(sudo cat /sys/class/powercap/*/energy_uj | awk 'BEGIN { sum = 0; } { sum += $1; } END { print sum; }' "$@") / 1000000" | bc | xargs -I _ echo "_ W" + ''; + watchCurrentPowerUsed = pkgs.writeShellScriptBin "watch-current-power" '' + function getCurrentPowerUsed() { + local energy_uj=$(sudo cat $energy_path | awk 'BEGIN { sum = 0; } { sum += $1; } END { print sum; }' "$@") + echo "scale=2; $energy_uj / 1000000" | bc + } - energy_path=$(grep package /sys/class/powercap/*/name | sed 's/name.*$/energy_uj/') - power_prev=0 - power_curr=$(getCurrentPowerUsed) - while true; do - power_prev=$power_curr - sleep 1 + energy_path=$(grep package /sys/class/powercap/*/name | sed 's/name.*$/energy_uj/') + power_prev=0 power_curr=$(getCurrentPowerUsed) - echo "scale=2; ($power_curr - $power_prev) / 1" | bc | xargs -I _ echo "_ W" - done - ''; - in mkIf cfg.enable { - environment.systemPackages = with pkgs; [ - getTotalPowerUsed - watchCurrentPowerUsed - (if lib.versionOlder lib.version "25.05" then + while true; do + power_prev=$power_curr + sleep 1 + power_curr=$(getCurrentPowerUsed) + echo "scale=2; ($power_curr - $power_prev) / 1" | bc | xargs -I _ echo "_ W" + done + ''; + in + mkIf cfg.enable { + environment.systemPackages = with pkgs; [ + getTotalPowerUsed + watchCurrentPowerUsed + (if lib.versionOlder lib.version "25.05" then + wget + else + powerjoular) # monitor power usage + fzf # fuzzy finder + bat # fancy cat + fd # nicer find + duf # nicer du + eza # nicer ls + ripgrep # faster grep + gdu wget - else - powerjoular) # monitor power usage - fzf # fuzzy finder - bat # fancy cat - fd # nicer find - duf # nicer du - eza # nicer ls - ripgrep # faster grep - gdu - wget - pciutils - rippkgs # faster nixpkgs search, init with `rippkgs-index nixpkgs && mv rippkgs-index.sqlite ~/.local/share/`; - nixos-option - btop - git - gh # github - killall - xclip - usbutils - inputs.agenix.packages."x86_64-linux".default - fastfetch - pdfgrep - glxinfo - vulkan-tools - ffmpeg - nethogs - dig - smartmontools - bc - xxd - tldr - file - unzip - lsof - lshw - screen - tmux - fatrace # monitor filesystem events - nh - nix-output-monitor # nom - nvd # nix diff, example: nvd diff /nix/var/nix/profiles/system-389-link /nix/var/nix/profiles/system-390-link - compsize - trashy # move files to trash - shell-gpt - libheif # convert heic to jpg with `heif-convert something.heic something.jpg` - imagemagick # convert images - tree - kop-newproject # creates a shell.nix and .envrc - nix-tree # show nix derivations - binwalk # show what's inside a binary - iotop - ]; - }; + pciutils + rippkgs # faster nixpkgs search, init with `rippkgs-index nixpkgs && mv rippkgs-index.sqlite ~/.local/share/`; + nixos-option + btop + git + gh # github + killall + xclip + usbutils + inputs.agenix.packages."x86_64-linux".default + fastfetch + pdfgrep + glxinfo + vulkan-tools + ffmpeg + nethogs + dig + smartmontools + bc + xxd + tldr + file + unzip + lsof + lshw + screen + tmux + fatrace # monitor filesystem events + nh + nix-output-monitor # nom + nvd # nix diff, example: nvd diff /nix/var/nix/profiles/system-389-link /nix/var/nix/profiles/system-390-link + compsize + trashy # move files to trash + shell-gpt + libheif # convert heic to jpg with `heif-convert something.heic something.jpg` + imagemagick # convert images + tree + kop-newproject # creates a shell.nix and .envrc + nix-tree # show nix derivations + binwalk # show what's inside a binary + iotop + ]; + }; } diff --git a/modules/misc/default.nix b/modules/misc/default.nix index 1f602c3..0c8cc3c 100644 --- a/modules/misc/default.nix +++ b/modules/misc/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ...}: +{ pkgs, config, ... }: { imports = [ ./packages-list.nix diff --git a/modules/misc/docker.nix b/modules/misc/docker.nix index 0119056..ef7ab31 100644 --- a/modules/misc/docker.nix +++ b/modules/misc/docker.nix @@ -11,7 +11,7 @@ in virtualisation.docker.enable = true; virtualisation.docker.daemon.settings = { ip = "127.0.0.1"; }; environment.systemPackages = with pkgs; [ - docker-compose + docker-compose ]; hardware.nvidia-container-toolkit.enable = lib.mkIf config.custom.hardware.nvidia.enable true; }; diff --git a/modules/misc/faster-boot-time.nix b/modules/misc/faster-boot-time.nix index d9e2c72..2266d81 100644 --- a/modules/misc/faster-boot-time.nix +++ b/modules/misc/faster-boot-time.nix @@ -1,4 +1,4 @@ -{ lib, pkgs, config, ... }: { +{ lib, pkgs, config, ... }: { # before: Startup finished in 18.830s (firmware) + 5.844s (loader) + 4.422s (kernel) + 7.616s (userspace) = 36.713s # after: Startup finished in 14.115s (firmware) + 789ms (loader) + 4.312s (kernel) + 5.777s (userspace) = 24.995s systemd = { diff --git a/modules/misc/nftables.nix b/modules/misc/nftables.nix index b10d052..e624adc 100644 --- a/modules/misc/nftables.nix +++ b/modules/misc/nftables.nix @@ -1,15 +1,15 @@ -{config, lib, ...}: +{ config, lib, ... }: with lib; let - cfg = config.custom.nftables; + cfg = config.custom.nftables; in { - options.custom.nftables = { - enable = mkEnableOption "Enables nftables"; - }; - - config = mkIf cfg.enable { - networking.nftables.enable = true; - }; + options.custom.nftables = { + enable = mkEnableOption "Enables nftables"; + }; + + config = mkIf cfg.enable { + networking.nftables.enable = true; + }; } diff --git a/modules/misc/packages-list.nix b/modules/misc/packages-list.nix index 27dd7a6..f14e140 100644 --- a/modules/misc/packages-list.nix +++ b/modules/misc/packages-list.nix @@ -1,8 +1,10 @@ { config, pkgs, ... }: { - environment.etc."current-system-packages".text = let - packages = builtins.map (p: "${p.name}") config.environment.systemPackages; - sortedUnique = - builtins.sort builtins.lessThan (pkgs.lib.lists.unique packages); - formatted = builtins.concatStringsSep "\n" sortedUnique; - in formatted; + environment.etc."current-system-packages".text = + let + packages = builtins.map (p: "${p.name}") config.environment.systemPackages; + sortedUnique = + builtins.sort builtins.lessThan (pkgs.lib.lists.unique packages); + formatted = builtins.concatStringsSep "\n" sortedUnique; + in + formatted; } diff --git a/modules/misc/static-ip.nix b/modules/misc/static-ip.nix index f7d52b0..8794447 100644 --- a/modules/misc/static-ip.nix +++ b/modules/misc/static-ip.nix @@ -22,27 +22,28 @@ in { description = "Default gateway"; }; }; - config = let fallback = "1.1.1.1"; - in mkIf cfg.enable { - networking = { - defaultGateway = cfg.gateway; - useDHCP = false; - nameservers = [ cfg.dns ] - ++ lib.lists.optionals (!config.services.resolved.enable) [ fallback ]; - interfaces = { - ${cfg.interface} = { - name = "eth0"; - ipv4.addresses = [{ - address = cfg.ip; - prefixLength = 24; - }]; + config = + let fallback = "1.1.1.1"; + in mkIf cfg.enable { + networking = { + defaultGateway = cfg.gateway; + useDHCP = false; + nameservers = [ cfg.dns ] + ++ lib.lists.optionals (!config.services.resolved.enable) [ fallback ]; + interfaces = { + ${cfg.interface} = { + name = "eth0"; + ipv4.addresses = [{ + address = cfg.ip; + prefixLength = 24; + }]; + }; }; }; - }; - services.resolved = lib.mkIf config.services.resolved.enable { - llmnr = "false"; - fallbackDns = [ "1.1.1.1" ]; + services.resolved = lib.mkIf config.services.resolved.enable { + llmnr = "false"; + fallbackDns = [ "1.1.1.1" ]; + }; }; - }; } diff --git a/modules/misc/tmpfs.nix b/modules/misc/tmpfs.nix index cd0ca33..f4287a1 100644 --- a/modules/misc/tmpfs.nix +++ b/modules/misc/tmpfs.nix @@ -1,15 +1,15 @@ -{config, lib, ...}: +{ config, lib, ... }: with lib; let - cfg = config.custom.tmpfs; + cfg = config.custom.tmpfs; in { - options.custom.tmpfs = { - enable = mkEnableOption "Enables tmpfs"; - }; - - config = mkIf cfg.enable { - boot.tmp.useTmpfs = true; - }; + options.custom.tmpfs = { + enable = mkEnableOption "Enables tmpfs"; + }; + + config = mkIf cfg.enable { + boot.tmp.useTmpfs = true; + }; } diff --git a/modules/misc/wireshark.nix b/modules/misc/wireshark.nix index 6e20d06..e2eda28 100644 --- a/modules/misc/wireshark.nix +++ b/modules/misc/wireshark.nix @@ -1,18 +1,18 @@ -{lib, config, pkgs, ... }: +{ lib, config, pkgs, ... }: with lib; let - cfg = config.custom.wireshark; + cfg = config.custom.wireshark; in { - options.custom.wireshark = { - enable = mkEnableOption "Enables wireshark"; - }; - - config = mkIf cfg.enable { - programs.wireshark.enable = true; - programs.wireshark.package = pkgs.wireshark; - - users.users.${config.mainUser.name}.extraGroups = [ "wireshark" ]; - }; + options.custom.wireshark = { + enable = mkEnableOption "Enables wireshark"; + }; + + config = mkIf cfg.enable { + programs.wireshark.enable = true; + programs.wireshark.package = pkgs.wireshark; + + users.users.${config.mainUser.name}.extraGroups = [ "wireshark" ]; + }; } diff --git a/modules/motd.nix b/modules/motd.nix index 413711c..e337a99 100644 --- a/modules/motd.nix +++ b/modules/motd.nix @@ -1,52 +1,52 @@ { users.motd = '' -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⣿⣿⣿⣿⣿⠟⡅⠠⢀⢠⡾⠋⠀⣀⣠⣴⠶⠛⠋⠉⢀⣀⣠⡴⠋⠁⡆⢌⠉⠙⢦⠀⠀⠈⠉⠉⠉⠓⠫⢝⡓⠦⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣄⣤⣤⣤⣤⣤⣤⣤⣴⣾⣿⢿⣻⣿⣿⣿⡿⠟⣱⠃⡄⢣⣰⣿⣗⣾⡿⠟⠉⠀⣀⠤⠒⠉⠁⣼⠋⠀⠀⢸⠀⠈⣆⠀⠀⠳⣤⣀⠀⠀⠀⠀⠀⠀⠈⠀⣀⣙⣻⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⢃⣤⣼⣦⣷⣮⣷⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠉⣠⡾⢡⠚⡤⣷⡿⣻⠟⠉⣀⣤⠞⠋⠀⠀⠀⠀⣼⢻⠀⠀⠀⠈⠀⠀⢸⡄⠀⠀⢣⠀⠉⠒⠶⣶⣿⣍⣉⣭⣡⣤⠀⠉⠛⢿⣷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡿⢠⣿⣟⣿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠚⠁⠀⢀⣴⡟⡔⣣⢹⣼⣿⠞⢁⣠⡾⠋⠀⠀⠀⠀⢀⣤⢾⠃⡏⠀⠀⠀⠀⠀⠀⠀⡇⢀⠀⠘⣦⠀⠀⠀⢄⠙⠺⣿⢿⣿⣿⣧⠀⢀⠀⠙⢮⡳⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⣧⢣⣿⣿⢾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡞⠛⠛⠛⠙⢻⠟⣀⣴⠟⠋⠀⠀⣠⡴⠊⣡⠞⠁⡟⢰⠁⠀⠀⠀⠀⠀⠀⠀⡇⢈⠆⠀⢿⡀⠀⠀⠀⠑⡀⠀⠙⠽⢿⣿⣧⠀⠣⠀⠀⠙⢶⡹⢷⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠊⠀⢹⣯⢿⣿⣻⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠀⢧⡽⠋⠀⠀⡠⠊⠁⠀⡴⠃⠀⠀⡇⠸⠀⠀⠀⠀⠀⠀⠀⠀⡜⢸⢠⠀⡘⢷⡀⠀⠀⠠⡈⠆⠀⠀⠀⠘⢿⣧⠰⠁⠀⠀⠀⠙⢮⣳⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⣷⡀⠀⠀⠀⠸⡀⡀⡰⠊⠀⠀⢀⠞⠀⠀⠀⠈⡇⠘⠀⠀⠀⠀⠀⠀⠀⠀⡇⣼⠎⠀⡅⠈⢳⡀⠀⠀⠈⠻⣄⠀⠀⠀⠸⣿⡄⢣⠀⠀⠀⠀⠈⠻⣦⡈⠑⠒⢤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⣰⣿⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠀⢀⣀⣴⣮⡿⣿⣿⣷⠀⠀⠀⠘⣿⠚⠀⠀⠀⢠⠋⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⣸⣷⡇⠀⢀⡇⠀⡀⢳⡀⠀⠀⠀⠈⠢⡀⠀⠀⣿⣧⠈⣧⠀⠀⠀⠀⠀⠙⢿⣦⡀⠀⠙⠗⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢦⣴⡿⣽⣿⣿⣿⡟⠀⠠⠤⠤⠤⣴⣶⣾⣿⡿⠟⣡⠿⣿⣿⣆⠀⠀⠀⢻⡆⠀⠀⠀⡜⢢⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⣠⡿⡻⠁⠀⣼⠃⠀⠱⡈⢇⠀⠀⠀⠀⠀⠳⡀⠀⢹⣿⠀⢻⡆⠀⠀⠀⠀⢀⠈⠻⣷⣄⠀⠀⠙⢅⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣽⣿⣿⣿⣿⣴⣶⣶⣾⣿⡿⢟⡹⣿⣯⣤⣾⣁⡀⡽⣿⣿⣄⠀⠀⠀⢿⡀⠀⡜⠀⠠⡙⠦⣄⡀⠀⣧⠀⠀⠀⠀⣀⠠⠞⢉⠜⠁⠀⢰⠏⡠⠀⠀⢱⠈⡄⠀⠀⠀⠀⠀⠘⢄⢸⣿⡀⠘⠻⡄⠀⠀⠀⠈⡄⠀⢻⣿⡻⢦⡀⠀⠑⢌⠢⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣟⣾⣿⣿⣿⠋⠈⣉⢭⡽⣟⡛⣬⠣⡗⢿⣿⡿⣿⣻⢿⣷⣿⣿⣿⣄⠀⠀⠸⣇⡸⠀⠀⠀⠈⠑⠬⣕⣢⣍⣉⠉⠉⠁⣀⣠⣴⠏⠀⠀⢠⡇⠀⠀⠀⠀⠸⣃⠸⡀⠀⠀⠀⠀⠀⠈⢚⣿⡇⠀⡀⠹⡀⠀⠀⠀⢱⠀⠀⢯⡻⣄⠈⠒⢄⡀⠱⡄⠑⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⢻⣾⣿⣿⠿⠁⠲⠟⡺⣍⠶⡡⢏⣴⣳⣽⣿⣿⣷⣭⣓⡏⡞⡽⣻⢿⣿⣦⣄⠀⢹⡁⠀⠀⠀⠀⠀⢠⠀⢩⠏⣯⠉⠛⠋⠉⡠⠊⠀⠀⣰⡟⠀⠀⠀⠀⠀⠀⠘⡀⢳⡀⠀⠀⠀⠀⠀⠀⣿⡇⠀⡇⠀⢡⡀⠀⠀⠸⡇⠀⠸⢿⣟⣦⠀⠀⠙⡆⢼⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣫⠟⠋⠁⠀⠀⠀⠰⣉⣶⡼⠶⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣽⣞⣿⣿⣿⣷⣌⣇⠀⠀⠀⠀⢠⡏⢀⡞⠀⠸⡆⠀⢀⠔⠁⠀⢠⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠇⠘⣿⡄⠀⠀⠀⠀⠀⣿⢳⠀⠇⠈⢄⠱⡀⠀⠀⢿⠀⠀⠸⡜⢿⣷⡄⠀⠈⢆⠈⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⠗⠁⠀⠀⠀⣀⡤⠖⠛⠉⠀⠀⢠⣾⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠋⠀⠀⠀⠀⡸⠀⣼⠒⢆⢀⡹⠔⠁⠀⣠⣶⠟⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢇⠹⣄⠀⠀⠀⠀⣿⠈⠀⠀⠀⠈⢦⠈⢂⠀⢸⡇⠀⠀⢣⠘⣟⣷⡀⠀⠀⠡⡀⠈⠢⡀⠑⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⠋⢀⡠⠤⠒⠉⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⠏⠀⢠⣿⡟⠀⠀⢸⠁⠀⠀⠀⠀⢀⠅⠀⡟⠀⠤⡀⠀⠀⠀⡇⣼⠃⡀⠜⠋⣀⣤⣴⠿⠋⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄⢸⠀⠹⣆⠀⠀⢠⡟⠐⠀⣆⠀⠀⠈⣷⢄⠑⢼⣗⠀⠀⠈⡄⠘⣟⣧⠀⠀⠀⠡⡀⠀⠐⠄⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡿⢋⠞⡏⢀⠴⠋⣼⠃⠀⠀⡎⠀⠀⠀⠀⠀⡜⠀⠀⡇⠠⣀⠀⠉⠐⣺⠟⡏⡻⣗⣉⣉⣀⠸⡙⡄⠀⠀⡀⢆⠈⢢⠀⠀⠀⠀⠀⠀⠀⢀⠇⠐⡀⠀⠘⡆⠀⢸⠇⠐⠀⠉⡄⠀⠀⢸⡄⠑⠤⡈⠢⢄⡀⠃⠀⠘⣿⣇⡀⠀⠀⠱⡀⠀⠈⢆⠈⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣻⢧⠏⣸⠔⠉⣠⠎⣾⠀⠀⠀⠇⠀⠀⠀⠀⣰⠁⠀⢸⠁⠀⠀⠉⠉⣸⣿⡷⠟⠛⠉⠉⠀⠈⢾⡇⠹⡄⠀⠱⠈⣦⠀⠑⡄⢀⠀⠀⠀⠀⠈⠉⠘⠗⠠⢀⣸⡄⣸⡀⠃⢠⠀⢰⠀⠀⠀⣧⠀⠀⣿⠑⠢⠬⢷⡲⠦⠼⣿⡅⠀⠀⠀⢱⠀⠀⠀⢣⢥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⢡⣏⠔⠁⠀⠴⠃⡜⢸⠀⠀⢈⠀⠀⠀⠀⢠⡟⠀⠀⢸⠀⣀⠄⠂⣁⡽⢸⡄⠀⠀⠀⠀⠀⠀⠘⣧⠀⢻⡄⠀⢣⠘⡳⣄⠀⠙⢆⠀⠀⠀⠀⠀⠀⠂⠀⠀⠈⣿⣷⠀⡀⡸⠀⠀⣆⠀⠀⢸⡀⠀⣿⠆⠀⠀⡀⠆⠀⠀⢿⣿⠀⠀⠀⠀⠆⠀⠀⠈⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢾⣇⡾⠉⠀⣠⣤⠀⡸⠀⢸⡀⠀⠠⠀⠀⠀⢀⣾⠇⠀⠀⢸⡏⠀⠀⡰⢣⠟⢸⡇⠀⠀⠀⠀⠀⠀⠀⢹⡄⠈⣿⡄⠈⣆⠁⠈⢳⣤⡀⠑⠠⣀⢀⠀⠐⠀⠀⠀⠀⢈⣧⠀⢀⠇⠀⠀⢼⠀⠀⠈⡇⠀⣿⡅⠀⠀⢧⠸⠀⠀⠈⢿⡇⠀⠀⠀⢡⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡜⢸⠋⠀⢀⣾⣿⠇⢠⠁⠀⢸⡀⠀⠐⠀⠀⢀⣾⣼⠁⠀⠀⢸⠅⢀⣼⡷⠋⠀⢸⣷⣃⣀⣀⣀⣀⠀⠀⢈⡇⠀⢳⢹⡄⠀⢃⠀⠀⢻⡛⠷⣤⣀⣉⠒⢤⣀⡀⠀⠀⡞⠸⡏⡈⢀⠤⠊⠈⡆⠀⠀⣿⠀⣿⠆⠀⠀⣾⡀⡇⢠⠀⠈⠏⢆⠀⠀⡐⠀⠀⣰⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣃⠂⢀⠔⣻⣿⡏⠀⠀⠀⠀⢸⡇⠀⠈⠀⠀⣼⣿⣿⢀⠀⠀⢸⣴⣿⡟⠁⢀⣨⣽⣿⣿⣾⣧⣍⣙⠿⠂⠀⣧⠀⡜⠈⢿⡄⢸⠀⠀⠘⡷⡄⠈⢿⣿⡿⣷⣶⣻⢟⣾⠓⣶⣷⠋⠁⠀⠀⠀⢣⠀⠀⣿⡀⢹⠇⠀⢀⠿⣇⢁⠀⡆⠀⠈⠄⠢⡴⠥⡴⠞⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠃⢠⡎⢰⣿⣿⠀⠀⠀⠀⢠⠸⣧⠀⠀⡃⢰⣿⡿⢻⡎⠀⠀⢹⠻⠃⣬⣿⣿⣿⣿⣿⣿⣿⣿⠿⢿⣿⠀⠀⣾⠀⡆⠀⠈⣯⠽⡀⠀⠀⢱⠘⣤⣿⣟⠀⠙⣿⣯⣨⠏⢩⣿⢿⡀⠀⠀⠀⠀⠸⡀⠀⢹⣧⢸⠀⠀⢸⠀⣿⢈⠀⢡⠀⠀⠘⡄⠑⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢠⣿⣆⣿⣿⡇⠀⠀⠀⠀⡘⠀⣿⢇⠀⢣⣾⣿⣿⢿⡄⠀⠀⢹⣦⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣤⡤⠈⠀⠀⣿⣰⠁⠀⠀⣾⣷⠰⠀⢀⣸⡾⠟⣇⠘⣦⣀⠘⣿⣿⣤⠋⠁⢸⣧⣀⠀⠀⠀⠀⡇⠀⢸⣿⣿⠀⢀⡇⠀⢸⡄⡀⠸⡀⠀⠀⠈⢆⠈⢷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡏⠙⣿⣿⣿⠀⠀⠀⠀⠀⡇⠀⢹⡼⡄⠘⣿⣿⡏⣀⣻⠀⠘⢿⣿⡟⠀⣴⣿⣿⣿⡿⣭⣽⣿⣿⣿⠀⠀⢰⣿⡞⠀⠀⠀⣿⠋⡆⣇⠀⠀⡇⠈⣿⣷⣿⣿⣄⡈⣿⣿⣦⠀⠀⣿⣀⠉⠀⠀⢰⣷⠀⣿⣿⡇⠀⡞⠀⠀⠈⡇⠅⠀⡇⠀⠆⠀⠈⢳⣀⠙⢭⣒⢤⣀⡀⢀⣀⣀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢀⢿⣿⣿⠀⠀⠀⠀⢠⣗⠀⠘⣇⢷⠀⢻⣿⣷⠛⢿⡆⠀⠸⣿⠁⠀⣿⣿⣿⣿⣷⢯⣿⣿⣿⡏⠀⠀⢸⡿⠁⠀⠀⣰⡟⠀⣷⢹⠀⠀⡇⠀⣿⣿⣿⡿⣽⣷⣯⣿⣿⣄⠀⢹⣋⠀⠀⠀⢸⣿⡄⢿⣿⠁⡰⠁⢀⠀⠀⡇⡄⠀⢱⠀⠐⡀⠀⠈⠍⠢⢌⡙⠚⠭⠥⠾⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠄⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣹⢻⣿⣿⠀⠀⠀⠀⢠⡛⠀⠀⠹⣾⣧⡀⢿⣿⣇⠀⣿⡀⠀⠻⡃⠀⠸⠿⣿⣏⠋⠛⢫⣽⡿⠁⠀⣠⠟⠁⠀⠀⣠⠟⠀⠀⣿⣘⡇⠀⢡⠀⠈⣿⣎⠽⠇⣛⣻⣿⡿⠁⠑⡞⠀⠀⠀⠀⣞⣿⣧⣸⢃⡜⠀⠀⠀⠆⠀⡇⡄⠀⠘⡄⠀⠹⣄⠀⠈⢆⠀⠈⢋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠋⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠇⣸⣿⣿⠀⠀⠀⠀⠠⣇⠀⠀⠀⢹⣿⣷⡌⢿⣿⣿⣻⣷⣀⠀⠙⡶⠤⣄⣿⡾⠥⠴⠚⠛⠒⢁⡤⠋⠀⠀⣠⠜⠁⠀⠀⠀⠟⢻⣇⠀⡼⠀⠈⠙⠛⠦⠦⠬⣷⣿⣤⠴⢺⡇⠀⠀⠀⢠⣿⣿⣿⣣⣾⡇⠀⠀⠀⢃⢀⡧⡇⠀⠀⢃⠀⠀⢻⡦⠀⠀⠢⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠁⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⠀⠀⠀⠀⠀⠀⠀⣾⡇⣼⣿⣿⠀⠀⠀⠀⠐⣧⠀⠀⠀⢸⣿⣿⣿⣶⣿⣿⣿⣿⣿⣷⣄⠈⠢⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠀⠻⠼⠶⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡿⠀⠀⢀⣾⣿⣿⣯⣿⣿⣿⡇⠀⢘⠀⢨⢸⢱⠃⠀⠀⠘⡀⠀⠈⡇⠡⡀⠀⢃⠀⠀⠁⠀⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⢰⢫⡇⢹⡿⣿⣇⠀⠀⠀⠀⣿⡀⠀⠀⢸⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⡮⢿⣲⣬⣑⠢⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣟⠥⢶⣾⣿⣾⣿⣿⣿⣿⣿⣿⡇⠀⢸⠀⢸⣞⠎⠀⠀⠀⠀⡇⠀⠀⡅⠀⠱⡀⠈⢆⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⢸⡀⣷⣸⡇⢹⣿⡀⠀⠀⠀⠸⣧⡆⠀⠘⣿⣿⡿⣿⣾⣟⡿⣿⣿⣿⣷⠈⠒⠉⠉⠛⠛⠛⠒⠀⠀⠀⢯⠉⠑⠒⠒⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠤⠾⠭⠔⠂⣼⣿⣿⣿⣿⣿⣿⣿⡿⣽⠀⢀⡏⠀⣼⠋⠀⠀⠀⢀⠀⠰⠀⠀⠀⠀⠀⠑⡀⠈⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢄⡀⠀⠘⡆⠀⠀⠀⠀⠀⢳⣯⣿⣽⠀⢿⣿⠀⠀⠀⠀⢿⣻⠀⠀⢹⣿⢿⣿⣻⣿⣿⣿⣿⢿⣿⣆⠙⠢⠤⠀⠀⠀⠀⠀⠀⠀⠈⠳⡀⠀⠀⠀⠈⠳⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⡿⣿⣿⣼⠇⠀⣼⡇⠊⣸⠀⠀⠀⠀⠈⡄⠸⠀⠀⠀⠀⠀⠀⢠⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠢⡀⢡⠀⠀⠀⠀⠀⠀⠻⣾⣏⢇⠀⢙⣷⠘⡀⠀⠘⣿⣄⠄⠀⠹⣿⣿⣟⣷⣿⡾⣽⡻⣞⡿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢷⠀⠀⠀⠣⡀⠀⠈⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣟⣯⣿⣳⣿⢿⣿⣿⠏⢀⣼⣿⠁⠀⣿⠀⠀⠀⠀⠀⢡⠀⡆⠀⠀⠀⠀⠀⠀⢇⠀⣯⢀⠔⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠺⡆⠀⠀⠀⠀⠀⠀⠘⣿⠈⢄⠐⣿⣧⡘⡄⠀⠘⣯⠿⣶⣄⣈⣳⣿⣾⢯⡻⣵⢻⣬⢷⣻⡽⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⠀⠀⠀⠱⡀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣟⡷⢯⣟⣾⣿⡿⣿⣿⣃⣴⢿⣿⡿⠀⢸⡗⠀⠀⠀⠀⠀⠈⠀⢡⡄⠀⠀⠀⠀⠀⢸⢠⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠒⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠹⣧⠀⠣⠘⡌⢻⣜⣆⡀⠈⠻⣬⣉⠻⣬⣛⣿⢯⣓⢭⢻⣼⡧⣗⡯⣝⣻⣦⣄⣠⣤⣶⣶⣿⣿⣿⠿⢦⡀⠀⠀⠘⠀⠀⠀⢻⣿⣶⣶⣤⣄⣀⣀⣠⣶⡟⣯⠷⣞⡽⣻⣾⢻⡿⣿⡿⣟⣿⣽⣿⡿⠇⢠⣿⡅⠀⢀⠀⠀⠀⠀⡇⢸⠀⠀⠀⠀⠀⠀⣼⠎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⡄⠀⠀⠀⠀⠀⠀⠘⢧⡀⠀⠈⠢⡈⠻⣟⠶⣶⣶⡿⣍⣹⣾⣏⢧⡙⠆⢫⣷⣽⣷⣿⣿⡿⠿⠿⠛⠛⠋⠉⣁⣀⣤⣤⣤⣇⠀⠀⠀⠀⠀⠀⢸⠉⠉⠛⠛⠻⠿⠿⣿⣷⣿⣾⣿⣞⣋⠑⡡⠋⣼⣏⢷⣻⣿⡷⠋⠃⣰⡿⣳⠁⠀⡌⠀⠀⠀⠀⣧⠸⡀⠀⠀⠀⣀⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠢⠬⣢⣀⠀⠀⠀⠀⠀⠀⠙⠢⠤⠀⠈⠢⣘⠿⡳⣷⡹⣿⣯⠻⣟⢮⣉⢿⣿⡿⣿⣟⣿⣶⣤⣤⣴⣶⣾⣿⣿⣿⣿⣿⣿⣿⡿⢇⠀⠀⠀⡀⠀⣼⣿⣿⣿⣶⣶⣤⣤⣀⡈⠉⠙⠛⠿⣿⣿⣷⣾⣳⣾⠟⣿⣋⣀⣠⣼⣟⣿⡟⠀⢠⠃⠀⠀⠀⠀⣿⢄⠈⠑⠒⢊⣽⠥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠁⠋⠀⠉⠋⠘⠧⠛⠚⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣾⣿⣿⣿⣿⣿⡇⠀⠄⠀⠀⠁⠀⡽⣿⣯⣭⣝⣛⣛⠻⠿⢿⣿⣷⣾⣶⣤⣬⠇⠀⠈⠱⠋⠀⠀⠘⠁⢈⣈⠀⠀⠀⡞⠀⠀⠀⠀⣠⠟⢸⢀⣤⠞⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢮⣑⠦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠈⠀⠈⠀⡸⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣭⣝⣻⡟⠀⠀⠀⠀⠀⠀⠀⠀⡠⠊⣼⠋⢀⡞⠁⠀⠀⠀⣴⣯⢴⣼⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠜⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠠⠒⢈⠇⠀⠙⠳⢦⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣉⠘⣌⡙⢳⠦⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠔⠚⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠡⡀⠐⡄⠜⡡⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡗⠤⣀⠀⠀⠐⠒⠂⠉⠀⣰⠃⢠⠞⠁⠀⠀⢠⣞⡿⢡⣿⣏⡠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡴⠞⠉⠀⠀⡉⠒⠤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠂⠀⠀⠀⠀⠀⡈⠙⠥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⢾⣵⣚⠦⣝⢮⣛⡟⣶⣶⣶⠶⠦⠒⠊⠉⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⢂⠁⢠⠗⠊⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠈⠑⠒⠤⣤⣤⣴⡶⠃⡠⠃⠀⢀⣠⠞⣣⣿⠼⢻⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⡀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠘⣄⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠋⠀⠀⠀⠀⠀⡔⠁⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠻⢶⣹⣎⡯⠷⠛⠉⠉⠀⠀⠀⡀⠀⠀⠀⠀⡈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠾⣄⠞⠀⣀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⢀⣴⣿⡿⠟⣁⣴⣡⡤⣶⣾⣯⡶⠟⢉⣠⠞⠁⠀⠀⠀⠀⠀⠀⠤⣀⠀⠀⠈⠑⠠⡀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠙⡆⠀⠀⠠⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠃⠀⠀⠀⠀⠄⣊⠄⠀⠀⠀⣀⠮⠤⠤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡤⢶⣾⠉⠀⡇⠀⠀⠀⠀⠀⠀⠀⠈⠓⠌⠲⠦⣄⢣⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠁⡀⠀⠈⠒⢾⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⣠⣴⣿⣯⣽⣶⣾⠿⠛⡡⠔⢛⠀⢻⢹⠒⢦⣀⠀⠀⠀⣄⠀⠀⠀⠀⠀⠈⠙⠷⠶⠦⠤⠼⢀⠀⠀⠉⠢⣝⠢⢄⣀⡀⡀⠘⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠲⠤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠁⠀⢤⠔⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠴⡾⣿⠀⢸⠸⡀⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠲⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⣀⣠⣾⣿⣶⣄⠀⠀⠉⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠓⠒⠒⠒⠛⠛⠛⠛⠛⠋⠛⠉⠉⠁⠀⠀⡞⠀⡇⡜⠀⢸⠙⣿⠶⣄⣈⠙⠶⣤⣤⣀⣤⡠⠄⠀⠀⠀⠀⠀⠉⠒⡤⢄⡈⠦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠠⣀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠄⠀⠀⠴⠚⠉⢠⠟⠀⢹⠀⠈⡆⡇⠀⠸⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⡴⠒⠒⠒⠓⠚⠛⠿⢿⣿⣿⣿⣿⣿⣿⡿⠛⠞⠻⠿⠿⣷⣷⡀⠀⠀⠀⠙⢻⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⠀⠀⠀⠀⣸⠁⢰⢡⠇⠀⢸⠀⣺⣯⡝⡭⢷⢶⣤⡀⠣⣄⡀⠀⠀⡀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠑⠦⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⠀⠀⠀⠀⠠⠀⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⡏⠀⡇⢸⠀⠀⢳⢸⠀⠀⢷⠀⠀⠀⠀⠀⠀⠀⠀⢠⣇⡀⠀⠀⠀⠀⠀⠀⠀⠈⠳⢯⣟⣿⣿⣃⠀⠀⠀⠀⠀⠀⠀⠉⠙⠲⠄⠀⠀⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠀⠀⠀⠀⢠⡏⠀⡜⡜⠀⠀⡇⠀⡇⣿⣞⡱⣯⢷⣄⡀⠀⠘⢯⢓⠒⠚⠒⠦⣄⣀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⣠⠤⠊ -⠀⠀⠀⠀⠀⠈⠉⠙⠒⠶⠤⢤⣄⣀⠀⡀⠀⢀⠀⠀⠄⠀⠈⠁⠀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⢡⠈⡆⠀⠘⡆⡇⠀⠈⣇⠀⠀⠀⠀⠀⠀⠀⣸⠌⣷⡀⠀⠀⠄⠀⠠⠀⢀⠀⠀⢿⣿⣏⠀⠈⠉⠀⠀⠀⠀⠤⠠⠤⠀⠀⠀⠀⣿⡿⠛⠛⠛⠲⠤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⡼⠀⢠⢳⠃⠀⢠⠃⣸⠀⢸⣧⣏⢿⡌⢷⡹⣳⣄⠈⢯⠙⠦⣅⡐⠀⠀⠉⠉⠀⠈⠢⠤⠄⣀⠀⢀⢀⡀⡀⠠⠔⠒⠒⠀⠈⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⢃⠀⠘⢆⢣⠀⠀⠹⡸⡀⠀⠸⡄⠀⠀⠀⠀⠀⠀⣿⠄⡐⢻⠀⠀⠀⢀⠀⠠⠀⠀⠂⢘⣿⡿⠶⠒⠂⠉⠉⠉⠑⠒⠀⠐⣒⡶⠀⠀⢿⣳⣤⡀⠀⠀⠀⠀⠉⠑⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⡞⡏⠀⠀⡰⢰⡇⠀⢸⡏⢧⣋⢷⡈⢷⡈⠙⠛⠓⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ -⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠈⢿⡆⠀⠀⢣⢣⠀⠀⢱⡀⠀⠀⠀⠀⢀⣿⡇⣌⠃⠀⠀⠈⠀⠀⠀⠀⠁⠐⣾⡟⠀⢀⣤⣴⡶⠿⠿⠚⠒⠒⠊⠉⠀⠀⠀⢸⡄⠀⠙⠶⡀⠀⢀⠀⢀⠀⠀⠙⠲⢤⣀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⠁⠀⣠⣿⡿⠇⠀⣻⠀⠀⠀⠧⣹⢮⣳⡈⠲⠄⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ - ''; + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⣾⣿⣿⣿⣿⣿⠟⡅⠠⢀⢠⡾⠋⠀⣀⣠⣴⠶⠛⠋⠉⢀⣀⣠⡴⠋⠁⡆⢌⠉⠙⢦⠀⠀⠈⠉⠉⠉⠓⠫⢝⡓⠦⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣄⣤⣤⣤⣤⣤⣤⣤⣴⣾⣿⢿⣻⣿⣿⣿⡿⠟⣱⠃⡄⢣⣰⣿⣗⣾⡿⠟⠉⠀⣀⠤⠒⠉⠁⣼⠋⠀⠀⢸⠀⠈⣆⠀⠀⠳⣤⣀⠀⠀⠀⠀⠀⠀⠈⠀⣀⣙⣻⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⢃⣤⣼⣦⣷⣮⣷⣿⣿⣿⣿⣿⣿⣿⣿⡿⠛⠉⣠⡾⢡⠚⡤⣷⡿⣻⠟⠉⣀⣤⠞⠋⠀⠀⠀⠀⣼⢻⠀⠀⠀⠈⠀⠀⢸⡄⠀⠀⢣⠀⠉⠒⠶⣶⣿⣍⣉⣭⣡⣤⠀⠉⠛⢿⣷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡿⢠⣿⣟⣿⠿⠿⠿⠿⠿⠿⠿⠿⠿⠚⠁⠀⢀⣴⡟⡔⣣⢹⣼⣿⠞⢁⣠⡾⠋⠀⠀⠀⠀⢀⣤⢾⠃⡏⠀⠀⠀⠀⠀⠀⠀⡇⢀⠀⠘⣦⠀⠀⠀⢄⠙⠺⣿⢿⣿⣿⣧⠀⢀⠀⠙⢮⡳⣷⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⣧⢣⣿⣿⢾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡞⠛⠛⠛⠙⢻⠟⣀⣴⠟⠋⠀⠀⣠⡴⠊⣡⠞⠁⡟⢰⠁⠀⠀⠀⠀⠀⠀⠀⡇⢈⠆⠀⢿⡀⠀⠀⠀⠑⡀⠀⠙⠽⢿⣿⣧⠀⠣⠀⠀⠙⢶⡹⢷⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠊⠀⢹⣯⢿⣿⣻⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⡀⠀⠀⠀⠀⢧⡽⠋⠀⠀⡠⠊⠁⠀⡴⠃⠀⠀⡇⠸⠀⠀⠀⠀⠀⠀⠀⠀⡜⢸⢠⠀⡘⢷⡀⠀⠀⠠⡈⠆⠀⠀⠀⠘⢿⣧⠰⠁⠀⠀⠀⠙⢮⣳⢧⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⣿⣿⣿⣿⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⣷⡀⠀⠀⠀⠸⡀⡀⡰⠊⠀⠀⢀⠞⠀⠀⠀⠈⡇⠘⠀⠀⠀⠀⠀⠀⠀⠀⡇⣼⠎⠀⡅⠈⢳⡀⠀⠀⠈⠻⣄⠀⠀⠀⠸⣿⡄⢣⠀⠀⠀⠀⠈⠻⣦⡈⠑⠒⢤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⣰⣿⣿⣿⣿⣿⠟⠀⠀⠀⠀⠀⠀⢀⣀⣴⣮⡿⣿⣿⣷⠀⠀⠀⠘⣿⠚⠀⠀⠀⢠⠋⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⠀⣸⣷⡇⠀⢀⡇⠀⡀⢳⡀⠀⠀⠀⠈⠢⡀⠀⠀⣿⣧⠈⣧⠀⠀⠀⠀⠀⠙⢿⣦⡀⠀⠙⠗⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⢦⣴⡿⣽⣿⣿⣿⡟⠀⠠⠤⠤⠤⣴⣶⣾⣿⡿⠟⣡⠿⣿⣿⣆⠀⠀⠀⢻⡆⠀⠀⠀⡜⢢⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⠀⠀⣠⡿⡻⠁⠀⣼⠃⠀⠱⡈⢇⠀⠀⠀⠀⠀⠳⡀⠀⢹⣿⠀⢻⡆⠀⠀⠀⠀⢀⠈⠻⣷⣄⠀⠀⠙⢅⠢⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣽⣿⣿⣿⣿⣴⣶⣶⣾⣿⡿⢟⡹⣿⣯⣤⣾⣁⡀⡽⣿⣿⣄⠀⠀⠀⢿⡀⠀⡜⠀⠠⡙⠦⣄⡀⠀⣧⠀⠀⠀⠀⣀⠠⠞⢉⠜⠁⠀⢰⠏⡠⠀⠀⢱⠈⡄⠀⠀⠀⠀⠀⠘⢄⢸⣿⡀⠘⠻⡄⠀⠀⠀⠈⡄⠀⢻⣿⡻⢦⡀⠀⠑⢌⠢⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣟⣾⣿⣿⣿⠋⠈⣉⢭⡽⣟⡛⣬⠣⡗⢿⣿⡿⣿⣻⢿⣷⣿⣿⣿⣄⠀⠀⠸⣇⡸⠀⠀⠀⠈⠑⠬⣕⣢⣍⣉⠉⠉⠁⣀⣠⣴⠏⠀⠀⢠⡇⠀⠀⠀⠀⠸⣃⠸⡀⠀⠀⠀⠀⠀⠈⢚⣿⡇⠀⡀⠹⡀⠀⠀⠀⢱⠀⠀⢯⡻⣄⠈⠒⢄⡀⠱⡄⠑⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⢻⣾⣿⣿⠿⠁⠲⠟⡺⣍⠶⡡⢏⣴⣳⣽⣿⣿⣷⣭⣓⡏⡞⡽⣻⢿⣿⣦⣄⠀⢹⡁⠀⠀⠀⠀⠀⢠⠀⢩⠏⣯⠉⠛⠋⠉⡠⠊⠀⠀⣰⡟⠀⠀⠀⠀⠀⠀⠘⡀⢳⡀⠀⠀⠀⠀⠀⠀⣿⡇⠀⡇⠀⢡⡀⠀⠀⠸⡇⠀⠸⢿⣟⣦⠀⠀⠙⡆⢼⣦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣫⠟⠋⠁⠀⠀⠀⠰⣉⣶⡼⠶⠛⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣽⣞⣿⣿⣿⣷⣌⣇⠀⠀⠀⠀⢠⡏⢀⡞⠀⠸⡆⠀⢀⠔⠁⠀⢠⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠇⠘⣿⡄⠀⠀⠀⠀⠀⣿⢳⠀⠇⠈⢄⠱⡀⠀⠀⢿⠀⠀⠸⡜⢿⣷⡄⠀⠈⢆⠈⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⠗⠁⠀⠀⠀⣀⡤⠖⠛⠉⠀⠀⢠⣾⣿⣿⡿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠋⠀⠀⠀⠀⡸⠀⣼⠒⢆⢀⡹⠔⠁⠀⣠⣶⠟⢧⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠀⢇⠹⣄⠀⠀⠀⠀⣿⠈⠀⠀⠀⠈⢦⠈⢂⠀⢸⡇⠀⠀⢣⠘⣟⣷⡀⠀⠀⠡⡀⠈⠢⡀⠑⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⠋⢀⡠⠤⠒⠉⠀⠀⠀⠀⠀⠀⢰⣿⣿⣿⠏⠀⢠⣿⡟⠀⠀⢸⠁⠀⠀⠀⠀⢀⠅⠀⡟⠀⠤⡀⠀⠀⠀⡇⣼⠃⡀⠜⠋⣀⣤⣴⠿⠋⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠸⡄⢸⠀⠹⣆⠀⠀⢠⡟⠐⠀⣆⠀⠀⠈⣷⢄⠑⢼⣗⠀⠀⠈⡄⠘⣟⣧⠀⠀⠀⠡⡀⠀⠐⠄⠘⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢰⡿⢋⠞⡏⢀⠴⠋⣼⠃⠀⠀⡎⠀⠀⠀⠀⠀⡜⠀⠀⡇⠠⣀⠀⠉⠐⣺⠟⡏⡻⣗⣉⣉⣀⠸⡙⡄⠀⠀⡀⢆⠈⢢⠀⠀⠀⠀⠀⠀⠀⢀⠇⠐⡀⠀⠘⡆⠀⢸⠇⠐⠀⠉⡄⠀⠀⢸⡄⠑⠤⡈⠢⢄⡀⠃⠀⠘⣿⣇⡀⠀⠀⠱⡀⠀⠈⢆⠈⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣻⢧⠏⣸⠔⠉⣠⠎⣾⠀⠀⠀⠇⠀⠀⠀⠀⣰⠁⠀⢸⠁⠀⠀⠉⠉⣸⣿⡷⠟⠛⠉⠉⠀⠈⢾⡇⠹⡄⠀⠱⠈⣦⠀⠑⡄⢀⠀⠀⠀⠀⠈⠉⠘⠗⠠⢀⣸⡄⣸⡀⠃⢠⠀⢰⠀⠀⠀⣧⠀⠀⣿⠑⠢⠬⢷⡲⠦⠼⣿⡅⠀⠀⠀⢱⠀⠀⠀⢣⢥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡾⢡⣏⠔⠁⠀⠴⠃⡜⢸⠀⠀⢈⠀⠀⠀⠀⢠⡟⠀⠀⢸⠀⣀⠄⠂⣁⡽⢸⡄⠀⠀⠀⠀⠀⠀⠘⣧⠀⢻⡄⠀⢣⠘⡳⣄⠀⠙⢆⠀⠀⠀⠀⠀⠀⠂⠀⠀⠈⣿⣷⠀⡀⡸⠀⠀⣆⠀⠀⢸⡀⠀⣿⠆⠀⠀⡀⠆⠀⠀⢿⣿⠀⠀⠀⠀⠆⠀⠀⠈⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⢾⣇⡾⠉⠀⣠⣤⠀⡸⠀⢸⡀⠀⠠⠀⠀⠀⢀⣾⠇⠀⠀⢸⡏⠀⠀⡰⢣⠟⢸⡇⠀⠀⠀⠀⠀⠀⠀⢹⡄⠈⣿⡄⠈⣆⠁⠈⢳⣤⡀⠑⠠⣀⢀⠀⠐⠀⠀⠀⠀⢈⣧⠀⢀⠇⠀⠀⢼⠀⠀⠈⡇⠀⣿⡅⠀⠀⢧⠸⠀⠀⠈⢿⡇⠀⠀⠀⢡⠀⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡜⢸⠋⠀⢀⣾⣿⠇⢠⠁⠀⢸⡀⠀⠐⠀⠀⢀⣾⣼⠁⠀⠀⢸⠅⢀⣼⡷⠋⠀⢸⣷⣃⣀⣀⣀⣀⠀⠀⢈⡇⠀⢳⢹⡄⠀⢃⠀⠀⢻⡛⠷⣤⣀⣉⠒⢤⣀⡀⠀⠀⡞⠸⡏⡈⢀⠤⠊⠈⡆⠀⠀⣿⠀⣿⠆⠀⠀⣾⡀⡇⢠⠀⠈⠏⢆⠀⠀⡐⠀⠀⣰⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣃⠂⢀⠔⣻⣿⡏⠀⠀⠀⠀⢸⡇⠀⠈⠀⠀⣼⣿⣿⢀⠀⠀⢸⣴⣿⡟⠁⢀⣨⣽⣿⣿⣾⣧⣍⣙⠿⠂⠀⣧⠀⡜⠈⢿⡄⢸⠀⠀⠘⡷⡄⠈⢿⣿⡿⣷⣶⣻⢟⣾⠓⣶⣷⠋⠁⠀⠀⠀⢣⠀⠀⣿⡀⢹⠇⠀⢀⠿⣇⢁⠀⡆⠀⠈⠄⠢⡴⠥⡴⠞⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⠃⢠⡎⢰⣿⣿⠀⠀⠀⠀⢠⠸⣧⠀⠀⡃⢰⣿⡿⢻⡎⠀⠀⢹⠻⠃⣬⣿⣿⣿⣿⣿⣿⣿⣿⠿⢿⣿⠀⠀⣾⠀⡆⠀⠈⣯⠽⡀⠀⠀⢱⠘⣤⣿⣟⠀⠙⣿⣯⣨⠏⢩⣿⢿⡀⠀⠀⠀⠀⠸⡀⠀⢹⣧⢸⠀⠀⢸⠀⣿⢈⠀⢡⠀⠀⠘⡄⠑⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢠⣿⣆⣿⣿⡇⠀⠀⠀⠀⡘⠀⣿⢇⠀⢣⣾⣿⣿⢿⡄⠀⠀⢹⣦⣿⡿⠋⢻⣿⣿⣿⣿⣿⣿⣤⡤⠈⠀⠀⣿⣰⠁⠀⠀⣾⣷⠰⠀⢀⣸⡾⠟⣇⠘⣦⣀⠘⣿⣿⣤⠋⠁⢸⣧⣀⠀⠀⠀⠀⡇⠀⢸⣿⣿⠀⢀⡇⠀⢸⡄⡀⠸⡀⠀⠀⠈⢆⠈⢷⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⡏⠙⣿⣿⣿⠀⠀⠀⠀⠀⡇⠀⢹⡼⡄⠘⣿⣿⡏⣀⣻⠀⠘⢿⣿⡟⠀⣴⣿⣿⣿⡿⣭⣽⣿⣿⣿⠀⠀⢰⣿⡞⠀⠀⠀⣿⠋⡆⣇⠀⠀⡇⠈⣿⣷⣿⣿⣄⡈⣿⣿⣦⠀⠀⣿⣀⠉⠀⠀⢰⣷⠀⣿⣿⡇⠀⡞⠀⠀⠈⡇⠅⠀⡇⠀⠆⠀⠈⢳⣀⠙⢭⣒⢤⣀⡀⢀⣀⣀⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢣⢀⢿⣿⣿⠀⠀⠀⠀⢠⣗⠀⠘⣇⢷⠀⢻⣿⣷⠛⢿⡆⠀⠸⣿⠁⠀⣿⣿⣿⣿⣷⢯⣿⣿⣿⡏⠀⠀⢸⡿⠁⠀⠀⣰⡟⠀⣷⢹⠀⠀⡇⠀⣿⣿⣿⡿⣽⣷⣯⣿⣿⣄⠀⢹⣋⠀⠀⠀⢸⣿⡄⢿⣿⠁⡰⠁⢀⠀⠀⡇⡄⠀⢱⠀⠐⡀⠀⠈⠍⠢⢌⡙⠚⠭⠥⠾⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠄⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣹⢻⣿⣿⠀⠀⠀⠀⢠⡛⠀⠀⠹⣾⣧⡀⢿⣿⣇⠀⣿⡀⠀⠻⡃⠀⠸⠿⣿⣏⠋⠛⢫⣽⡿⠁⠀⣠⠟⠁⠀⠀⣠⠟⠀⠀⣿⣘⡇⠀⢡⠀⠈⣿⣎⠽⠇⣛⣻⣿⡿⠁⠑⡞⠀⠀⠀⠀⣞⣿⣧⣸⢃⡜⠀⠀⠀⠆⠀⡇⡄⠀⠘⡄⠀⠹⣄⠀⠈⢆⠀⠈⢋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠋⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠇⣸⣿⣿⠀⠀⠀⠀⠠⣇⠀⠀⠀⢹⣿⣷⡌⢿⣿⣿⣻⣷⣀⠀⠙⡶⠤⣄⣿⡾⠥⠴⠚⠛⠒⢁⡤⠋⠀⠀⣠⠜⠁⠀⠀⠀⠟⢻⣇⠀⡼⠀⠈⠙⠛⠦⠦⠬⣷⣿⣤⠴⢺⡇⠀⠀⠀⢠⣿⣿⣿⣣⣾⡇⠀⠀⠀⢃⢀⡧⡇⠀⠀⢃⠀⠀⢻⡦⠀⠀⠢⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠁⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⠀⠀⠀⠀⠀⠀⠀⣾⡇⣼⣿⣿⠀⠀⠀⠀⠐⣧⠀⠀⠀⢸⣿⣿⣿⣶⣿⣿⣿⣿⣿⣷⣄⠈⠢⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠀⠻⠼⠶⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡿⠀⠀⢀⣾⣿⣿⣯⣿⣿⣿⡇⠀⢘⠀⢨⢸⢱⠃⠀⠀⠘⡀⠀⠈⡇⠡⡀⠀⢃⠀⠀⠁⠀⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⠀⠀⠀⠀⢰⢫⡇⢹⡿⣿⣇⠀⠀⠀⠀⣿⡀⠀⠀⢸⣿⣿⣯⣿⣿⣿⣿⣿⣿⣿⡮⢿⣲⣬⣑⠢⠀⠀⠀⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣟⠥⢶⣾⣿⣾⣿⣿⣿⣿⣿⣿⡇⠀⢸⠀⢸⣞⠎⠀⠀⠀⠀⡇⠀⠀⡅⠀⠱⡀⠈⢆⠀⠀⢸⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠄⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⠀⠀⠀⠀⠀⢸⡀⣷⣸⡇⢹⣿⡀⠀⠀⠀⠸⣧⡆⠀⠘⣿⣿⡿⣿⣾⣟⡿⣿⣿⣿⣷⠈⠒⠉⠉⠛⠛⠛⠒⠀⠀⠀⢯⠉⠑⠒⠒⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠤⠾⠭⠔⠂⣼⣿⣿⣿⣿⣿⣿⣿⡿⣽⠀⢀⡏⠀⣼⠋⠀⠀⠀⢀⠀⠰⠀⠀⠀⠀⠀⠑⡀⠈⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⢄⡀⠀⠘⡆⠀⠀⠀⠀⠀⢳⣯⣿⣽⠀⢿⣿⠀⠀⠀⠀⢿⣻⠀⠀⢹⣿⢿⣿⣻⣿⣿⣿⣿⢿⣿⣆⠙⠢⠤⠀⠀⠀⠀⠀⠀⠀⠈⠳⡀⠀⠀⠀⠈⠳⠤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⡿⣿⣿⣼⠇⠀⣼⡇⠊⣸⠀⠀⠀⠀⠈⡄⠸⠀⠀⠀⠀⠀⠀⢠⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠢⡀⢡⠀⠀⠀⠀⠀⠀⠻⣾⣏⢇⠀⢙⣷⠘⡀⠀⠘⣿⣄⠄⠀⠹⣿⣿⣟⣷⣿⡾⣽⡻⣞⡿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢷⠀⠀⠀⠣⡀⠀⠈⢦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⣿⣟⣯⣿⣳⣿⢿⣿⣿⠏⢀⣼⣿⠁⠀⣿⠀⠀⠀⠀⠀⢡⠀⡆⠀⠀⠀⠀⠀⠀⢇⠀⣯⢀⠔⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠳⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠺⡆⠀⠀⠀⠀⠀⠀⠘⣿⠈⢄⠐⣿⣧⡘⡄⠀⠘⣯⠿⣶⣄⣈⣳⣿⣾⢯⡻⣵⢻⣬⢷⣻⡽⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣇⠀⠀⠀⠱⡀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣟⡷⢯⣟⣾⣿⡿⣿⣿⣃⣴⢿⣿⡿⠀⢸⡗⠀⠀⠀⠀⠀⠈⠀⢡⡄⠀⠀⠀⠀⠀⢸⢠⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠞⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠒⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠹⣧⠀⠣⠘⡌⢻⣜⣆⡀⠈⠻⣬⣉⠻⣬⣛⣿⢯⣓⢭⢻⣼⡧⣗⡯⣝⣻⣦⣄⣠⣤⣶⣶⣿⣿⣿⠿⢦⡀⠀⠀⠘⠀⠀⠀⢻⣿⣶⣶⣤⣄⣀⣀⣠⣶⡟⣯⠷⣞⡽⣻⣾⢻⡿⣿⡿⣟⣿⣽⣿⡿⠇⢠⣿⡅⠀⢀⠀⠀⠀⠀⡇⢸⠀⠀⠀⠀⠀⠀⣼⠎⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠒⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⡄⠀⠀⠀⠀⠀⠀⠘⢧⡀⠀⠈⠢⡈⠻⣟⠶⣶⣶⡿⣍⣹⣾⣏⢧⡙⠆⢫⣷⣽⣷⣿⣿⡿⠿⠿⠛⠛⠋⠉⣁⣀⣤⣤⣤⣇⠀⠀⠀⠀⠀⠀⢸⠉⠉⠛⠛⠻⠿⠿⣿⣷⣿⣾⣿⣞⣋⠑⡡⠋⣼⣏⢷⣻⣿⡷⠋⠃⣰⡿⣳⠁⠀⡌⠀⠀⠀⠀⣧⠸⡀⠀⠀⠀⣀⣾⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠐⠢⠬⣢⣀⠀⠀⠀⠀⠀⠀⠙⠢⠤⠀⠈⠢⣘⠿⡳⣷⡹⣿⣯⠻⣟⢮⣉⢿⣿⡿⣿⣟⣿⣶⣤⣤⣴⣶⣾⣿⣿⣿⣿⣿⣿⣿⡿⢇⠀⠀⠀⡀⠀⣼⣿⣿⣿⣶⣶⣤⣤⣀⡈⠉⠙⠛⠿⣿⣿⣷⣾⣳⣾⠟⣿⣋⣀⣠⣼⣟⣿⡟⠀⢠⠃⠀⠀⠀⠀⣿⢄⠈⠑⠒⢊⣽⠥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠒⠤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠳⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠉⠁⠋⠀⠉⠋⠘⠧⠛⠚⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣶⣾⣿⣿⣿⣿⣿⡇⠀⠄⠀⠀⠁⠀⡽⣿⣯⣭⣝⣛⣛⠻⠿⢿⣿⣷⣾⣶⣤⣬⠇⠀⠈⠱⠋⠀⠀⠘⠁⢈⣈⠀⠀⠀⡞⠀⠀⠀⠀⣠⠟⢸⢀⣤⠞⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢮⣑⠦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡀⠈⠀⠈⠀⡸⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⣭⣝⣻⡟⠀⠀⠀⠀⠀⠀⠀⠀⡠⠊⣼⠋⢀⡞⠁⠀⠀⠀⣴⣯⢴⣼⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠜⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠠⠒⢈⠇⠀⠙⠳⢦⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣉⠘⣌⡙⢳⠦⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠔⠚⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠡⡀⠐⡄⠜⡡⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡗⠤⣀⠀⠀⠐⠒⠂⠉⠀⣰⠃⢠⠞⠁⠀⠀⢠⣞⡿⢡⣿⣏⡠⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⡴⠞⠉⠀⠀⡉⠒⠤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⠂⠀⠀⠀⠀⠀⡈⠙⠥⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠻⢾⣵⣚⠦⣝⢮⣛⡟⣶⣶⣶⠶⠦⠒⠊⠉⠀⠀⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣟⢂⠁⢠⠗⠊⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠈⠑⠒⠤⣤⣤⣴⡶⠃⡠⠃⠀⢀⣠⠞⣣⣿⠼⢻⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⢄⡀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠘⣄⠀⠈⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠋⠀⠀⠀⠀⠀⡔⠁⠀⠀⠀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠻⢶⣹⣎⡯⠷⠛⠉⠉⠀⠀⠀⡀⠀⠀⠀⠀⡈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠾⣄⠞⠀⣀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⢀⣴⣿⡿⠟⣁⣴⣡⡤⣶⣾⣯⡶⠟⢉⣠⠞⠁⠀⠀⠀⠀⠀⠀⠤⣀⠀⠀⠈⠑⠠⡀⠀⠀⠀⠈⠢⡀⠀⠀⠀⠀⠙⡆⠀⠀⠠⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠃⠀⠀⠀⠀⠄⣊⠄⠀⠀⠀⣀⠮⠤⠤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⡤⢶⣾⠉⠀⡇⠀⠀⠀⠀⠀⠀⠀⠈⠓⠌⠲⠦⣄⢣⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⠁⡀⠀⠈⠒⢾⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⠀⣠⣴⣿⣯⣽⣶⣾⠿⠛⡡⠔⢛⠀⢻⢹⠒⢦⣀⠀⠀⠀⣄⠀⠀⠀⠀⠀⠈⠙⠷⠶⠦⠤⠼⢀⠀⠀⠉⠢⣝⠢⢄⣀⡀⡀⠘⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠲⠤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠼⠁⠀⢤⠔⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⠴⡾⣿⠀⢸⠸⡀⠀⢱⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⠲⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⣀⣠⣾⣿⣶⣄⠀⠀⠉⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠓⠒⠒⠒⠛⠛⠛⠛⠛⠋⠛⠉⠉⠁⠀⠀⡞⠀⡇⡜⠀⢸⠙⣿⠶⣄⣈⠙⠶⣤⣤⣀⣤⡠⠄⠀⠀⠀⠀⠀⠉⠒⡤⢄⡈⠦⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠠⣀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠄⠀⠀⠴⠚⠉⢠⠟⠀⢹⠀⠈⡆⡇⠀⠸⡆⠀⠀⠀⠀⠀⠀⠀⠀⠀⡴⠒⠒⠒⠓⠚⠛⠿⢿⣿⣿⣿⣿⣿⣿⡿⠛⠞⠻⠿⠿⣷⣷⡀⠀⠀⠀⠙⢻⣿⣿⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠂⠀⠀⠀⠀⣸⠁⢰⢡⠇⠀⢸⠀⣺⣯⡝⡭⢷⢶⣤⡀⠣⣄⡀⠀⠀⡀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠑⠦⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⠁⠀⠀⠀⠀⠠⠀⠀⠀⠀⠀⠀⠀⠀⡠⠞⠁⠀⡏⠀⡇⢸⠀⠀⢳⢸⠀⠀⢷⠀⠀⠀⠀⠀⠀⠀⠀⢠⣇⡀⠀⠀⠀⠀⠀⠀⠀⠈⠳⢯⣟⣿⣿⣃⠀⠀⠀⠀⠀⠀⠀⠉⠙⠲⠄⠀⠀⣿⣿⣿⣿⡿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠎⠀⠀⠀⠀⢠⡏⠀⡜⡜⠀⠀⡇⠀⡇⣿⣞⡱⣯⢷⣄⡀⠀⠘⢯⢓⠒⠚⠒⠦⣄⣀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⣠⠤⠊ + ⠀⠀⠀⠀⠀⠈⠉⠙⠒⠶⠤⢤⣄⣀⠀⡀⠀⢀⠀⠀⠄⠀⠈⠁⠀⠐⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡇⠀⢡⠈⡆⠀⠘⡆⡇⠀⠈⣇⠀⠀⠀⠀⠀⠀⠀⣸⠌⣷⡀⠀⠀⠄⠀⠠⠀⢀⠀⠀⢿⣿⣏⠀⠈⠉⠀⠀⠀⠀⠤⠠⠤⠀⠀⠀⠀⣿⡿⠛⠛⠛⠲⠤⣄⡀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⡼⠀⢠⢳⠃⠀⢠⠃⣸⠀⢸⣧⣏⢿⡌⢷⡹⣳⣄⠈⢯⠙⠦⣅⡐⠀⠀⠉⠉⠀⠈⠢⠤⠄⣀⠀⢀⢀⡀⡀⠠⠔⠒⠒⠀⠈⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡰⢃⠀⠘⢆⢣⠀⠀⠹⡸⡀⠀⠸⡄⠀⠀⠀⠀⠀⠀⣿⠄⡐⢻⠀⠀⠀⢀⠀⠠⠀⠀⠂⢘⣿⡿⠶⠒⠂⠉⠉⠉⠑⠒⠀⠐⣒⡶⠀⠀⢿⣳⣤⡀⠀⠀⠀⠀⠉⠑⠢⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⠃⠀⡞⡏⠀⠀⡰⢰⡇⠀⢸⡏⢧⣋⢷⡈⢷⡈⠙⠛⠓⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⠀⠀⠀⠀⠀⢀⠀⠀⠀⠀⠀⠀⠈⠀⠀⠈⢿⡆⠀⠀⢣⢣⠀⠀⢱⡀⠀⠀⠀⠀⢀⣿⡇⣌⠃⠀⠀⠈⠀⠀⠀⠀⠁⠐⣾⡟⠀⢀⣤⣴⡶⠿⠿⠚⠒⠒⠊⠉⠀⠀⠀⢸⡄⠀⠙⠶⡀⠀⢀⠀⢀⠀⠀⠙⠲⢤⣀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣿⠁⠀⣠⣿⡿⠇⠀⣻⠀⠀⠀⠧⣹⢮⣳⡈⠲⠄⠀⠀⠀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ + ''; } diff --git a/modules/networkmanager.nix b/modules/networkmanager.nix index 9079055..3f5fd93 100644 --- a/modules/networkmanager.nix +++ b/modules/networkmanager.nix @@ -1,5 +1,5 @@ -{pkgs, lib, ...}: +{ pkgs, lib, ... }: { - networking.networkmanager.enable = true; + networking.networkmanager.enable = true; networking.networkmanager.plugins = lib.mkForce [ pkgs.networkmanager-openvpn ]; } diff --git a/modules/nix/default.nix b/modules/nix/default.nix index 9f38fc9..48796e8 100644 --- a/modules/nix/default.nix +++ b/modules/nix/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ...}: +{ pkgs, config, ... }: { imports = [ ./index.nix diff --git a/modules/nix/ld.nix b/modules/nix/ld.nix index 596f6b3..d16328f 100644 --- a/modules/nix/ld.nix +++ b/modules/nix/ld.nix @@ -1,4 +1,4 @@ -{config, lib, pkgs, ... }: +{ config, lib, pkgs, ... }: with lib; let cfg = config.custom.nix.ld; @@ -7,7 +7,7 @@ in options.custom.nix.ld = { enable = mkEnableOption "Enables nix ld"; }; - + config = mkIf cfg.enable { programs.nix-ld.enable = true; programs.nix-ld.libraries = with pkgs; [ diff --git a/modules/nix/settings.nix b/modules/nix/settings.nix index cc833cb..2a47d1e 100644 --- a/modules/nix/settings.nix +++ b/modules/nix/settings.nix @@ -3,7 +3,8 @@ with lib; let cfg = config.custom.nix.settings; cache = "https://cache.nixos.org"; -in { +in +{ options.custom.nix.settings = { enable = mkEnableOption "Enables various nix settings"; optimise = mkOption { diff --git a/modules/no-sleep-lid-closed.nix b/modules/no-sleep-lid-closed.nix index 5baac73..75c6ce3 100644 --- a/modules/no-sleep-lid-closed.nix +++ b/modules/no-sleep-lid-closed.nix @@ -1,4 +1,3 @@ - { services.logind.lidSwitchExternalPower = "ignore"; } diff --git a/modules/services/adam-site.nix b/modules/services/adam-site.nix index 49d02c1..3c5db4d 100644 --- a/modules/services/adam-site.nix +++ b/modules/services/adam-site.nix @@ -1,4 +1,3 @@ - { config, pkgs, lib, inputs, ... }: with lib; let cfg = config.custom.services.adam-site; diff --git a/modules/services/adguard.nix b/modules/services/adguard.nix index f8a65db..961ebe7 100644 --- a/modules/services/adguard.nix +++ b/modules/services/adguard.nix @@ -19,157 +19,159 @@ in { description = "use https for the adguard instance"; }; }; - config = let - ip = cfg.ip; - wireguardIp = config.custom.services.wireguard.ip; - in lib.mkIf cfg.enable { - networking.firewall.allowedTCPPorts = [ 53 ]; - networking.firewall.allowedUDPPorts = [ 53 ]; + config = + let + ip = cfg.ip; + wireguardIp = config.custom.services.wireguard.ip; + in + lib.mkIf cfg.enable { + networking.firewall.allowedTCPPorts = [ 53 ]; + networking.firewall.allowedUDPPorts = [ 53 ]; - security.acme.certs."${cfg.fqdn}".server = - "https://127.0.0.1:8443/acme/kop-acme/directory"; - # nginx reverse proxy - services.nginx.virtualHosts.${cfg.fqdn} = { - forceSSL = cfg.useHttps; - enableACME = cfg.useHttps; - quic = cfg.useHttps; - http3 = cfg.useHttps; - locations."/" = { - proxyPass = - "http://127.0.0.1:${toString config.services.adguardhome.port}"; - proxyWebsockets = true; - }; - }; - systemd.services.adguardhome = { - after = [ "nginx.service" "step-ca.service" ]; - }; - - services.adguardhome = { - enable = true; - settings = { - schema_version = 28; - users = [{ - name = "admin"; - password = - "$2y$15$iPzjmUJPTwWUOsDp46GOPO/LYor/jDJjndwy2QlPddaKSD4QXvq9W"; - }]; - dns = { - bind_hosts = [ "127.0.0.1" ip ] ++ lib.lists.optionals config.custom.services.wireguard.enable [ wireguardIp ]; - port = 53; - protection_enabled = true; - filtering_enabled = true; - upstream_dns = [ - "https://dns10.quad9.net/dns-query" - "https://dns.adguard-dns.com/dns-query" - ]; - use_http3_upstreams = true; + security.acme.certs."${cfg.fqdn}".server = + "https://127.0.0.1:8443/acme/kop-acme/directory"; + # nginx reverse proxy + services.nginx.virtualHosts.${cfg.fqdn} = { + forceSSL = cfg.useHttps; + enableACME = cfg.useHttps; + quic = cfg.useHttps; + http3 = cfg.useHttps; + locations."/" = { + proxyPass = + "http://127.0.0.1:${toString config.services.adguardhome.port}"; + proxyWebsockets = true; }; - querylog = { enabled = false; }; - filters = [ - { - enabled = true; - url = - "https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt"; - name = "adguard dns list"; - id = 1; - } - { - enabled = true; - url = - "https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt"; - name = "adguard block list"; - id = 2; - } - { - enabled = true; - url = "https://dbl.oisd.nl/"; - name = "big block list"; - id = 3; - } - ]; - dhcp = { enabled = false; }; - tls = { enabled = false; }; - filtering = { - rewrites = [ + }; + systemd.services.adguardhome = { + after = [ "nginx.service" "step-ca.service" ]; + }; + + services.adguardhome = { + enable = true; + settings = { + schema_version = 28; + users = [{ + name = "admin"; + password = + "$2y$15$iPzjmUJPTwWUOsDp46GOPO/LYor/jDJjndwy2QlPddaKSD4QXvq9W"; + }]; + dns = { + bind_hosts = [ "127.0.0.1" ip ] ++ lib.lists.optionals config.custom.services.wireguard.enable [ wireguardIp ]; + port = 53; + protection_enabled = true; + filtering_enabled = true; + upstream_dns = [ + "https://dns10.quad9.net/dns-query" + "https://dns.adguard-dns.com/dns-query" + ]; + use_http3_upstreams = true; + }; + querylog = { enabled = false; }; + filters = [ { - "domain" = "kopatz.ddns.net"; - "answer" = ip; + enabled = true; + url = + "https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt"; + name = "adguard dns list"; + id = 1; } { - "domain" = "kop.oasch.net"; - "answer" = ip; + enabled = true; + url = + "https://adguardteam.github.io/HostlistsRegistry/assets/filter_2.txt"; + name = "adguard block list"; + id = 2; } { - "domain" = "kavita-kopatz.duckdns.org"; - "answer" = ip; + enabled = true; + url = "https://dbl.oisd.nl/"; + name = "big block list"; + id = 3; } - { - "domain" = "server.home"; - "answer" = ip; - } - { - "domain" = "server.home.arpa"; - "answer" = ip; - } - { - "domain" = "adguard.home.arpa"; - "answer" = ip; - } - { - "domain" = "nextcloud.home.arpa"; - "answer" = ip; - } - { - "domain" = "kavita.home.arpa"; - "answer" = ip; - } - { - "domain" = "grafana.home.arpa"; - "answer" = ip; - } - { - "domain" = "yt.home.arpa"; - "answer" = ip; - } - { - "domain" = "nextcloud.home.arpa"; - "answer" = wireguardIp; - } - { - "domain" = "kavita.home.arpa"; - "answer" = wireguardIp; - } - { - "domain" = "yt.home.arpa"; - "answer" = wireguardIp; - } - { - "domain" = "turnserver.home.arpa"; - "answer" = wireguardIp; - } - { - "domain" = "powerline.home.arpa"; - "answer" = "192.168.0.2"; - } - { - "domain" = "3neo.home.arpa"; - "answer" = "192.168.0.4"; - } - { - "domain" = "alcatel.home.arpa"; - "answer" = "192.168.0.5"; - } - { - "domain" = "extender.home.arpa"; - "answer" = "192.168.0.8"; - } - { - "domain" = "inverter.home.arpa"; - "answer" = "192.168.0.9"; - } ]; + dhcp = { enabled = false; }; + tls = { enabled = false; }; + filtering = { + rewrites = [ + { + "domain" = "kopatz.ddns.net"; + "answer" = ip; + } + { + "domain" = "kop.oasch.net"; + "answer" = ip; + } + { + "domain" = "kavita-kopatz.duckdns.org"; + "answer" = ip; + } + { + "domain" = "server.home"; + "answer" = ip; + } + { + "domain" = "server.home.arpa"; + "answer" = ip; + } + { + "domain" = "adguard.home.arpa"; + "answer" = ip; + } + { + "domain" = "nextcloud.home.arpa"; + "answer" = ip; + } + { + "domain" = "kavita.home.arpa"; + "answer" = ip; + } + { + "domain" = "grafana.home.arpa"; + "answer" = ip; + } + { + "domain" = "yt.home.arpa"; + "answer" = ip; + } + { + "domain" = "nextcloud.home.arpa"; + "answer" = wireguardIp; + } + { + "domain" = "kavita.home.arpa"; + "answer" = wireguardIp; + } + { + "domain" = "yt.home.arpa"; + "answer" = wireguardIp; + } + { + "domain" = "turnserver.home.arpa"; + "answer" = wireguardIp; + } + { + "domain" = "powerline.home.arpa"; + "answer" = "192.168.0.2"; + } + { + "domain" = "3neo.home.arpa"; + "answer" = "192.168.0.4"; + } + { + "domain" = "alcatel.home.arpa"; + "answer" = "192.168.0.5"; + } + { + "domain" = "extender.home.arpa"; + "answer" = "192.168.0.8"; + } + { + "domain" = "inverter.home.arpa"; + "answer" = "192.168.0.9"; + } + ]; + }; }; }; }; - }; } diff --git a/modules/services/caldav.nix b/modules/services/caldav.nix index 75db09f..d150b8a 100644 --- a/modules/services/caldav.nix +++ b/modules/services/caldav.nix @@ -28,44 +28,47 @@ in { large = [ "/var/lib/radicale/" ]; }; - systemd.services.kop-fhcalendar = let - radicale = if lib.versionOlder lib.version "25.05" then - (builtins.elemAt - config.services.radicale.settings.storage.filesystem_folder 0) - else - config.services.radicale.settings.storage.filesystem_folder; - # not reproducible - working = - "${radicale}/collection-root/kopatz/b6d2c446-8109-714a-397f-1f35d3136639"; - in { - description = "Download fh calendar"; - wants = [ "network-online.target" ]; - after = [ "network.target" "network-online.target" ]; - wantedBy = [ "multi-user.target" ]; - startAt = "*-*-* 06:00:00"; + systemd.services.kop-fhcalendar = + let + radicale = + if lib.versionOlder lib.version "25.05" then + (builtins.elemAt + config.services.radicale.settings.storage.filesystem_folder 0) + else + config.services.radicale.settings.storage.filesystem_folder; + # not reproducible + working = + "${radicale}/collection-root/kopatz/b6d2c446-8109-714a-397f-1f35d3136639"; + in + { + description = "Download fh calendar"; + wants = [ "network-online.target" ]; + after = [ "network.target" "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + startAt = "*-*-* 06:00:00"; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${pkgs.kop-fhcalendar}/bin/kop-fhcalendar"; - WorkingDirectory = working; - BindPaths = [ working ]; - User = "radicale"; - Restart = "on-failure"; - RestartSec = "5s"; - PrivateMounts = lib.mkDefault true; - PrivateTmp = lib.mkDefault true; - PrivateUsers = lib.mkDefault true; - ProtectClock = lib.mkDefault true; - ProtectControlGroups = lib.mkDefault true; - ProtectHome = lib.mkDefault true; - ProtectHostname = lib.mkDefault true; - ProtectKernelLogs = lib.mkDefault true; - ProtectKernelModules = lib.mkDefault true; - ProtectKernelTunables = lib.mkDefault true; - ProtectSystem = lib.mkDefault "strict"; - # Needs network access - PrivateNetwork = lib.mkDefault false; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.kop-fhcalendar}/bin/kop-fhcalendar"; + WorkingDirectory = working; + BindPaths = [ working ]; + User = "radicale"; + Restart = "on-failure"; + RestartSec = "5s"; + PrivateMounts = lib.mkDefault true; + PrivateTmp = lib.mkDefault true; + PrivateUsers = lib.mkDefault true; + ProtectClock = lib.mkDefault true; + ProtectControlGroups = lib.mkDefault true; + ProtectHome = lib.mkDefault true; + ProtectHostname = lib.mkDefault true; + ProtectKernelLogs = lib.mkDefault true; + ProtectKernelModules = lib.mkDefault true; + ProtectKernelTunables = lib.mkDefault true; + ProtectSystem = lib.mkDefault "strict"; + # Needs network access + PrivateNetwork = lib.mkDefault false; + }; }; - }; }; } diff --git a/modules/services/coturn.nix b/modules/services/coturn.nix index 17b2455..30f9766 100644 --- a/modules/services/coturn.nix +++ b/modules/services/coturn.nix @@ -1,12 +1,12 @@ { config, pkgs, lib, inputs, ... }: { - age.secrets.coturn-secret = { - file = ../../secrets/coturn-secret.age; - owner = "turnserver"; - group = "turnserver"; - }; + age.secrets.coturn-secret = { + file = ../../secrets/coturn-secret.age; + owner = "turnserver"; + group = "turnserver"; + }; - networking.firewall.allowedUDPPortRanges = [ { from = 49000; to=50000; } ]; + networking.firewall.allowedUDPPortRanges = [{ from = 49000; to = 50000; }]; networking.firewall.allowedUDPPorts = [ 3478 ]; #5349 ]; networking.firewall.allowedTCPPorts = [ 3478 ]; #5349 ]; @@ -21,10 +21,10 @@ use-auth-secret = true; static-auth-secret-file = config.age.secrets.coturn-secret.path; relay-ips = [ - "192.168.2.1" + "192.168.2.1" ]; listening-ips = [ - "192.168.2.1" + "192.168.2.1" ]; realm = "kopatz.ddns.net"; #cert = "${config.security.acme.certs."kopatz.ddns.net".directory}/full.pem"; @@ -65,9 +65,9 @@ }; #systemd.services.coturn = { -# serviceConfig = { -# User = lib.mkForce "root"; -# Group = lib.mkForce "root"; -# }; -# }; + # serviceConfig = { + # User = lib.mkForce "root"; + # Group = lib.mkForce "root"; + # }; + # }; } diff --git a/modules/services/default.nix b/modules/services/default.nix index b6af121..bb24eca 100644 --- a/modules/services/default.nix +++ b/modules/services/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ...}: +{ pkgs, config, ... }: { imports = [ ./acme.nix diff --git a/modules/services/dyndns.nix b/modules/services/dyndns.nix index 34cb7c1..5d4859b 100644 --- a/modules/services/dyndns.nix +++ b/modules/services/dyndns.nix @@ -1,12 +1,12 @@ { config, pkgs, lib, inputs, ... }: { - age.secrets.duckdns = { - file = ../../secrets/duckdns.age; - }; - services.ddclient = { - enable = true; - protocol = "duckdns"; - passwordFile = config.age.secrets.duckdns.path; - domains = ["wachbirn.duckdns.org"]; + age.secrets.duckdns = { + file = ../../secrets/duckdns.age; + }; + services.ddclient = { + enable = true; + protocol = "duckdns"; + passwordFile = config.age.secrets.duckdns.path; + domains = [ "wachbirn.duckdns.org" ]; }; } diff --git a/modules/services/fileshelter.nix b/modules/services/fileshelter.nix index 89b3ef2..661fbf4 100644 --- a/modules/services/fileshelter.nix +++ b/modules/services/fileshelter.nix @@ -13,17 +13,17 @@ in }; config = lib.mkIf cfg.enable { users.users.fileshelter = { - isSystemUser = true; - uid = cfg.uid; - group = "fileshelter"; + isSystemUser = true; + uid = cfg.uid; + group = "fileshelter"; }; - users.groups.fileshelter = {}; + users.groups.fileshelter = { }; age.secrets.fileshelter-conf = { - file = ../../secrets/fileshelter-conf.age; - owner = "fileshelter"; + file = ../../secrets/fileshelter-conf.age; + owner = "fileshelter"; }; systemd.tmpfiles.rules = [ - "d /data/fileshelter 0770 fileshelter fileshelter -" + "d /data/fileshelter 0770 fileshelter fileshelter -" ]; custom.misc.docker.enable = true; virtualisation.oci-containers.backend = "docker"; diff --git a/modules/services/games/default.nix b/modules/services/games/default.nix index 31f675b..7d4f228 100644 --- a/modules/services/games/default.nix +++ b/modules/services/games/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ...}: +{ pkgs, config, ... }: { imports = [ ./terraria.nix diff --git a/modules/services/games/palworld.nix b/modules/services/games/palworld.nix index 852fedd..28134ef 100644 --- a/modules/services/games/palworld.nix +++ b/modules/services/games/palworld.nix @@ -1,59 +1,61 @@ # valheim.nix -{config, pkgs, lib, ...}: let +{ config, pkgs, lib, ... }: +let join = builtins.concatStringsSep " "; -in { +in +{ - services.cron = { - enable = true; - systemCronJobs = [ - "0 6 * * * root systemctl restart palworld" - ]; - }; + services.cron = { + enable = true; + systemCronJobs = [ + "0 6 * * * root systemctl restart palworld" + ]; + }; - networking.firewall.allowedUDPPorts = [ 8211 ]; #5349 ]; - users.users.palworld = { - isSystemUser = true; - # Valheim puts save data in the home directory. - home = "/var/lib/palworld"; - createHome = true; - homeMode = "750"; - group = "palworld"; - }; + networking.firewall.allowedUDPPorts = [ 8211 ]; #5349 ]; + users.users.palworld = { + isSystemUser = true; + # Valheim puts save data in the home directory. + home = "/var/lib/palworld"; + createHome = true; + homeMode = "750"; + group = "palworld"; + }; - users.groups.palworld = {}; + users.groups.palworld = { }; - systemd.services.palworld = { - wantedBy = [ "multi-user.target" ]; + systemd.services.palworld = { + wantedBy = [ "multi-user.target" ]; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; - serviceConfig = { - ExecStartPre = join [ - "${pkgs.steamcmd}/bin/steamcmd" - "+force_install_dir /var/lib/palworld" - "+login anonymous" - "+app_update 2394010" - "+quit" - "&& mkdir -p /var/lib/palworld/.steam/sdk64" - "&& cp /var/lib/palworld/linux64/steamclient.so /var/lib/palworld/.steam/sdk64/." - ]; - ExecStart = join [ - "${pkgs.steam-run}/bin/steam-run /var/lib/palworld/Pal/Binaries/Linux/PalServer-Linux-Test Pal" - "-useperfthreads" - "-NoAsyncLoadingThread" - "-UseMultithreadForDS" - ]; - Nice = "-5"; - PrivateTmp = true; - Restart = "on-failure"; - User = "palworld"; - WorkingDirectory = "~"; - }; - environment = { - # linux64 directory is required by Valheim. - LD_LIBRARY_PATH = "/var/lib/palworld/linux64:${pkgs.glibc}/lib"; - SteamAppId = "2394010"; - }; - }; + serviceConfig = { + ExecStartPre = join [ + "${pkgs.steamcmd}/bin/steamcmd" + "+force_install_dir /var/lib/palworld" + "+login anonymous" + "+app_update 2394010" + "+quit" + "&& mkdir -p /var/lib/palworld/.steam/sdk64" + "&& cp /var/lib/palworld/linux64/steamclient.so /var/lib/palworld/.steam/sdk64/." + ]; + ExecStart = join [ + "${pkgs.steam-run}/bin/steam-run /var/lib/palworld/Pal/Binaries/Linux/PalServer-Linux-Test Pal" + "-useperfthreads" + "-NoAsyncLoadingThread" + "-UseMultithreadForDS" + ]; + Nice = "-5"; + PrivateTmp = true; + Restart = "on-failure"; + User = "palworld"; + WorkingDirectory = "~"; + }; + environment = { + # linux64 directory is required by Valheim. + LD_LIBRARY_PATH = "/var/lib/palworld/linux64:${pkgs.glibc}/lib"; + SteamAppId = "2394010"; + }; + }; } diff --git a/modules/services/grafana.nix b/modules/services/grafana.nix index 9ef3dac..d9b6869 100644 --- a/modules/services/grafana.nix +++ b/modules/services/grafana.nix @@ -1,4 +1,4 @@ -{pkgs, config, lib, ...}: +{ pkgs, config, lib, ... }: let useHttps = config.services.step-ca.enable; fqdn = "grafana.home.arpa"; @@ -25,25 +25,25 @@ in }; provision.alerting.contactPoints.path = config.age.secrets.grafana-contact-points.path; - provision.alerting.policies.path = ./grafana/notification-policies.yml; + provision.alerting.policies.path = ./grafana/notification-policies.yml; provision.alerting.templates.path = ./grafana/alerts.yml; provision.datasources.settings = { - datasources = - [ - { - name = "DS_PROMETHEUS"; - url = "http://127.0.0.1:${toString config.services.prometheus.port}"; - type = "prometheus"; - isDefault = true; - # This has to match the prometheus scrape interval, otherwise the $__rate_interval variable wont work. - jsonData.timeInterval = "60s"; - } - { - name = "loki"; - url = "http://localhost:3100"; - type = "loki"; - } - ]; + datasources = + [ + { + name = "DS_PROMETHEUS"; + url = "http://127.0.0.1:${toString config.services.prometheus.port}"; + type = "prometheus"; + isDefault = true; + # This has to match the prometheus scrape interval, otherwise the $__rate_interval variable wont work. + jsonData.timeInterval = "60s"; + } + { + name = "loki"; + url = "http://localhost:3100"; + type = "loki"; + } + ]; }; provision.dashboards.settings.providers = [{ name = "provisioned-dashboards"; @@ -63,8 +63,8 @@ in quic = useHttps; http3 = useHttps; locations."/" = { - proxyPass = "http://127.0.0.1:${toString config.services.grafana.settings.server.http_port}"; - proxyWebsockets = true; + proxyPass = "http://127.0.0.1:${toString config.services.grafana.settings.server.http_port}"; + proxyWebsockets = true; }; }; @@ -91,7 +91,7 @@ in settings.namespaces = [ { name = "nginxlog"; - source.files = ["/var/log/nginx/access.log"]; + source.files = [ "/var/log/nginx/access.log" ]; format = "$remote_addr - $remote_user [$time_local] \"$request\" $status $body_bytes_sent \"$http_referer\" \"$http_user_agent\""; } ]; @@ -101,18 +101,18 @@ in { job_name = "scrapema"; static_configs = [{ - targets = [ - "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" - ] ++ - (lib.optional config.services.cadvisor.enable "${config.services.cadvisor.listenAddress}:${toString config.services.cadvisor.port}") ++ + targets = [ + "127.0.0.1:${toString config.services.prometheus.exporters.node.port}" + ] ++ + (lib.optional config.services.cadvisor.enable "${config.services.cadvisor.listenAddress}:${toString config.services.cadvisor.port}") ++ (lib.optional config.services.prometheus.exporters.nginx.enable "127.0.0.1:${toString config.services.prometheus.exporters.nginx.port}") ++ (lib.optional config.services.prometheus.exporters.nginxlog.enable "127.0.0.1:${toString config.services.prometheus.exporters.nginxlog.port}") ; - }]; + }]; } ]; }; - + services.cadvisor = { enable = true; listenAddress = "127.0.0.1"; diff --git a/modules/services/home-assistant.nix b/modules/services/home-assistant.nix index 4c5bc9e..10a2d6a 100644 --- a/modules/services/home-assistant.nix +++ b/modules/services/home-assistant.nix @@ -13,7 +13,7 @@ config = { # Includes dependencies for a basic setup # https://www.home-assistant.io/integrations/default_config/ - default_config = {}; + default_config = { }; }; }; -} \ No newline at end of file +} diff --git a/modules/services/invidious.nix b/modules/services/invidious.nix index 2d47875..3a4634b 100644 --- a/modules/services/invidious.nix +++ b/modules/services/invidious.nix @@ -1,4 +1,4 @@ -{ config, vars, ...} : +{ config, vars, ... }: let fqdn = "yt.home.arpa"; useHttps = config.services.step-ca.enable; diff --git a/modules/services/kavita.nix b/modules/services/kavita.nix index 7f1341b..00917b0 100644 --- a/modules/services/kavita.nix +++ b/modules/services/kavita.nix @@ -21,133 +21,138 @@ in { }; isTest = mkEnableOption "Is this a test vm?"; }; - config = let - fqdn = "kavita-kopatz.duckdns.org"; - useStepCa = false; # config.services.step-ca.enable; - useHttps = cfg.https; - baseDir = cfg.dir; - mangal = "${pkgs.mangal-patched}/bin/mangal"; - githubRunnerEnabled = config.services.github-runners ? oberprofis.enable; - in lib.mkIf cfg.enable { - networking.firewall.allowedTCPPorts = [ 5000 ]; - systemd.tmpfiles.rules = [ - (if githubRunnerEnabled then - "d ${baseDir} 0750 kavita github-actions-runner -" - else - "d ${baseDir} 0770 kavita kavita -") - "d ${baseDir}/manga 0770 kavita kavita -" - ] ++ lib.optional githubRunnerEnabled - "d ${baseDir}/github 0770 github-actions-runner kavita -"; + config = + let + fqdn = "kavita-kopatz.duckdns.org"; + useStepCa = false; # config.services.step-ca.enable; + useHttps = cfg.https; + baseDir = cfg.dir; + mangal = "${pkgs.mangal-patched}/bin/mangal"; + githubRunnerEnabled = config.services.github-runners ? oberprofis.enable; + in + lib.mkIf cfg.enable { + networking.firewall.allowedTCPPorts = [ 5000 ]; + systemd.tmpfiles.rules = [ + (if githubRunnerEnabled then + "d ${baseDir} 0750 kavita github-actions-runner -" + else + "d ${baseDir} 0770 kavita kavita -") + "d ${baseDir}/manga 0770 kavita kavita -" + ] ++ lib.optional githubRunnerEnabled + "d ${baseDir}/github 0770 github-actions-runner kavita -"; - age.secrets.kavita = mkIf (!cfg.isTest) { - file = ../../secrets/kavita.age; - owner = "kavita"; - group = "kavita"; - }; - - services.kavita = { - enable = true; - user = "kavita"; - package = let - backend = pkgs.unstable.kavita.backend.overrideAttrs - (old: { patches = old.patches ++ [ ./kavita-patches-chapter-parsing.diff ./kavita-page-size.diff ]; }); - kavitaPatched = pkgs.unstable.kavita.overrideAttrs (old: { backend = backend; }); - in kavitaPatched; - settings = { - Port = 5000; - IpAddresses = "127.0.0.1"; - BaseUrl = "/kavita"; + age.secrets.kavita = mkIf (!cfg.isTest) { + file = ../../secrets/kavita.age; + owner = "kavita"; + group = "kavita"; }; - dataDir = baseDir; - tokenKeyFile = if cfg.isTest then - (builtins.toFile "test" - "wWKNeGUslGILrUUp8Dnn4xyYnivZWBb8uqjKg3ALyCs7reV5v3CtE/E2b6i0Mwz1Xw1p9a0wcduRDNoa8Yh8kQ==") - else - config.age.secrets.kavita.path; - }; - #todo: base url needs new kavita version - systemd.services = { - kavita = { - after = [ "nginx.service" ] ++ lib.optional useStepCa "step-ca.service"; + services.kavita = { + enable = true; + user = "kavita"; + package = + let + backend = pkgs.unstable.kavita.backend.overrideAttrs + (old: { patches = old.patches ++ [ ./kavita-patches-chapter-parsing.diff ./kavita-page-size.diff ]; }); + kavitaPatched = pkgs.unstable.kavita.overrideAttrs (old: { backend = backend; }); + in + kavitaPatched; + settings = { + Port = 5000; + IpAddresses = "127.0.0.1"; + BaseUrl = "/kavita"; + }; + dataDir = baseDir; + tokenKeyFile = + if cfg.isTest then + (builtins.toFile "test" + "wWKNeGUslGILrUUp8Dnn4xyYnivZWBb8uqjKg3ALyCs7reV5v3CtE/E2b6i0Mwz1Xw1p9a0wcduRDNoa8Yh8kQ==") + else + config.age.secrets.kavita.path; }; - download-manga = mkIf cfg.autoDownload { - wantedBy = [ "multi-user.target" ]; - wants = [ "network-online.target" ]; - after = [ "network-online.target" ]; - startAt = "*-*-* 19:00:00"; - restartIfChanged = false; - script = '' - ${mangal} clear -q - ${mangal} clear -c - ${mangal} inline -S Mangapill -q omniscient -m first -d - ${mangal} inline -S Mangapill --query "oshi-no-ko" --manga first --download - ${mangal} inline -S Mangapill --query "Frieren" --manga first --download -f - ${mangal} inline -S Mangapill --query "Chainsaw" --manga first --download - ${mangal} inline -S Mangapill --query "Jujutsu%20Kaisen" --manga first --download - ${mangal} inline -S Mangapill --query "solo-leveling" --manga first --download - ${mangal} inline -S Mangapill --query "the-greatest-real-estate" --manga first --download - ${mangal} inline -S Mangapill --query "66666_years" --manga first --download - ${mangal} inline -S Mangapill --query "Return_of_the_blossoming" --manga first --download - ${mangal} inline -S Mangapill --query "path_of_the_shaman" --manga first --download - ${mangal} inline -S Mangapill --query "pick_me_up" --manga first --download - ${mangal} inline -S Mangapill --query "revenge_of_the_iron_blooded" --manga first --download - ${mangal} inline -S Mangapill --query "northern_blade" --manga first --download - ${mangal} inline -S Mangapill --query "Dungeon_reset" --manga first --download - ${mangal} inline -S Mangapill --query "iruma-kun" --manga first --download - ${mangal} inline -S Manganato --query "grand_blue" --manga first --download - ${mangal} inline -S Manganato --query "sss-class_suicide" --manga first --download - ${mangal} inline -S Manganato --query "cultivation_chat" --manga first --download - ${mangal} inline -S Manganato --query "gokushufudo" --manga first --download - ${mangal} inline -S Manganato --query "slime" --manga first --download - ${mangal} inline -S Manganato --query "nano_machine" --manga first --download - ${mangal} inline -S Manganato --query "kill_the_hero" --manga first --download - ${mangal} inline -S Manganato --query "Seoul_Station_Necromancer" --manga first --download - ${mangal} inline -S Manganato --query "grandmaster_of_demonic" --manga first --download - ${mangal} inline -S Manganato --query "becoming_the_monarch" --manga first --download - ${mangal} inline -S Manganato --query "sleeping" --manga first --download - ${mangal} inline -S Manganato --query "Terror_man" --manga first --download - ${mangal} inline -S Manganato --query "I_Stole_the_Number_One_Ranker" --manga first --download - ${mangal} inline -S Manganato --query "hidan_no_aria" --manga first --download - ${mangal} inline -S AsuraScans --query "the_max_level_hero" --manga first --download - ${mangal} inline -S Manganato --query "Parallel_City" --manga first --download - ${mangal} inline -S Manganato --query "Existence" --manga first --download - ${mangal} inline -S Mangapill --query "Call_of_the_Night" --manga first --download - ''; - serviceConfig = { - PrivateTmp = true; - User = "kavita"; - Group = "kavita"; - Type = "oneshot"; - WorkingDirectory = "${baseDir}/manga"; + #todo: base url needs new kavita version + systemd.services = { + kavita = { + after = [ "nginx.service" ] ++ lib.optional useStepCa "step-ca.service"; + }; + download-manga = mkIf cfg.autoDownload { + wantedBy = [ "multi-user.target" ]; + + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + startAt = "*-*-* 19:00:00"; + restartIfChanged = false; + script = '' + ${mangal} clear -q + ${mangal} clear -c + ${mangal} inline -S Mangapill -q omniscient -m first -d + ${mangal} inline -S Mangapill --query "oshi-no-ko" --manga first --download + ${mangal} inline -S Mangapill --query "Frieren" --manga first --download -f + ${mangal} inline -S Mangapill --query "Chainsaw" --manga first --download + ${mangal} inline -S Mangapill --query "Jujutsu%20Kaisen" --manga first --download + ${mangal} inline -S Mangapill --query "solo-leveling" --manga first --download + ${mangal} inline -S Mangapill --query "the-greatest-real-estate" --manga first --download + ${mangal} inline -S Mangapill --query "66666_years" --manga first --download + ${mangal} inline -S Mangapill --query "Return_of_the_blossoming" --manga first --download + ${mangal} inline -S Mangapill --query "path_of_the_shaman" --manga first --download + ${mangal} inline -S Mangapill --query "pick_me_up" --manga first --download + ${mangal} inline -S Mangapill --query "revenge_of_the_iron_blooded" --manga first --download + ${mangal} inline -S Mangapill --query "northern_blade" --manga first --download + ${mangal} inline -S Mangapill --query "Dungeon_reset" --manga first --download + ${mangal} inline -S Mangapill --query "iruma-kun" --manga first --download + ${mangal} inline -S Manganato --query "grand_blue" --manga first --download + ${mangal} inline -S Manganato --query "sss-class_suicide" --manga first --download + ${mangal} inline -S Manganato --query "cultivation_chat" --manga first --download + ${mangal} inline -S Manganato --query "gokushufudo" --manga first --download + ${mangal} inline -S Manganato --query "slime" --manga first --download + ${mangal} inline -S Manganato --query "nano_machine" --manga first --download + ${mangal} inline -S Manganato --query "kill_the_hero" --manga first --download + ${mangal} inline -S Manganato --query "Seoul_Station_Necromancer" --manga first --download + ${mangal} inline -S Manganato --query "grandmaster_of_demonic" --manga first --download + ${mangal} inline -S Manganato --query "becoming_the_monarch" --manga first --download + ${mangal} inline -S Manganato --query "sleeping" --manga first --download + ${mangal} inline -S Manganato --query "Terror_man" --manga first --download + ${mangal} inline -S Manganato --query "I_Stole_the_Number_One_Ranker" --manga first --download + ${mangal} inline -S Manganato --query "hidan_no_aria" --manga first --download + ${mangal} inline -S AsuraScans --query "the_max_level_hero" --manga first --download + ${mangal} inline -S Manganato --query "Parallel_City" --manga first --download + ${mangal} inline -S Manganato --query "Existence" --manga first --download + ${mangal} inline -S Mangapill --query "Call_of_the_Night" --manga first --download + ''; + serviceConfig = { + PrivateTmp = true; + User = "kavita"; + Group = "kavita"; + Type = "oneshot"; + WorkingDirectory = "${baseDir}/manga"; + }; }; }; - }; - # services.nginx.virtualHosts."kopatz.ddns.net".locations."/kavita" = { - # proxyPass = "http://127.0.0.1:5000"; - # extraConfig = '' - # add_header Access-Control-Allow-Origin *; - # add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; - # add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept"; - # ''; - # }; - security.acme.certs."${fqdn}" = lib.mkIf useStepCa { - server = "https://127.0.0.1:8443/acme/kop-acme/directory"; + # services.nginx.virtualHosts."kopatz.ddns.net".locations."/kavita" = { + # proxyPass = "http://127.0.0.1:5000"; + # extraConfig = '' + # add_header Access-Control-Allow-Origin *; + # add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; + # add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept"; + # ''; + # }; + security.acme.certs."${fqdn}" = lib.mkIf useStepCa { + server = "https://127.0.0.1:8443/acme/kop-acme/directory"; + }; + services.nginx.virtualHosts."${fqdn}" = { + forceSSL = useHttps; + enableACME = useHttps; + quic = useHttps; + http3 = useHttps; + locations."/".proxyPass = "http://127.0.0.1:5000"; + locations."/".extraConfig = '' + more_clear_headers 'x-frame-options'; + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; + add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept"; + ''; + }; }; - services.nginx.virtualHosts."${fqdn}" = { - forceSSL = useHttps; - enableACME = useHttps; - quic = useHttps; - http3 = useHttps; - locations."/".proxyPass = "http://127.0.0.1:5000"; - locations."/".extraConfig = '' - more_clear_headers 'x-frame-options'; - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Methods "GET, POST, OPTIONS"; - add_header Access-Control-Allow-Headers "Authorization, Origin, X-Requested-With, Content-Type, Accept"; - ''; - }; - }; } diff --git a/modules/services/kubernetes.nix b/modules/services/kubernetes.nix index 035fb86..8412b66 100644 --- a/modules/services/kubernetes.nix +++ b/modules/services/kubernetes.nix @@ -1,4 +1,4 @@ -{ pkgs, config, lib, ...}: +{ pkgs, config, lib, ... }: # idk, dont need this with lib; let @@ -6,38 +6,40 @@ let in { options.custom.services.kubernetes = { - enable = mkEnableOption "Enables kubernetes"; + enable = mkEnableOption "Enables kubernetes"; }; - config = let - kubeMasterIP = "localhost"; - kubeMasterHostname = "localhost"; - in lib.mkIf cfg.enable { + config = + let + kubeMasterIP = "localhost"; + kubeMasterHostname = "localhost"; + in + lib.mkIf cfg.enable { - networking.firewall.allowedTCPPorts = [ - 6443 # k3s: required so that pods can reach the API server (running on port 6443 by default) - # 2379 # k3s, etcd clients: required if using a "High Availability Embedded etcd" configuration - # 2380 # k3s, etcd peers: required if using a "High Availability Embedded etcd" configuration - ]; - networking.firewall.allowedUDPPorts = [ - # 8472 # k3s, flannel: required if using multi-node for inter-node networking - ]; - services.k3s.enable = true; - services.k3s.role = "server"; - services.k3s.extraFlags = toString [ - # "--kubelet-arg=v=4" # Optionally add additional args to k3s - ]; - environment.systemPackages = with pkgs; [ - k3s - ]; - #services.kubernetes = { - # roles = ["master" "node"]; - # masterAddress = "localhost"; - # apiserverAddress = "https://localhost:6443"; - # apiserver = { - # advertiseAddress = "127.0.0.1"; - # securePort = 6443; - # allowPrivileged = true; - # }; - #}; - }; + networking.firewall.allowedTCPPorts = [ + 6443 # k3s: required so that pods can reach the API server (running on port 6443 by default) + # 2379 # k3s, etcd clients: required if using a "High Availability Embedded etcd" configuration + # 2380 # k3s, etcd peers: required if using a "High Availability Embedded etcd" configuration + ]; + networking.firewall.allowedUDPPorts = [ + # 8472 # k3s, flannel: required if using multi-node for inter-node networking + ]; + services.k3s.enable = true; + services.k3s.role = "server"; + services.k3s.extraFlags = toString [ + # "--kubelet-arg=v=4" # Optionally add additional args to k3s + ]; + environment.systemPackages = with pkgs; [ + k3s + ]; + #services.kubernetes = { + # roles = ["master" "node"]; + # masterAddress = "localhost"; + # apiserverAddress = "https://localhost:6443"; + # apiserver = { + # advertiseAddress = "127.0.0.1"; + # securePort = 6443; + # allowPrivileged = true; + # }; + #}; + }; } diff --git a/modules/services/minecraft-server.nix b/modules/services/minecraft-server.nix index b172126..7998830 100644 --- a/modules/services/minecraft-server.nix +++ b/modules/services/minecraft-server.nix @@ -1,66 +1,66 @@ -{ pkgs, ...}: +{ pkgs, ... }: { - services.minecraft-server = { - enable = true; - eula = true; - openFirewall = true; - package = pkgs.unstable.papermc; - declarative = true; - whitelist = { - coolBayram = "514afd03-8ca2-4f60-abe4-4c2a365d223b"; - filipus098 = "a09fb009-be78-4e26-9f33-1534186e2228"; - }; - serverProperties = { - allow-flight=true; - allow-nether=true; - broadcast-console-to-ops=true; - broadcast-rcon-to-ops=true; - debug=false; - difficulty="hard"; - enable-command-block=false; - enable-jmx-monitoring=false; - enable-query=false; - enable-rcon=false; - enable-status=true; - enforce-secure-profile=true; - enforce-whitelist=false; - entity-broadcast-range-percentage=100; - force-gamemode=false; - function-permission-level=2; - gamemode="survival"; - generate-structures=true; - hardcore=false; - hide-online-players=false; - initial-enabled-packs="vanilla"; - level-name="budak"; - level-type="minecraft\:normal"; - log-ips=true; - max-chained-neighbor-updates=1000000; - max-players=5; - max-tick-time=60000; - max-world-size=29999984; - motd="A Minecraft Server"; - network-compression-threshold=256; - online-mode=true; - op-permission-level=4; - player-idle-timeout=0; - prevent-proxy-connections=false; - pvp=true; - "query.port"=25565; - rate-limit=0; - "rcon.password"="123asdadsqwe123123"; - "rcon.port"=25575; - require-resource-pack=false; - server-port=25565; - simulation-distance=10; - spawn-animals=true; - spawn-monsters=true; - spawn-npcs=true; - spawn-protection=16; - sync-chunk-writes=true; - use-native-transport=true; - view-distance=10; - white-list=true; - }; + services.minecraft-server = { + enable = true; + eula = true; + openFirewall = true; + package = pkgs.unstable.papermc; + declarative = true; + whitelist = { + coolBayram = "514afd03-8ca2-4f60-abe4-4c2a365d223b"; + filipus098 = "a09fb009-be78-4e26-9f33-1534186e2228"; }; + serverProperties = { + allow-flight = true; + allow-nether = true; + broadcast-console-to-ops = true; + broadcast-rcon-to-ops = true; + debug = false; + difficulty = "hard"; + enable-command-block = false; + enable-jmx-monitoring = false; + enable-query = false; + enable-rcon = false; + enable-status = true; + enforce-secure-profile = true; + enforce-whitelist = false; + entity-broadcast-range-percentage = 100; + force-gamemode = false; + function-permission-level = 2; + gamemode = "survival"; + generate-structures = true; + hardcore = false; + hide-online-players = false; + initial-enabled-packs = "vanilla"; + level-name = "budak"; + level-type = "minecraft\:normal"; + log-ips = true; + max-chained-neighbor-updates = 1000000; + max-players = 5; + max-tick-time = 60000; + max-world-size = 29999984; + motd = "A Minecraft Server"; + network-compression-threshold = 256; + online-mode = true; + op-permission-level = 4; + player-idle-timeout = 0; + prevent-proxy-connections = false; + pvp = true; + "query.port" = 25565; + rate-limit = 0; + "rcon.password" = "123asdadsqwe123123"; + "rcon.port" = 25575; + require-resource-pack = false; + server-port = 25565; + simulation-distance = 10; + spawn-animals = true; + spawn-monsters = true; + spawn-npcs = true; + spawn-protection = 16; + sync-chunk-writes = true; + use-native-transport = true; + view-distance = 10; + white-list = true; + }; + }; } diff --git a/modules/services/netdata.nix b/modules/services/netdata.nix index eb363d5..9a05c28 100644 --- a/modules/services/netdata.nix +++ b/modules/services/netdata.nix @@ -1,5 +1,5 @@ { vars, ... }: -let +let ip = vars.ipv4; wireguardIp = vars.wireguardIp; in @@ -54,6 +54,6 @@ in perf = no freeipmi = no apps = yes - ''; + ''; }; } diff --git a/modules/services/nextcloud.nix b/modules/services/nextcloud.nix index c2ebf38..09188cf 100644 --- a/modules/services/nextcloud.nix +++ b/modules/services/nextcloud.nix @@ -5,70 +5,70 @@ let useHttps = config.services.step-ca.enable; in { - imports = [ ./postgres.nix ]; - security.acme.certs."${fqdn}".server = "https://127.0.0.1:8443/acme/kop-acme/directory"; - services.nginx = { - enable = true; + imports = [ ./postgres.nix ]; + security.acme.certs."${fqdn}".server = "https://127.0.0.1:8443/acme/kop-acme/directory"; + services.nginx = { + enable = true; - # Use recommended settings - recommendedGzipSettings = true; - recommendedOptimisation = true; - recommendedProxySettings = true; - recommendedTlsSettings = true; + # Use recommended settings + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; - # Only allow PFS-enabled ciphers with AES256 - sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; + # Only allow PFS-enabled ciphers with AES256 + sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL"; - # Setup Nextcloud virtual host to listen on ports - virtualHosts = { - "${fqdn}" = { - serverAliases = [ wireguardIp ]; - ## Force HTTP redirect to HTTPS - forceSSL = useHttps; - enableACME = useHttps; - locations."~ \\.php(?:$|/)".extraConfig = '' - client_max_body_size 20G; - ''; - }; - }; + # Setup Nextcloud virtual host to listen on ports + virtualHosts = { + "${fqdn}" = { + serverAliases = [ wireguardIp ]; + ## Force HTTP redirect to HTTPS + forceSSL = useHttps; + enableACME = useHttps; + locations."~ \\.php(?:$|/)".extraConfig = '' + client_max_body_size 20G; + ''; + }; + }; + }; + + age.secrets.nextcloud-admin = { + file = ../../secrets/nextcloud-admin.age; + owner = "nextcloud"; + group = "nextcloud"; + }; + services.nextcloud = { + enable = true; + package = pkgs.nextcloud28; + https = true; + hostName = "nextcloud.home.arpa"; + config.adminpassFile = config.age.secrets.nextcloud-admin.path; + config.dbtype = "pgsql"; + database.createLocally = true; + settings.trusted_domains = [ wireguardIp "nextcloud.home.arpa" ]; + home = "/mnt/250ssd/nextcloud"; + extraApps = with config.services.nextcloud.package.packages.apps; { + inherit onlyoffice calendar mail; }; - age.secrets.nextcloud-admin = { - file = ../../secrets/nextcloud-admin.age; - owner = "nextcloud"; - group = "nextcloud"; - }; - services.nextcloud = { - enable = true; - package = pkgs.nextcloud28; - https = true; - hostName = "nextcloud.home.arpa"; - config.adminpassFile = config.age.secrets.nextcloud-admin.path; - config.dbtype = "pgsql"; - database.createLocally = true; - settings.trusted_domains = [ wireguardIp "nextcloud.home.arpa" ]; - home = "/mnt/250ssd/nextcloud"; - extraApps = with config.services.nextcloud.package.packages.apps; { - inherit onlyoffice calendar mail; - }; - - phpOptions = { - upload_max_filesize = lib.mkForce "20G"; - post_max_size = lib.mkForce "20G"; - }; - extraAppsEnable = true; - settings.enabledPreviewProviders = [ - "OC\\Preview\\BMP" - "OC\\Preview\\GIF" - "OC\\Preview\\JPEG" - "OC\\Preview\\Krita" - "OC\\Preview\\MarkDown" - "OC\\Preview\\MP3" - "OC\\Preview\\OpenDocument" - "OC\\Preview\\PNG" - "OC\\Preview\\TXT" - "OC\\Preview\\XBitmap" - "OC\\Preview\\HEIC" - ]; + phpOptions = { + upload_max_filesize = lib.mkForce "20G"; + post_max_size = lib.mkForce "20G"; }; + extraAppsEnable = true; + settings.enabledPreviewProviders = [ + "OC\\Preview\\BMP" + "OC\\Preview\\GIF" + "OC\\Preview\\JPEG" + "OC\\Preview\\Krita" + "OC\\Preview\\MarkDown" + "OC\\Preview\\MP3" + "OC\\Preview\\OpenDocument" + "OC\\Preview\\PNG" + "OC\\Preview\\TXT" + "OC\\Preview\\XBitmap" + "OC\\Preview\\HEIC" + ]; + }; } diff --git a/modules/services/nginx.nix b/modules/services/nginx.nix index e552dad..585beda 100644 --- a/modules/services/nginx.nix +++ b/modules/services/nginx.nix @@ -45,72 +45,74 @@ in { more_set_headers "Permissions-Policy: geolocation=(), microphone=()"; ''; - virtualHosts = let - kopConfig = { - root = pkgs.kop-website; - forceSSL = cfg.https; - enableACME = cfg.https; - quic = cfg.https; - http3 = cfg.https; - locations = { - "~* \\.(jpg|png)$".extraConfig = '' - add_header Access-Control-Allow-Origin *; - ''; - "/stash" = { - basicAuthFile = config.age.secrets.stash-auth.path; - extraConfig = '' - client_max_body_size 20000M; - proxy_redirect off; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-NginX-Proxy true; - proxy_pass http://localhost:7777; + virtualHosts = + let + kopConfig = { + root = pkgs.kop-website; + forceSSL = cfg.https; + enableACME = cfg.https; + quic = cfg.https; + http3 = cfg.https; + locations = { + "~* \\.(jpg|png)$".extraConfig = '' + add_header Access-Control-Allow-Origin *; ''; - }; - "/tracker-site" = { - tryFiles = "$uri $uri/ /tracker-site/index.html =404"; - }; - "/tracker-site/api" = { - extraConfig = '' - rewrite /tracker-site/api/(.*) /$1 break; - ''; - proxyPass = "http://127.0.0.1:8080"; - }; - "/radicale/" = { - extraConfig = '' - proxy_set_header X-Script-Name /radicale; - ''; - proxyPass = "http://localhost:5232/"; - }; - "/socket.io" = { proxyPass = "http://localhost:9955"; proxyWebsockets = true; }; - "/comms/" = { - extraConfig = '' + "/stash" = { + basicAuthFile = config.age.secrets.stash-auth.path; + extraConfig = '' + client_max_body_size 20000M; + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-NginX-Proxy true; + proxy_pass http://localhost:7777; + ''; + }; + "/tracker-site" = { + tryFiles = "$uri $uri/ /tracker-site/index.html =404"; + }; + "/tracker-site/api" = { + extraConfig = '' + rewrite /tracker-site/api/(.*) /$1 break; + ''; + proxyPass = "http://127.0.0.1:8080"; + }; + "/radicale/" = { + extraConfig = '' + proxy_set_header X-Script-Name /radicale; + ''; + proxyPass = "http://localhost:5232/"; + }; + "/socket.io" = { proxyPass = "http://localhost:9955"; proxyWebsockets = true; }; + "/comms/" = { + extraConfig = '' more_set_headers "Permissions-Policy: geolocation=(), microphone=(self), camera=(self)"; - ''; - alias = "/comms/"; - tryFiles = "$uri $uri/ /comms/index.html"; - }; - "/comms" = { - extraConfig = '' - return 301 /comms/; - ''; - }; - "/kavita-client" = { - extraConfig = '' - return 301 /kavita-client/; - ''; - }; - "/kavita-client/" = { - alias = "/kavita-client/"; + ''; + alias = "/comms/"; + tryFiles = "$uri $uri/ /comms/index.html"; + }; + "/comms" = { + extraConfig = '' + return 301 /comms/; + ''; + }; + "/kavita-client" = { + extraConfig = '' + return 301 /kavita-client/; + ''; + }; + "/kavita-client/" = { + alias = "/kavita-client/"; + }; }; }; + in + { + "kopatz.ddns.net" = kopConfig; + "kop.oasch.net" = kopConfig; }; - in { - "kopatz.ddns.net" = kopConfig; - "kop.oasch.net" = kopConfig; - }; }; }; } diff --git a/modules/services/paperless.nix b/modules/services/paperless.nix index dc3dfdd..c00b2d7 100644 --- a/modules/services/paperless.nix +++ b/modules/services/paperless.nix @@ -1,20 +1,20 @@ { config, pkgs, lib, inputs, vars, ... }: -let +let ip = vars.ipv4; wireguardIp = vars.wireguardIp; in { - networking.firewall.allowedTCPPorts = [ 28981 ]; - age.secrets.paperless = { - file = ../../secrets/paperless.age; - owner = "paperless"; - group = "paperless"; - }; - services.paperless = { - enable = true; - port = 28981; - passwordFile = config.age.secrets.paperless.path; - address = wireguardIp; - mediaDir = "/mnt/250ssd/paperless"; - }; + networking.firewall.allowedTCPPorts = [ 28981 ]; + age.secrets.paperless = { + file = ../../secrets/paperless.age; + owner = "paperless"; + group = "paperless"; + }; + services.paperless = { + enable = true; + port = 28981; + passwordFile = config.age.secrets.paperless.path; + address = wireguardIp; + mediaDir = "/mnt/250ssd/paperless"; + }; } diff --git a/modules/services/postgres.nix b/modules/services/postgres.nix index 893aa04..0acbfe2 100644 --- a/modules/services/postgres.nix +++ b/modules/services/postgres.nix @@ -1,23 +1,23 @@ { pkgs, ... }: { - services.postgresql = { - enable = true; - authentication = pkgs.lib.mkOverride 10 '' - #type database DBuser auth-method optional_ident_map - local sameuser all peer map=superuser_map - local all postgres peer - ''; - identMap = '' - # ArbitraryMapName systemUser DBUser - superuser_map root postgres - superuser_map postgres postgres - # Let other names login as themselves - superuser_map /^(.*)$ \1 - ''; - }; - services.postgresqlBackup = { - enable = true; - location = "/var/backup/postgresql"; - backupAll = true; - }; + services.postgresql = { + enable = true; + authentication = pkgs.lib.mkOverride 10 '' + #type database DBuser auth-method optional_ident_map + local sameuser all peer map=superuser_map + local all postgres peer + ''; + identMap = '' + # ArbitraryMapName systemUser DBUser + superuser_map root postgres + superuser_map postgres postgres + # Let other names login as themselves + superuser_map /^(.*)$ \1 + ''; + }; + services.postgresqlBackup = { + enable = true; + location = "/var/backup/postgresql"; + backupAll = true; + }; } diff --git a/modules/services/rdp.nix b/modules/services/rdp.nix index 95fbee3..a2d61a7 100644 --- a/modules/services/rdp.nix +++ b/modules/services/rdp.nix @@ -3,7 +3,7 @@ let wm = vars.wm; in { - services.xrdp.enable = true; - services.xrdp.defaultWindowManager = wm; - services.xrdp.openFirewall = true; + services.xrdp.enable = true; + services.xrdp.defaultWindowManager = wm; + services.xrdp.openFirewall = true; } diff --git a/modules/services/samba.nix b/modules/services/samba.nix index 0a2f214..26fe396 100644 --- a/modules/services/samba.nix +++ b/modules/services/samba.nix @@ -1,37 +1,37 @@ { - #services.samba-wsdd.enable = true; # make shares visible for windows 10 clients - #networking.firewall.allowedTCPPorts = [ - #5357 # wsdd - #]; - #networking.firewall.allowedUDPPorts = [ - #3702 # wsdd - #]; - services.samba.openFirewall = true; - services.samba = { - enable = true; - securityType = "user"; - invalidUsers = [ - "root" - ]; - extraConfig = '' - disable netbios = yes - smb ports = 445 - workgroup = WORKGROUP - server string = smbnix - security = user - #use sendfile = yes - #max protocol = smb2 - # note: localhost is the ipv6 localhost ::1 - hosts allow = 192.168.0. 192.168.174.1 127.0.0.1 localhost - hosts deny = 0.0.0.0/0 - guest account = nobody - map to guest = bad user - ''; - shares = { - homes = { - browseable = "no"; - writable = "yes"; - }; - }; + #services.samba-wsdd.enable = true; # make shares visible for windows 10 clients + #networking.firewall.allowedTCPPorts = [ + #5357 # wsdd + #]; + #networking.firewall.allowedUDPPorts = [ + #3702 # wsdd + #]; + services.samba.openFirewall = true; + services.samba = { + enable = true; + securityType = "user"; + invalidUsers = [ + "root" + ]; + extraConfig = '' + disable netbios = yes + smb ports = 445 + workgroup = WORKGROUP + server string = smbnix + security = user + #use sendfile = yes + #max protocol = smb2 + # note: localhost is the ipv6 localhost ::1 + hosts allow = 192.168.0. 192.168.174.1 127.0.0.1 localhost + hosts deny = 0.0.0.0/0 + guest account = nobody + map to guest = bad user + ''; + shares = { + homes = { + browseable = "no"; + writable = "yes"; + }; }; + }; } diff --git a/modules/services/smartd.nix b/modules/services/smartd.nix index d002be1..ba354db 100644 --- a/modules/services/smartd.nix +++ b/modules/services/smartd.nix @@ -17,7 +17,8 @@ let --data "$JSON" ''; cfg = config.custom.services.smartd; -in { +in +{ options.custom.services.smartd = { enable = lib.mkEnableOption "Enables smartd monitoring"; diff --git a/modules/services/ssh.nix b/modules/services/ssh.nix index ee5b344..5b95717 100644 --- a/modules/services/ssh.nix +++ b/modules/services/ssh.nix @@ -1,16 +1,16 @@ { - networking.firewall.allowedTCPPorts = [ 22 ]; - services.openssh = { - enable = true; - allowSFTP = false; - settings.PasswordAuthentication = false; - settings.KbdInteractiveAuthentication = false; - settings.X11Forwarding = false; - settings.PermitRootLogin = "prohibit-password"; - extraConfig = '' - AllowAgentForwarding no - AllowStreamLocalForwarding no - AuthenticationMethods publickey - ''; - }; + networking.firewall.allowedTCPPorts = [ 22 ]; + services.openssh = { + enable = true; + allowSFTP = false; + settings.PasswordAuthentication = false; + settings.KbdInteractiveAuthentication = false; + settings.X11Forwarding = false; + settings.PermitRootLogin = "prohibit-password"; + extraConfig = '' + AllowAgentForwarding no + AllowStreamLocalForwarding no + AuthenticationMethods publickey + ''; + }; } diff --git a/modules/services/step-ca.nix b/modules/services/step-ca.nix index 3500c2d..900de00 100644 --- a/modules/services/step-ca.nix +++ b/modules/services/step-ca.nix @@ -2,33 +2,33 @@ let root_ca = '' ------BEGIN CERTIFICATE----- -MIIBjTCCATKgAwIBAgIRAMVH2+JHZ3wm2fLUlKjTYDswCgYIKoZIzj0EAwIwJDEM -MAoGA1UEChMDS29wMRQwEgYDVQQDEwtLb3AgUm9vdCBDQTAeFw0yMzEyMDgxNDUx -MTZaFw0zMzEyMDUxNDUxMTZaMCQxDDAKBgNVBAoTA0tvcDEUMBIGA1UEAxMLS29w -IFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATdZBOkNynShXipzhuX -f6dUByD3chNupNWsagYC5AlPRJT9fAeHEIK/bxWkFwRtLBDopWvBu9lHahBgpHc7 -y7rTo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNV -HQ4EFgQU9AVtwipW5HDBLfZRH1KZCnIKCfowCgYIKoZIzj0EAwIDSQAwRgIhAMHj -AipNdhQKIYPvMt/h1uW4xP3NTkitnmshM09+rIasAiEAlSalGddXDkqJBHhPD+Fr -gpuVkfVkA8gQCXNs5F9TnxA= ------END CERTIFICATE----- + -----BEGIN CERTIFICATE----- + MIIBjTCCATKgAwIBAgIRAMVH2+JHZ3wm2fLUlKjTYDswCgYIKoZIzj0EAwIwJDEM + MAoGA1UEChMDS29wMRQwEgYDVQQDEwtLb3AgUm9vdCBDQTAeFw0yMzEyMDgxNDUx + MTZaFw0zMzEyMDUxNDUxMTZaMCQxDDAKBgNVBAoTA0tvcDEUMBIGA1UEAxMLS29w + IFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATdZBOkNynShXipzhuX + f6dUByD3chNupNWsagYC5AlPRJT9fAeHEIK/bxWkFwRtLBDopWvBu9lHahBgpHc7 + y7rTo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNV + HQ4EFgQU9AVtwipW5HDBLfZRH1KZCnIKCfowCgYIKoZIzj0EAwIDSQAwRgIhAMHj + AipNdhQKIYPvMt/h1uW4xP3NTkitnmshM09+rIasAiEAlSalGddXDkqJBHhPD+Fr + gpuVkfVkA8gQCXNs5F9TnxA= + -----END CERTIFICATE----- ''; intermediate_ca = '' ------BEGIN CERTIFICATE----- -MIIBtDCCAVqgAwIBAgIQbEVEV7LgtjVWO+qBrrmgETAKBggqhkjOPQQDAjAkMQww -CgYDVQQKEwNLb3AxFDASBgNVBAMTC0tvcCBSb290IENBMB4XDTIzMTIwODE0NTEx -N1oXDTMzMTIwNTE0NTExN1owLDEMMAoGA1UEChMDS29wMRwwGgYDVQQDExNLb3Ag -SW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmv7jg7Cs -4L5v52+3yUmn79hZFS2vmm/5wwcUCL63dokEXQsHgbEjaRKsF/MW0yJDLTB6Sdhl -pCvoNJqITWuEN6NmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C -AQAwHQYDVR0OBBYEFDgVolMCmdrhDIXhuIs4q/KwRKNLMB8GA1UdIwQYMBaAFPQF -bcIqVuRwwS32UR9SmQpyCgn6MAoGCCqGSM49BAMCA0gAMEUCIQCQa01E+UvAJ8KR -DFfDducZUpW4tZRN35lqoge7T9nM2QIgK4FFt1NqDqcjOSabAXPOQ68bvdxlHW0y -AgN9qNc3Jbo= ------END CERTIFICATE----- -''; + -----BEGIN CERTIFICATE----- + MIIBtDCCAVqgAwIBAgIQbEVEV7LgtjVWO+qBrrmgETAKBggqhkjOPQQDAjAkMQww + CgYDVQQKEwNLb3AxFDASBgNVBAMTC0tvcCBSb290IENBMB4XDTIzMTIwODE0NTEx + N1oXDTMzMTIwNTE0NTExN1owLDEMMAoGA1UEChMDS29wMRwwGgYDVQQDExNLb3Ag + SW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEmv7jg7Cs + 4L5v52+3yUmn79hZFS2vmm/5wwcUCL63dokEXQsHgbEjaRKsF/MW0yJDLTB6Sdhl + pCvoNJqITWuEN6NmMGQwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8C + AQAwHQYDVR0OBBYEFDgVolMCmdrhDIXhuIs4q/KwRKNLMB8GA1UdIwQYMBaAFPQF + bcIqVuRwwS32UR9SmQpyCgn6MAoGCCqGSM49BAMCA0gAMEUCIQCQa01E+UvAJ8KR + DFfDducZUpW4tZRN35lqoge7T9nM2QIgK4FFt1NqDqcjOSabAXPOQ68bvdxlHW0y + AgN9qNc3Jbo= + -----END CERTIFICATE----- + ''; in { @@ -82,9 +82,9 @@ in "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" ]; - minVersion = 1.2; - maxVersion = 1.3; - renegotiation = false; + minVersion = 1.2; + maxVersion = 1.3; + renegotiation = false; }; }; }; diff --git a/modules/services/synapse.nix b/modules/services/synapse.nix index fe57755..57bc17b 100644 --- a/modules/services/synapse.nix +++ b/modules/services/synapse.nix @@ -9,7 +9,8 @@ let add_header Access-Control-Allow-Origin *; return 200 '${builtins.toJSON data}'; ''; -in { +in +{ networking.domain = "kopatz.ddns.net"; networking.firewall.allowedTCPPorts = [ 80 443 ]; @@ -59,9 +60,9 @@ in { }; age.secrets.matrix-registration = { - file = ../../secrets/matrix-registration.age; - owner = "matrix-synapse"; - group = "matrix-synapse"; + file = ../../secrets/matrix-registration.age; + owner = "matrix-synapse"; + group = "matrix-synapse"; }; services.matrix-synapse = { @@ -77,15 +78,16 @@ in { config.age.secrets.matrix-registration.path ]; settings.listeners = [ - { port = 8008; + { + port = 8008; bind_addresses = [ "::1" ]; type = "http"; tls = false; x_forwarded = true; - resources = [ { + resources = [{ names = [ "client" "federation" ]; compress = true; - } ]; + }]; } ]; }; diff --git a/modules/services/wireguard-client.nix b/modules/services/wireguard-client.nix index 8ea9c78..53211b4 100644 --- a/modules/services/wireguard-client.nix +++ b/modules/services/wireguard-client.nix @@ -6,7 +6,7 @@ }; systemd.network.networks.wg0 = { - dns = [ "192.168.2.1"]; + dns = [ "192.168.2.1" ]; }; networking.wg-quick.interfaces = { wg0 = { @@ -15,7 +15,7 @@ privateKeyFile = config.age.secrets.wireguard-client.path; listenPort = 51820; dns = [ "192.168.2.1" ]; - address = ["192.168.2.22/24"]; + address = [ "192.168.2.22/24" ]; peers = [ { #allowedIPs = [ "192.168.2.0/24" "192.168.0.0/24" ]; diff --git a/modules/services/wireguard.nix b/modules/services/wireguard.nix index 3e527e7..4f8de8b 100644 --- a/modules/services/wireguard.nix +++ b/modules/services/wireguard.nix @@ -5,109 +5,110 @@ let in { options.custom.services.wireguard = { - enable = mkEnableOption "Enables wireguard"; - ip = lib.mkOption { - default = "192.168.2.1"; - type = types.str; - description = "ipv4 address"; - }; - }; - config = -let - wireguardIp = cfg.ip; -in lib.mkIf cfg.enable { - - age.secrets.wireguard-private = { - file = ../../secrets/wireguard-private.age; - }; - - networking.nat.enable = true; - networking.nat.externalInterface = "eth0"; - networking.nat.internalInterfaces = [ "wg0" ]; - networking.firewall.allowedUDPPorts = [ 51820 ]; - - networking.wg-quick.interfaces = { - wg0 = { - autostart = true; - listenPort = 51820; - address = [ - "${wireguardIp}/24" - ]; - peers = [ - { - allowedIPs = [ - "192.168.2.2/32" - ]; - publicKey = "YgecbWSNRqOmylYqxr/V21LL3UpKEr5x42lXPAxriSc="; - } - { - allowedIPs = [ - "192.168.2.3/32" - ]; - publicKey = "Eg5ZS3zN05mJ/gct6wJlwVAHTlXpkhxFfUd7yscANV0="; - } - # detschn pc - { - allowedIPs = [ - "192.168.2.4/32" - ]; - publicKey = "8Eigfs+k2k2WPaMn+SqDmlSHdMv+I+xcBr/2qhtpGzI="; - } - # detschn laptop - { - allowedIPs = [ - "192.168.2.5/32" - ]; - publicKey = "g5uTlA1IciXgtSbECjhVis0dajRAc53Oa7Hz6dUI+0Q="; - } - { - allowedIPs = [ - "192.168.2.6/32" - ]; - publicKey = "5ClF2HcqndpXS7nVgDn2unWFUYcKo5fbudV6xX2OIVE="; - } - # handy - { - allowedIPs = [ - "192.168.2.20/32" - ]; - publicKey = "25u1RSfjsx3wb1DMeTm0pvUfUkG7zTjGaN+m0w6ZjCw="; - } - { - allowedIPs = [ - "192.168.2.21/32" - ]; - publicKey = "S+8F+yxSQvjjoU44LRYqRv1YulqmOKumUtYo/YIh7X8="; - } - # laptop - { - allowedIPs = [ - "192.168.2.22/32" - ]; - publicKey = "/dIW7K49vB9HOghFeXvcY7wu2utQltuv6RfgCbxZwlk="; - } - { - allowedIPs = [ - "192.168.2.23/32" - ]; - publicKey = "89rjQXNcyCRUCihqfqcOnctWmhiNR8snpRFF6dyHAmk="; - } - { - allowedIPs = [ - "192.168.2.24/32" - ]; - publicKey = "adaWtboVz3UhpNBKFirs7slbU2+Y3GaV5yS2EoafwVU="; - } - # raphi - { - allowedIPs = [ - "192.168.2.25/32" - ]; - publicKey = "AGBWzMeSTxmB3jwNdROYHbyiqhhAVyofMV5Ku5JIE1A="; - } - ]; - privateKeyFile = config.age.secrets.wireguard-private.path; + enable = mkEnableOption "Enables wireguard"; + ip = lib.mkOption { + default = "192.168.2.1"; + type = types.str; + description = "ipv4 address"; }; }; -}; + config = + let + wireguardIp = cfg.ip; + in + lib.mkIf cfg.enable { + + age.secrets.wireguard-private = { + file = ../../secrets/wireguard-private.age; + }; + + networking.nat.enable = true; + networking.nat.externalInterface = "eth0"; + networking.nat.internalInterfaces = [ "wg0" ]; + networking.firewall.allowedUDPPorts = [ 51820 ]; + + networking.wg-quick.interfaces = { + wg0 = { + autostart = true; + listenPort = 51820; + address = [ + "${wireguardIp}/24" + ]; + peers = [ + { + allowedIPs = [ + "192.168.2.2/32" + ]; + publicKey = "YgecbWSNRqOmylYqxr/V21LL3UpKEr5x42lXPAxriSc="; + } + { + allowedIPs = [ + "192.168.2.3/32" + ]; + publicKey = "Eg5ZS3zN05mJ/gct6wJlwVAHTlXpkhxFfUd7yscANV0="; + } + # detschn pc + { + allowedIPs = [ + "192.168.2.4/32" + ]; + publicKey = "8Eigfs+k2k2WPaMn+SqDmlSHdMv+I+xcBr/2qhtpGzI="; + } + # detschn laptop + { + allowedIPs = [ + "192.168.2.5/32" + ]; + publicKey = "g5uTlA1IciXgtSbECjhVis0dajRAc53Oa7Hz6dUI+0Q="; + } + { + allowedIPs = [ + "192.168.2.6/32" + ]; + publicKey = "5ClF2HcqndpXS7nVgDn2unWFUYcKo5fbudV6xX2OIVE="; + } + # handy + { + allowedIPs = [ + "192.168.2.20/32" + ]; + publicKey = "25u1RSfjsx3wb1DMeTm0pvUfUkG7zTjGaN+m0w6ZjCw="; + } + { + allowedIPs = [ + "192.168.2.21/32" + ]; + publicKey = "S+8F+yxSQvjjoU44LRYqRv1YulqmOKumUtYo/YIh7X8="; + } + # laptop + { + allowedIPs = [ + "192.168.2.22/32" + ]; + publicKey = "/dIW7K49vB9HOghFeXvcY7wu2utQltuv6RfgCbxZwlk="; + } + { + allowedIPs = [ + "192.168.2.23/32" + ]; + publicKey = "89rjQXNcyCRUCihqfqcOnctWmhiNR8snpRFF6dyHAmk="; + } + { + allowedIPs = [ + "192.168.2.24/32" + ]; + publicKey = "adaWtboVz3UhpNBKFirs7slbU2+Y3GaV5yS2EoafwVU="; + } + # raphi + { + allowedIPs = [ + "192.168.2.25/32" + ]; + publicKey = "AGBWzMeSTxmB3jwNdROYHbyiqhhAVyofMV5Ku5JIE1A="; + } + ]; + privateKeyFile = config.age.secrets.wireguard-private.path; + }; + }; + }; } diff --git a/modules/support/default.nix b/modules/support/default.nix index 59e291a..6d72116 100644 --- a/modules/support/default.nix +++ b/modules/support/default.nix @@ -1,4 +1,4 @@ -{ pkgs, config, ...}: +{ pkgs, config, ... }: { imports = [ diff --git a/modules/themes/tsukasa.nix b/modules/themes/tsukasa.nix index 73bd7a4..6d99ec0 100644 --- a/modules/themes/tsukasa.nix +++ b/modules/themes/tsukasa.nix @@ -1,21 +1,21 @@ { - "base00"= "201a1e"; - "base01"= "5c4133"; - "base02"= "83644f"; - "base03"= "c3955f"; - "base04"= "dab353"; - "base05"= "f4dfb4"; - "base06"= "fef1de"; - "base07"= "fef1de"; - "base08"= "ed8796"; - "base09"= "f5a97f"; - "base0A"= "eed49f"; - "base0B"= "a6da95"; - "base0C"= "8bd5ca"; - "base0D"= "8aadf4"; - "base0E"= "c6a0f6"; - "base0F"= "f0c6c6"; - "author"= "Stylix"; - "scheme"= "Stylix"; - "slug"= "stylix"; + "base00" = "201a1e"; + "base01" = "5c4133"; + "base02" = "83644f"; + "base03" = "c3955f"; + "base04" = "dab353"; + "base05" = "f4dfb4"; + "base06" = "fef1de"; + "base07" = "fef1de"; + "base08" = "ed8796"; + "base09" = "f5a97f"; + "base0A" = "eed49f"; + "base0B" = "a6da95"; + "base0C" = "8bd5ca"; + "base0D" = "8aadf4"; + "base0E" = "c6a0f6"; + "base0F" = "f0c6c6"; + "author" = "Stylix"; + "scheme" = "Stylix"; + "slug" = "stylix"; } diff --git a/modules/vmware-host.nix b/modules/vmware-host.nix index ed881ea..cca8542 100644 --- a/modules/vmware-host.nix +++ b/modules/vmware-host.nix @@ -1,3 +1,3 @@ { - virtualisation.vmware.host.enable = true; + virtualisation.vmware.host.enable = true; } diff --git a/overlays.nix b/overlays.nix index 741d031..6eb6ca0 100644 --- a/overlays.nix +++ b/overlays.nix @@ -3,12 +3,13 @@ let addPatches = pkg: patches: pkg.overrideAttrs - (oldAttrs: { patches = (oldAttrs.patches or [ ]) ++ patches; }); - mesa-git = import inputs.nixpkgs-mesa-git { - system = "x86_64-linux"; - config.allowUnfree = true; - }; -in { + (oldAttrs: { patches = (oldAttrs.patches or [ ]) ++ patches; }); + mesa-git = import inputs.nixpkgs-mesa-git { + system = "x86_64-linux"; + config.allowUnfree = true; + }; +in +{ # This one brings our custom packages from the 'pkgs' directory additions = final: _prev: import ./pkgs { pkgs = final; }; diff --git a/pkgs/adam-site/default.nix b/pkgs/adam-site/default.nix index e61107d..6349c8e 100644 --- a/pkgs/adam-site/default.nix +++ b/pkgs/adam-site/default.nix @@ -8,7 +8,7 @@ buildNpmPackage rec { ref = "main"; rev = "6575c418f45aef025d2d89d5b0b4ff4fbdffe298"; }; - npmDepsHash="sha256-PRFHBlVIdHfATAAKVKax+bY4o+9czdfl7HjFnKk4KtI="; + npmDepsHash = "sha256-PRFHBlVIdHfATAAKVKax+bY4o+9czdfl7HjFnKk4KtI="; installPhase = '' mkdir -p $out cp -r ./dist/adams-site/* $out diff --git a/pkgs/electron27/default.nix b/pkgs/electron27/default.nix index 0123155..ab10772 100644 --- a/pkgs/electron27/default.nix +++ b/pkgs/electron27/default.nix @@ -1,7 +1,33 @@ -{ lib, stdenv, libXScrnSaver, makeWrapper, fetchurl, wrapGAppsHook3, glib, gtk3 -, unzip, at-spi2-atk, libdrm, libgbm, libxkbcommon, libxshmfence, libGL -, vulkan-loader, alsa-lib, cairo, cups, dbus, expat, gdk-pixbuf, nss, nspr, xorg -, pango, systemd, pciutils, }: +{ lib +, stdenv +, libXScrnSaver +, makeWrapper +, fetchurl +, wrapGAppsHook3 +, glib +, gtk3 +, unzip +, at-spi2-atk +, libdrm +, libgbm +, libxkbcommon +, libxshmfence +, libGL +, vulkan-loader +, alsa-lib +, cairo +, cups +, dbus +, expat +, gdk-pixbuf +, nss +, nspr +, xorg +, pango +, systemd +, pciutils +, +}: let version = "27.3.11"; @@ -96,13 +122,13 @@ let stdenv.cc.cc systemd ] ++ lib.optionals (lib.versionAtLeast version "9.0.0") [ libdrm libgbm ] - ++ lib.optionals (lib.versionOlder version "10.0.0") [ libXScrnSaver ] - ++ lib.optionals (lib.versionAtLeast version "11.0.0") [ libxkbcommon ] - ++ lib.optionals (lib.versionAtLeast version "12.0.0") [ libxshmfence ] - ++ lib.optionals (lib.versionAtLeast version "17.0.0") [ - libGL - vulkan-loader - ]); + ++ lib.optionals (lib.versionOlder version "10.0.0") [ libXScrnSaver ] + ++ lib.optionals (lib.versionAtLeast version "11.0.0") [ libxkbcommon ] + ++ lib.optionals (lib.versionAtLeast version "12.0.0") [ libxshmfence ] + ++ lib.optionals (lib.versionAtLeast version "17.0.0") [ + libGL + vulkan-loader + ]); linux = finalAttrs: { buildInputs = [ glib gtk3 ]; @@ -157,6 +183,7 @@ let passthru.dist = finalAttrs.finalPackage + "/Applications"; }; -in stdenv.mkDerivation (finalAttrs: - lib.recursiveUpdate (common stdenv.hostPlatform) +in +stdenv.mkDerivation (finalAttrs: +lib.recursiveUpdate (common stdenv.hostPlatform) ((if stdenv.hostPlatform.isDarwin then darwin else linux) finalAttrs)) diff --git a/pkgs/lact/default.nix b/pkgs/lact/default.nix index 6c57dc2..e8b59c5 100644 --- a/pkgs/lact/default.nix +++ b/pkgs/lact/default.nix @@ -1,6 +1,19 @@ -{ lib, rustPlatform, stdenv, fetchFromGitHub, blueprint-compiler, pkg-config -, wrapGAppsHook4, gdk-pixbuf, gtk4, libdrm, vulkan-loader, coreutils -, nix-update-script, hwdata, fuse }: +{ lib +, rustPlatform +, stdenv +, fetchFromGitHub +, blueprint-compiler +, pkg-config +, wrapGAppsHook4 +, gdk-pixbuf +, gtk4 +, libdrm +, vulkan-loader +, coreutils +, nix-update-script +, hwdata +, fuse +}: rustPlatform.buildRustPackage rec { pname = "lact"; diff --git a/pkgs/mangal/default.nix b/pkgs/mangal/default.nix index a32cca9..bd5755b 100644 --- a/pkgs/mangal/default.nix +++ b/pkgs/mangal/default.nix @@ -1,9 +1,9 @@ -{ - lib, - stdenv, - buildGoModule, - fetchFromGitHub, - installShellFiles, +{ lib +, stdenv +, buildGoModule +, fetchFromGitHub +, installShellFiles +, }: buildGoModule rec { name = "mangal"; diff --git a/pkgs/sddm-astronaut/default.nix b/pkgs/sddm-astronaut/default.nix index 9217280..fa7a863 100644 --- a/pkgs/sddm-astronaut/default.nix +++ b/pkgs/sddm-astronaut/default.nix @@ -1,15 +1,15 @@ { pkgs }: pkgs.stdenv.mkDerivation { - name = "sddm-astronaut-theme"; - src = pkgs.fetchFromGitHub { - owner = "totoro-ghost"; - repo = "sddm-astronaut"; - hash = "sha256-j8pJvBml2LWxXNw1e/cSVXV+6w+K1lahv0uK1B9OYn0="; - rev = "6726b5e951a13d308bf17aa09e91a349d82c997b"; - }; - installPhase = '' - mkdir -p $out - cp -R ./* $out/ - ''; + name = "sddm-astronaut-theme"; + src = pkgs.fetchFromGitHub { + owner = "totoro-ghost"; + repo = "sddm-astronaut"; + hash = "sha256-j8pJvBml2LWxXNw1e/cSVXV+6w+K1lahv0uK1B9OYn0="; + rev = "6726b5e951a13d308bf17aa09e91a349d82c997b"; + }; + installPhase = '' + mkdir -p $out + cp -R ./* $out/ + ''; } diff --git a/systems/adam-site/disk-config.nix b/systems/adam-site/disk-config.nix index d245ca6..75ae234 100644 --- a/systems/adam-site/disk-config.nix +++ b/systems/adam-site/disk-config.nix @@ -6,7 +6,7 @@ device = lib.mkDefault "/dev/sda"; type = "disk"; content = { - type = "gpt"; + type = "gpt"; partitions = { boot = { name = "boot"; diff --git a/systems/amd-server-vm/configuration.nix b/systems/amd-server-vm/configuration.nix index 475fe39..150ca38 100644 --- a/systems/amd-server-vm/configuration.nix +++ b/systems/amd-server-vm/configuration.nix @@ -1,7 +1,8 @@ { config, pkgs, modulesPath, lib, ... }: { - imports = [ # Include the results of the hardware scan. + imports = [ + # Include the results of the hardware scan. #./hardware-configuration.nix ../../modules/services/ssh.nix ../../modules/services/step-ca.nix @@ -45,22 +46,24 @@ }; misc = { docker.enable = true; - backup = let - kavita = "/data/kavita"; - gitolite = "/var/lib/gitolite"; - syncthing = [ "/data/synced/default/" "/data/synced/work_drive/" ]; - syncthingFull = syncthing - ++ [ "/data/synced/fh/" "/data/synced/books/" ]; - backupPathsSmall = [ "/home" gitolite ] ++ syncthing; - backupPathsMedium = [ "/home" gitolite ] ++ syncthing; - backupPathsFull = [ "/home" kavita gitolite ] ++ syncthingFull; - in { - enable = true; - excludePaths = lib.mkOptionDefault [ "${kavita}/manga" ]; - small = backupPathsSmall; # goes to backblaze - medium = backupPathsMedium; # goes to gdrive - large = backupPathsFull; # goes to local storage medium - }; + backup = + let + kavita = "/data/kavita"; + gitolite = "/var/lib/gitolite"; + syncthing = [ "/data/synced/default/" "/data/synced/work_drive/" ]; + syncthingFull = syncthing + ++ [ "/data/synced/fh/" "/data/synced/books/" ]; + backupPathsSmall = [ "/home" gitolite ] ++ syncthing; + backupPathsMedium = [ "/home" gitolite ] ++ syncthing; + backupPathsFull = [ "/home" kavita gitolite ] ++ syncthingFull; + in + { + enable = true; + excludePaths = lib.mkOptionDefault [ "${kavita}/manga" ]; + small = backupPathsSmall; # goes to backblaze + medium = backupPathsMedium; # goes to gdrive + large = backupPathsFull; # goes to local storage medium + }; }; services = { acme.enable = true; diff --git a/systems/amd-server/configuration.nix b/systems/amd-server/configuration.nix index b8fc557..3625827 100644 --- a/systems/amd-server/configuration.nix +++ b/systems/amd-server/configuration.nix @@ -5,7 +5,8 @@ { config, lib, pkgs, ... }: { - imports = [ # Include the results of the hardware scan. + imports = [ + # Include the results of the hardware scan. ./hardware-configuration.nix ../../modules/kernel.nix ../../modules/services/ssh.nix diff --git a/systems/laptop/configuration.nix b/systems/laptop/configuration.nix index 843b4aa..0942f65 100644 --- a/systems/laptop/configuration.nix +++ b/systems/laptop/configuration.nix @@ -1,5 +1,6 @@ { config, pkgs, inputs, ... }: { - imports = [ # Include the results of the hardware scan. + imports = [ + # Include the results of the hardware scan. ./hardware-configuration.nix ./modules/battery.nix ../../modules/ecryptfs.nix @@ -86,19 +87,21 @@ # "d /docker-data 0755 kopatz users" #]; - security.pki.certificates = ['' - -----BEGIN CERTIFICATE----- - MIIBjTCCATKgAwIBAgIRAMVH2+JHZ3wm2fLUlKjTYDswCgYIKoZIzj0EAwIwJDEM - MAoGA1UEChMDS29wMRQwEgYDVQQDEwtLb3AgUm9vdCBDQTAeFw0yMzEyMDgxNDUx - MTZaFw0zMzEyMDUxNDUxMTZaMCQxDDAKBgNVBAoTA0tvcDEUMBIGA1UEAxMLS29w - IFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATdZBOkNynShXipzhuX - f6dUByD3chNupNWsagYC5AlPRJT9fAeHEIK/bxWkFwRtLBDopWvBu9lHahBgpHc7 - y7rTo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNV - HQ4EFgQU9AVtwipW5HDBLfZRH1KZCnIKCfowCgYIKoZIzj0EAwIDSQAwRgIhAMHj - AipNdhQKIYPvMt/h1uW4xP3NTkitnmshM09+rIasAiEAlSalGddXDkqJBHhPD+Fr - gpuVkfVkA8gQCXNs5F9TnxA= - -----END CERTIFICATE----- - '']; + security.pki.certificates = [ + '' + -----BEGIN CERTIFICATE----- + MIIBjTCCATKgAwIBAgIRAMVH2+JHZ3wm2fLUlKjTYDswCgYIKoZIzj0EAwIwJDEM + MAoGA1UEChMDS29wMRQwEgYDVQQDEwtLb3AgUm9vdCBDQTAeFw0yMzEyMDgxNDUx + MTZaFw0zMzEyMDUxNDUxMTZaMCQxDDAKBgNVBAoTA0tvcDEUMBIGA1UEAxMLS29w + IFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATdZBOkNynShXipzhuX + f6dUByD3chNupNWsagYC5AlPRJT9fAeHEIK/bxWkFwRtLBDopWvBu9lHahBgpHc7 + y7rTo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNV + HQ4EFgQU9AVtwipW5HDBLfZRH1KZCnIKCfowCgYIKoZIzj0EAwIDSQAwRgIhAMHj + AipNdhQKIYPvMt/h1uW4xP3NTkitnmshM09+rIasAiEAlSalGddXDkqJBHhPD+Fr + gpuVkfVkA8gQCXNs5F9TnxA= + -----END CERTIFICATE----- + '' + ]; system.stateVersion = "23.05"; # Did you read the comment? } diff --git a/systems/laptop/hardware-configuration.nix b/systems/laptop/hardware-configuration.nix index a27a721..3de00ab 100644 --- a/systems/laptop/hardware-configuration.nix +++ b/systems/laptop/hardware-configuration.nix @@ -5,7 +5,8 @@ { imports = - [ (modulesPath + "/installer/scan/not-detected.nix") + [ + (modulesPath + "/installer/scan/not-detected.nix") ]; boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "nvme" "usb_storage" "uas" "sd_mod" "rtsx_pci_sdmmc" ]; @@ -14,18 +15,19 @@ boot.extraModulePackages = [ ]; fileSystems."/" = - { device = "/dev/disk/by-uuid/10537ea5-9d9f-4be8-8509-c7f9c9b978b8"; + { + device = "/dev/disk/by-uuid/10537ea5-9d9f-4be8-8509-c7f9c9b978b8"; fsType = "ext4"; }; fileSystems."/boot" = - { device = "/dev/disk/by-uuid/C163-6BD5"; + { + device = "/dev/disk/by-uuid/C163-6BD5"; fsType = "vfat"; }; swapDevices = - [ { device = "/dev/disk/by-uuid/3ef4829c-e9ea-4cc0-85a1-bd8e704b9940"; } - ]; + [{ device = "/dev/disk/by-uuid/3ef4829c-e9ea-4cc0-85a1-bd8e704b9940"; }]; # Enables DHCP on each ethernet and wireless interface. In case of scripted networking # (the default) this is the recommended approach. When using systemd-networkd it's diff --git a/systems/mini-pc-proxmox/configuration.nix b/systems/mini-pc-proxmox/configuration.nix index d4117e1..e74173f 100644 --- a/systems/mini-pc-proxmox/configuration.nix +++ b/systems/mini-pc-proxmox/configuration.nix @@ -5,7 +5,8 @@ { config, pkgs, modulesPath, lib, ... }: { - imports = [ # Include the results of the hardware scan. + imports = [ + # Include the results of the hardware scan. ./hardware-configuration.nix ../../modules/services/ssh.nix ../../modules/services/step-ca.nix @@ -47,21 +48,23 @@ }; misc = { docker.enable = true; - backup = let - kavita = "/data/kavita"; - gitolite = "/var/lib/gitolite"; - syncthing = [ "/data/synced/default/" "/data/synced/work_drive/" ]; - syncthingFull = syncthing - ++ [ "/data/synced/fh/" "/data/synced/books/" ]; - backupPathsSmall = [ "/home" gitolite ] ++ syncthing; - backupPathsMedium = [ "/home" gitolite ] ++ syncthing; - backupPathsFull = [ "/home" kavita gitolite ] ++ syncthingFull; - in { - enable = true; - small = backupPathsSmall; # goes to backblaze - medium = backupPathsMedium; # goes to gdrive - large = backupPathsFull; # goes to local storage medium - }; + backup = + let + kavita = "/data/kavita"; + gitolite = "/var/lib/gitolite"; + syncthing = [ "/data/synced/default/" "/data/synced/work_drive/" ]; + syncthingFull = syncthing + ++ [ "/data/synced/fh/" "/data/synced/books/" ]; + backupPathsSmall = [ "/home" gitolite ] ++ syncthing; + backupPathsMedium = [ "/home" gitolite ] ++ syncthing; + backupPathsFull = [ "/home" kavita gitolite ] ++ syncthingFull; + in + { + enable = true; + small = backupPathsSmall; # goes to backblaze + medium = backupPathsMedium; # goes to gdrive + large = backupPathsFull; # goes to local storage medium + }; }; services = { acme.enable = true; diff --git a/systems/mini-pc-proxmox/hardware-configuration.nix b/systems/mini-pc-proxmox/hardware-configuration.nix index 5faef13..445a884 100644 --- a/systems/mini-pc-proxmox/hardware-configuration.nix +++ b/systems/mini-pc-proxmox/hardware-configuration.nix @@ -5,13 +5,15 @@ { fileSystems."/data" = - { device = "/dev/disk/by-uuid/d117419d-fce9-4d52-85c7-e3481feaa22a"; + { + device = "/dev/disk/by-uuid/d117419d-fce9-4d52-85c7-e3481feaa22a"; fsType = "btrfs"; options = [ "compress=zstd" "noatime" "nofail" ]; }; fileSystems."/1tbssd" = - { device = "/dev/disk/by-uuid/801d9217-9c38-4ca8-914e-e31361603892"; + { + device = "/dev/disk/by-uuid/801d9217-9c38-4ca8-914e-e31361603892"; fsType = "ext4"; - options = ["defaults" "nofail" "noatime"]; + options = [ "defaults" "nofail" "noatime" ]; }; - } +} diff --git a/systems/mini-pc/configuration.nix b/systems/mini-pc/configuration.nix index 64adb8b..f3eca82 100644 --- a/systems/mini-pc/configuration.nix +++ b/systems/mini-pc/configuration.nix @@ -5,7 +5,8 @@ { config, pkgs, ... }: { - imports = [ # Include the results of the hardware scan. + imports = [ + # Include the results of the hardware scan. ./hardware-configuration.nix ../../modules/services/ssh.nix ../../modules/services/step-ca.nix @@ -38,20 +39,22 @@ misc = { btrfs.enable = true; docker.enable = true; - backup = let - kavita = "/data/kavita"; - gitolite = "/var/lib/gitolite"; - syncthing = [ "/synced/default/" "/synced/work_drive/" ]; - syncthingFull = syncthing ++ [ "/synced/fh/" "/synced/books/" ]; - backupPathsSmall = [ "/home" gitolite ] ++ syncthing; - backupPathsMedium = [ "/home" gitolite ] ++ syncthing; - backupPathsFull = [ "/home" kavita gitolite ] ++ syncthingFull; - in { - enable = true; - small = backupPathsSmall; # goes to backblaze - medium = backupPathsMedium; # goes to gdrive - large = backupPathsFull; # goes to local storage medium - }; + backup = + let + kavita = "/data/kavita"; + gitolite = "/var/lib/gitolite"; + syncthing = [ "/synced/default/" "/synced/work_drive/" ]; + syncthingFull = syncthing ++ [ "/synced/fh/" "/synced/books/" ]; + backupPathsSmall = [ "/home" gitolite ] ++ syncthing; + backupPathsMedium = [ "/home" gitolite ] ++ syncthing; + backupPathsFull = [ "/home" kavita gitolite ] ++ syncthingFull; + in + { + enable = true; + small = backupPathsSmall; # goes to backblaze + medium = backupPathsMedium; # goes to gdrive + large = backupPathsFull; # goes to local storage medium + }; }; services = { acme.enable = true; diff --git a/systems/mini-pc/hardware-configuration.nix b/systems/mini-pc/hardware-configuration.nix index 8ecbaf7..cd60b2c 100644 --- a/systems/mini-pc/hardware-configuration.nix +++ b/systems/mini-pc/hardware-configuration.nix @@ -5,7 +5,8 @@ { imports = - [ (modulesPath + "/installer/scan/not-detected.nix") + [ + (modulesPath + "/installer/scan/not-detected.nix") ]; boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "ehci_pci" "nvme" "usbhid" "usb_storage" "sd_mod" ]; @@ -14,7 +15,8 @@ boot.extraModulePackages = [ ]; fileSystems."/" = - { device = "/dev/disk/by-uuid/193dfa08-bf89-4a8b-a159-592c0a0b4d6e"; + { + device = "/dev/disk/by-uuid/193dfa08-bf89-4a8b-a159-592c0a0b4d6e"; fsType = "ext4"; options = [ "defaults" @@ -23,25 +25,27 @@ }; fileSystems."/boot" = - { device = "/dev/disk/by-uuid/EEC1-C78B"; + { + device = "/dev/disk/by-uuid/EEC1-C78B"; fsType = "vfat"; options = [ "fmask=0022" "dmask=0022" ]; }; fileSystems."/data" = - { device = "/dev/disk/by-uuid/d117419d-fce9-4d52-85c7-e3481feaa22a"; + { + device = "/dev/disk/by-uuid/d117419d-fce9-4d52-85c7-e3481feaa22a"; fsType = "btrfs"; options = [ "compress=zstd" "noatime" "nofail" ]; }; fileSystems."/1tbssd" = - { device = "/dev/disk/by-uuid/801d9217-9c38-4ca8-914e-e31361603892"; + { + device = "/dev/disk/by-uuid/801d9217-9c38-4ca8-914e-e31361603892"; fsType = "ext4"; - options = ["defaults" "nofail" "noatime"]; + options = [ "defaults" "nofail" "noatime" ]; }; swapDevices = - [ { device = "/dev/disk/by-uuid/af6bf3d5-07a4-4139-9464-ffc1c4e23549"; } - ]; + [{ device = "/dev/disk/by-uuid/af6bf3d5-07a4-4139-9464-ffc1c4e23549"; }]; # Enables DHCP on each ethernet and wireless interface. In case of scripted networking # (the default) this is the recommended approach. When using systemd-networkd it's diff --git a/systems/pc/configuration.nix b/systems/pc/configuration.nix index c7a894f..88e846d 100644 --- a/systems/pc/configuration.nix +++ b/systems/pc/configuration.nix @@ -3,7 +3,8 @@ # and in the NixOS manual (accessible by running ‘nixos-help’). { config, pkgs, lib, inputs, ... }: { - imports = [ # Include the results of the hardware scan. + imports = [ + # Include the results of the hardware scan. ./hardware-configuration.nix ../../modules/flatpak.nix ../../modules/gpg.nix @@ -220,19 +221,21 @@ # Allow unfree packages nixpkgs.config.allowUnfree = true; - security.pki.certificates = ['' - -----BEGIN CERTIFICATE----- - MIIBjTCCATKgAwIBAgIRAMVH2+JHZ3wm2fLUlKjTYDswCgYIKoZIzj0EAwIwJDEM - MAoGA1UEChMDS29wMRQwEgYDVQQDEwtLb3AgUm9vdCBDQTAeFw0yMzEyMDgxNDUx - MTZaFw0zMzEyMDUxNDUxMTZaMCQxDDAKBgNVBAoTA0tvcDEUMBIGA1UEAxMLS29w - IFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATdZBOkNynShXipzhuX - f6dUByD3chNupNWsagYC5AlPRJT9fAeHEIK/bxWkFwRtLBDopWvBu9lHahBgpHc7 - y7rTo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNV - HQ4EFgQU9AVtwipW5HDBLfZRH1KZCnIKCfowCgYIKoZIzj0EAwIDSQAwRgIhAMHj - AipNdhQKIYPvMt/h1uW4xP3NTkitnmshM09+rIasAiEAlSalGddXDkqJBHhPD+Fr - gpuVkfVkA8gQCXNs5F9TnxA= - -----END CERTIFICATE----- - '']; + security.pki.certificates = [ + '' + -----BEGIN CERTIFICATE----- + MIIBjTCCATKgAwIBAgIRAMVH2+JHZ3wm2fLUlKjTYDswCgYIKoZIzj0EAwIwJDEM + MAoGA1UEChMDS29wMRQwEgYDVQQDEwtLb3AgUm9vdCBDQTAeFw0yMzEyMDgxNDUx + MTZaFw0zMzEyMDUxNDUxMTZaMCQxDDAKBgNVBAoTA0tvcDEUMBIGA1UEAxMLS29w + IFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATdZBOkNynShXipzhuX + f6dUByD3chNupNWsagYC5AlPRJT9fAeHEIK/bxWkFwRtLBDopWvBu9lHahBgpHc7 + y7rTo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNV + HQ4EFgQU9AVtwipW5HDBLfZRH1KZCnIKCfowCgYIKoZIzj0EAwIDSQAwRgIhAMHj + AipNdhQKIYPvMt/h1uW4xP3NTkitnmshM09+rIasAiEAlSalGddXDkqJBHhPD+Fr + gpuVkfVkA8gQCXNs5F9TnxA= + -----END CERTIFICATE----- + '' + ]; # This value determines the NixOS release from which the default # settings for stateful data, like file locations and database versions diff --git a/systems/pc/hardware-configuration.nix b/systems/pc/hardware-configuration.nix index 1c214a4..5f21846 100644 --- a/systems/pc/hardware-configuration.nix +++ b/systems/pc/hardware-configuration.nix @@ -5,7 +5,8 @@ { imports = - [ (modulesPath + "/installer/scan/not-detected.nix") + [ + (modulesPath + "/installer/scan/not-detected.nix") ]; boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" "usbhid" "usb_storage" "sd_mod" ]; @@ -14,7 +15,8 @@ boot.extraModulePackages = [ ]; fileSystems."/" = - { device = "/dev/disk/by-uuid/dd65bdf8-c003-439c-a1aa-d050cb20959d"; + { + device = "/dev/disk/by-uuid/dd65bdf8-c003-439c-a1aa-d050cb20959d"; fsType = "ext4"; options = [ "defaults" @@ -23,7 +25,8 @@ }; fileSystems."/boot" = - { device = "/dev/disk/by-uuid/CC7C-CF82"; + { + device = "/dev/disk/by-uuid/CC7C-CF82"; fsType = "vfat"; }; diff --git a/systems/proxmox-test-vm/disk-config.nix b/systems/proxmox-test-vm/disk-config.nix index 0625d3c..7b8045b 100644 --- a/systems/proxmox-test-vm/disk-config.nix +++ b/systems/proxmox-test-vm/disk-config.nix @@ -6,7 +6,7 @@ device = lib.mkDefault "/dev/sda"; type = "disk"; content = { - type = "gpt"; + type = "gpt"; partitions = { boot = { name = "boot"; diff --git a/systems/userdata-default.nix b/systems/userdata-default.nix index 0db3279..ffcd441 100644 --- a/systems/userdata-default.nix +++ b/systems/userdata-default.nix @@ -1,3 +1 @@ -{ - -} +{ } diff --git a/systems/wsl/configuration.nix b/systems/wsl/configuration.nix index 58e149b..c0feeb3 100644 --- a/systems/wsl/configuration.nix +++ b/systems/wsl/configuration.nix @@ -5,12 +5,12 @@ # NixOS-WSL specific options are documented on the NixOS-WSL repository: # https://github.com/nix-community/NixOS-WSL -{ config, lib, pkgs, inputs, ... } : #nixos-wsl, ... }: +{ config, lib, pkgs, inputs, ... }: #nixos-wsl, ... }: { imports = [ # include NixOS-WSL modules -# + # ]; wsl = { @@ -20,7 +20,7 @@ wslConf = { automount.root = "/mnt"; user.default = lib.mkForce "anon"; - interop = { enabled = false; appendWindowsPath = false;}; + interop = { enabled = false; appendWindowsPath = false; }; }; }; @@ -32,7 +32,7 @@ }; nix.settings.trusted-substituters = [ "https://ai.cachix.org" ]; nix.settings.trusted-public-keys = [ "ai.cachix.org-1:N9dzRK+alWwoKXQlnn0H6aUx0lU/mspIoz8hMvGvbbc=" ]; - nix.settings.experimental-features = [ "nix-command" "flakes" ]; + nix.settings.experimental-features = [ "nix-command" "flakes" ]; environment.systemPackages = with pkgs; [ openssh diff --git a/users/anon/default.nix b/users/anon/default.nix index 8b69735..4275133 100644 --- a/users/anon/default.nix +++ b/users/anon/default.nix @@ -5,7 +5,7 @@ , ... }: { - imports = [ ../default.nix ]; + imports = [ ../default.nix ]; mainUser.name = "anon"; mainUser.sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFeP6qtVqE/gu72ZUZE8cdRi3INiUW9NqDR7SjXIzTw2 kopatz"; @@ -19,7 +19,7 @@ description = config.mainUser.name; shell = pkgs.zsh; initialPassword = "cooltemporarypw"; - extraGroups = [ "networkmanager" "wheel" "docker" "wireshark"]; + extraGroups = [ "networkmanager" "wheel" "docker" "wireshark" ]; openssh.authorizedKeys.keys = [ config.mainUser.sshKey "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCuRAKtoU5rjSbjDxlac6oAww/XHgsVRFHwIVnVm/TrTtDNqRyAkr6fIUiSKTHrpBPyJjIKCzkHS8QhbS2zZo4wjcgAyMyK33q/CzLs8DPQMWX0RKxR+OaVNwh90iWHr663a5x7ztTag3oPGOAYjeqCoIJWyQRlvIKflriJnAjWE8nvw4QkErpRWo4JJnhS61GQMrPT6VK0yXzq3zQs2t3cXTvGMmeLjBuluvJ6yiDk2bAGdY2UWnbs1y2M1TD3xn0pHzITeQnoWLfy+cwPHnEulciVqyr4pp6LDygmIPI1rxKAIQUnwo09n/A1eIcqlUo8aKy7ZDyrssuGWKZ/U4FC258NWwdUPbjyQvzNdcZjXC4+AmQTb+DwiECYOCfF7O/uRRqoFl7jfVfKqHJ7DKebt20QKwDCH/d5qfDs6xA0Krl2dgu3vePhsOkmpnIfPk9Cxl+YHGfmpCOVQHhxCwpkQs0Oh7NerO3idnG1enckjCuzCotnL8vDhczdL4eZmus= kopatz@nix-laptop" diff --git a/users/anon/home.nix b/users/anon/home.nix index 2d0cd28..65ab213 100644 --- a/users/anon/home.nix +++ b/users/anon/home.nix @@ -1,4 +1,4 @@ -{ config, pkgs, inputs, ...}: +{ config, pkgs, inputs, ... }: { home = { # This value determines the Home Manager release that your diff --git a/users/default.nix b/users/default.nix index e38c1c4..8bdc611 100644 --- a/users/default.nix +++ b/users/default.nix @@ -5,7 +5,7 @@ , ... }: { - imports = [ ./option.nix ]; + imports = [ ./option.nix ]; environment.systemPackages = [ pkgs.home-manager ]; home-manager = { @@ -18,6 +18,6 @@ }; users.users.root = { - openssh.authorizedKeys.keys = [ config.mainUser.sshKey ]; + openssh.authorizedKeys.keys = [ config.mainUser.sshKey ]; }; } diff --git a/users/kopatz/default.nix b/users/kopatz/default.nix index 81948cb..599a270 100644 --- a/users/kopatz/default.nix +++ b/users/kopatz/default.nix @@ -5,7 +5,7 @@ , ... }: { - imports = [ ../default.nix ]; + imports = [ ../default.nix ]; mainUser.name = "kopatz"; mainUser.sshKey = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFeP6qtVqE/gu72ZUZE8cdRi3INiUW9NqDR7SjXIzTw2 kopatz"; environment.sessionVariables = { diff --git a/users/option.nix b/users/option.nix index 3c5bd75..b7d9f00 100644 --- a/users/option.nix +++ b/users/option.nix @@ -1,4 +1,4 @@ -{lib, config, pkgs, ...}: +{ lib, config, pkgs, ... }: { options = { mainUser = {