summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--flake.lock1
-rw-r--r--flake.nix60
-rw-r--r--home/baseline/default.nix67
-rw-r--r--home/baseline/git.nix16
-rw-r--r--home/baseline/graphics.nix76
-rw-r--r--home/baseline/nvim.nix29
-rw-r--r--home/baseline/zsh.nix20
-rw-r--r--home/baseline/zshrc.nix69
-rw-r--r--home/default.nix13
-rw-r--r--home/desktop/default.nix18
-rw-r--r--home/desktop/firefox.nix34
-rw-r--r--home/desktop/sway.nix115
-rw-r--r--home/environ/default.nix17
-rw-r--r--home/environ/gpg.nix37
-rw-r--r--home/environ/pass.nix33
-rw-r--r--home/environ/path.nix55
-rw-r--r--home/environ/source.nix27
-rw-r--r--home/environ/ssh-match.nix1
-rw-r--r--home/environ/ssh.nix27
-rw-r--r--home/environ/tmux.nix45
-rw-r--r--home/environ/units.nix37
-rw-r--r--home/environ/vtmp.nix23
-rw-r--r--home/isolation/default.nix37
-rw-r--r--home/pim/.gitignore1
-rw-r--r--home/pim/0001-gnutls-add-support-for-client-key-URLs-separate-from.patch48
-rw-r--r--home/pim/0002-gnutls-implement-token-insertion-and-PKCS-11-PIN-pro.patch126
-rw-r--r--home/pim/dav.nix54
-rw-r--r--home/pim/default.nix7
-rw-r--r--home/pim/mail.nix1
-rw-r--r--home/pim/sieve/mail.sieve1
-rw-r--r--home/pim/syncthing.nix18
-rw-r--r--home/platform/README.md1
-rw-r--r--home/profiles/README.md1
-rw-r--r--home/shenvs/README.md1
-rw-r--r--hooks/README2
-rwxr-xr-xhooks/lib/update-zone-serials8
-rwxr-xr-xhooks/pre-commit8
-rw-r--r--pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch25
-rw-r--r--pkgs/athena-bccr/LaunchGaudi.java12
-rw-r--r--pkgs/athena-bccr/default.nix30
-rw-r--r--pkgs/athena-bccr/firmador.nix57
-rw-r--r--pkgs/athena-bccr/gaudi-env.nix62
-rw-r--r--pkgs/athena-bccr/releases.nix12
-rw-r--r--pkgs/athena-bccr/unwrapped.nix226
-rwxr-xr-xpkgs/btclone/btclone.nix108
-rw-r--r--pkgs/btclone/default.nix11
-rw-r--r--pkgs/cocotb/default.nix19
-rw-r--r--pkgs/cocotb/exts/wishbone.nix25
-rw-r--r--pkgs/config/default.nix4
-rw-r--r--pkgs/config/unfree.nix1
-rw-r--r--pkgs/default.nix95
-rw-r--r--pkgs/dreame-vacuum.nix40
-rw-r--r--pkgs/find-libpython.nix15
-rw-r--r--pkgs/force-riscv/default.nix72
-rw-r--r--pkgs/force-riscv/imageio-include-string.patch12
-rw-r--r--pkgs/force-riscv/remove-pyeval-initthreads.patch12
-rw-r--r--pkgs/force-riscv/testio-include-string.patch12
-rw-r--r--pkgs/force-riscv/urbg-static-constexpr-min-max.patch15
-rw-r--r--pkgs/force-riscv/wno-error-range-loop-construct.patch13
-rw-r--r--pkgs/gem5.nix66
-rw-r--r--pkgs/git-aliases.nix107
-rw-r--r--pkgs/hdl-convertor/0001-to.verilog-fix-always_ff-sensitivity-list.patch25
-rw-r--r--pkgs/hdl-convertor/0002-to.hdl_ast_-visit-sensitivity-lists.patch39
-rw-r--r--pkgs/hdl-convertor/ast.nix22
-rw-r--r--pkgs/hdl-convertor/default.nix45
-rw-r--r--pkgs/iced-x86/0001-add-Cargo.lock.patch325
-rw-r--r--pkgs/iced-x86/Cargo.lock306
-rw-r--r--pkgs/iced-x86/default.nix36
-rw-r--r--pkgs/increment-zone-serials/default.nix18
-rwxr-xr-xpkgs/increment-zone-serials/increment-zone-serials.py48
-rw-r--r--pkgs/kbuild-standalone.nix36
-rw-r--r--pkgs/lib/default.nix3
-rw-r--r--pkgs/lib/importAll.nix20
-rw-r--r--pkgs/lovelace-xiaomi-vacuum-map-card/0001-Fix-error-during-rollup-c.patch25
-rw-r--r--pkgs/lovelace-xiaomi-vacuum-map-card/default.nix39
-rw-r--r--pkgs/lovelace-xiaomi-vacuum-map-card/package-lock.json6214
-rw-r--r--pkgs/msmtp/0001-msmtp-run-passwordeval-if-tls_key_file-is-provided-e.patch26
-rw-r--r--pkgs/msmtp/default.nix151
-rw-r--r--pkgs/msmtp/paths.patch64
-rw-r--r--pkgs/mssql-tools.nix55
-rw-r--r--pkgs/oregano/check-cfg-gio-unix.patch12
-rw-r--r--pkgs/oregano/default.nix75
-rwxr-xr-xpkgs/pass-bcr/bcr.bash25
-rw-r--r--pkgs/pass-bcr/completions/bash8
-rw-r--r--pkgs/pass-bcr/completions/zsh8
-rw-r--r--pkgs/pass-bcr/default.nix19
-rw-r--r--pkgs/pass-tail/default.nix25
-rw-r--r--pkgs/postfix/0001-smtpd-implement-CCERTS-action-for-access-5-tables.patch55
-rw-r--r--pkgs/postfix/default.nix9
-rw-r--r--pkgs/py-mini-racer.nix20
-rw-r--r--pkgs/rqlite.nix21
-rw-r--r--pkgs/rv8.nix55
-rw-r--r--pkgs/scripts/clip.nix50
-rw-r--r--pkgs/scripts/default.nix13
-rw-r--r--pkgs/scripts/merge-pdfs.nix38
-rw-r--r--pkgs/simple-scalar/0001-fix-case-of-YY_CURRENT_BUFFER.patch25
-rw-r--r--pkgs/simple-scalar/0002-define-sys_nerr.patch24
-rw-r--r--pkgs/simple-scalar/0003-fix-obstack.h-post-increment.patch25
-rw-r--r--pkgs/simple-scalar/0004-stdarg.h-instead-of-varargs.h.patch25
-rw-r--r--pkgs/simple-scalar/default.nix5
-rw-r--r--pkgs/simple-scalar/gcc-sslittle-na-sstrix.nix109
-rw-r--r--pkgs/simple-scalar/simplesim.nix52
-rw-r--r--pkgs/smartthinq-sensors.nix31
-rw-r--r--pkgs/spliit/default.nix64
-rw-r--r--pkgs/st.nix476
-rw-r--r--pkgs/tmux-lift/Makefile6
-rw-r--r--pkgs/tmux-lift/default.nix14
-rw-r--r--pkgs/tmux-lift/lift.c139
-rw-r--r--pkgs/tmux-lift/lift.h9
-rw-r--r--pkgs/tmux-lift/unlift.c41
-rw-r--r--pkgs/tmux-open/default.nix12
-rw-r--r--pkgs/tmux-open/tmux-open.sh15
-rw-r--r--pkgs/tmux-pass.nix26
-rw-r--r--pkgs/xandikos/default.nix7
-rw-r--r--pki/by-path.nix18
-rw-r--r--pki/ca.nix129
-rw-r--r--pki/certs.nix1
-rw-r--r--pki/default.nix7
-rw-r--r--pki/public/README.md1
-rw-r--r--sys/auth/default.nix7
-rw-r--r--sys/auth/login.nix22
-rw-r--r--sys/auth/oath.nix38
-rw-r--r--sys/auth/openssh.nix193
-rw-r--r--sys/auth/ssh-key.pub1
-rw-r--r--sys/baseline/default.nix95
-rw-r--r--sys/boot/chain.nix41
-rw-r--r--sys/boot/default.nix14
-rw-r--r--sys/boot/detached-luks.nix117
-rw-r--r--sys/boot/efi.nix49
-rw-r--r--sys/boot/firmware.nix33
-rw-r--r--sys/boot/fscrypt.nix30
-rw-r--r--sys/boot/impermanence.nix56
-rw-r--r--sys/boot/namespaced.nix33
-rw-r--r--sys/boot/secure-boot.nix51
-rw-r--r--sys/boot/stack/btrfs-toplevel-multidrive.nix99
-rw-r--r--sys/boot/stack/default.nix6
-rw-r--r--sys/boot/stack/luks-ext4-fscrypt-impermanence.nix98
-rw-r--r--sys/boot/tpm.nix128
-rw-r--r--sys/btrfs/default.nix6
-rw-r--r--sys/btrfs/mounts.nix47
-rw-r--r--sys/btrfs/snapper.nix76
-rw-r--r--sys/default.nix38
-rw-r--r--sys/env/default.nix8
-rw-r--r--sys/env/domains.nix1
-rw-r--r--sys/env/maps.nix1
-rw-r--r--sys/env/users.nix1
-rw-r--r--sys/env/virtual.nix1
-rw-r--r--sys/gitea/default.nix41
-rw-r--r--sys/hardware/altera.nix25
-rw-r--r--sys/hardware/apc.nix33
-rw-r--r--sys/hardware/athena.nix48
-rw-r--r--sys/hardware/bluetooth.nix19
-rw-r--r--sys/hardware/default.nix13
-rw-r--r--sys/hardware/epson.nix38
-rw-r--r--sys/hardware/laptop.nix19
-rw-r--r--sys/hardware/printing.nix50
-rw-r--r--sys/hardware/thinkpad.nix42
-rw-r--r--sys/hardware/yubico.nix24
-rw-r--r--sys/home-assistant/default.nix6
-rw-r--r--sys/home-assistant/hass.nix79
-rw-r--r--sys/home-assistant/yaml-extra.nix23
-rw-r--r--sys/jobs/default.nix5
-rw-r--r--sys/jobs/pki-expiry/default.nix60
-rw-r--r--sys/jobs/pki-expiry/pki-expiry.sh108
-rw-r--r--sys/kiosk/default.nix48
-rw-r--r--sys/mail/default.nix246
-rw-r--r--sys/mta/default.nix269
-rw-r--r--sys/net/default.nix9
-rw-r--r--sys/net/fail2ban.nix37
-rw-r--r--sys/net/interfaces.nix119
-rw-r--r--sys/net/nets.nix1
-rw-r--r--sys/net/options.nix278
-rw-r--r--sys/net/vsock.nix63
-rw-r--r--sys/ns/default.nix10
-rw-r--r--sys/ns/dkim/README.md1
-rw-r--r--sys/ns/mx.nix60
-rw-r--r--sys/ns/ns.nix153
-rw-r--r--sys/ns/nsd.nix87
-rw-r--r--sys/ns/ptr/default.nix9
-rw-r--r--sys/ns/ptr/gate-public-v4/default.nix14
-rw-r--r--sys/ns/ptr/gate-public-v4/serial.nix6
-rw-r--r--sys/ns/ptr/gate-public-v6/default.nix14
-rw-r--r--sys/ns/ptr/gate-public-v6/serial.nix6
-rw-r--r--sys/ns/ptr/static-prefix-v6/default.nix14
-rw-r--r--sys/ns/ptr/static-prefix-v6/serial.nix6
-rw-r--r--sys/ns/rr.nix520
-rw-r--r--sys/ns/zones/README.md1
-rw-r--r--sys/nspawn/default.nix5
-rw-r--r--sys/nspawn/dmz.nix229
-rw-r--r--sys/platform/README.md1
-rw-r--r--sys/preset/default.nix6
-rw-r--r--sys/preset/dmz.nix64
-rw-r--r--sys/preset/user.nix73
-rw-r--r--sys/seat/default.nix142
-rw-r--r--sys/syncthing/default.nix45
-rw-r--r--sys/virt/default.nix5
-rw-r--r--sys/virt/dom/README.md1
-rw-r--r--sys/virt/libvirt.nix64
-rw-r--r--sys/web/default.nix7
-rw-r--r--sys/web/nginx.nix94
-rw-r--r--sys/web/php-fpm.nix154
-rw-r--r--sys/web/sites/default.nix7
-rw-r--r--sys/web/sites/home.nix38
-rw-r--r--sys/web/sites/host.nix106
-rw-r--r--sys/web/sites/portal.nix40
-rw-r--r--sysret.org/.gitignore1
-rw-r--r--sysret.org/config.toml (renamed from config.toml)0
-rw-r--r--trivionomicon/.gitignore2
-rw-r--r--trivionomicon/COPYING674
-rw-r--r--trivionomicon/README.md8
-rw-r--r--trivionomicon/doctrine/default.nix16
-rw-r--r--trivionomicon/doctrine/lib/default.nix23
-rw-r--r--trivionomicon/doctrine/lib/import-all.nix21
-rw-r--r--trivionomicon/doctrine/lib/mk-module.nix51
-rw-r--r--trivionomicon/flake.lock61
-rw-r--r--trivionomicon/flake.nix229
-rw-r--r--trivionomicon/modules/athena-bccr/default.nix14
-rw-r--r--trivionomicon/modules/athena-bccr/hm.nix14
-rw-r--r--trivionomicon/modules/athena-bccr/options.nix30
-rw-r--r--trivionomicon/modules/athena-bccr/sys.nix35
-rw-r--r--trivionomicon/modules/default.nix3
-rw-r--r--trivionomicon/modules/laptop/default.nix10
-rw-r--r--trivionomicon/modules/laptop/sys.nix11
-rw-r--r--trivionomicon/modules/nix-registry/default.nix16
-rw-r--r--trivionomicon/modules/nix-registry/hm.nix23
-rw-r--r--trivionomicon/modules/nix-registry/options.nix19
-rw-r--r--trivionomicon/modules/sway/default.nix13
-rw-r--r--trivionomicon/modules/sway/options.nix3
-rw-r--r--trivionomicon/modules/sway/sys.nix45
-rw-r--r--trivionomicon/modules/thinkpad/default.nix11
-rw-r--r--trivionomicon/modules/thinkpad/sys.nix30
-rw-r--r--trivionomicon/modules/trivionomiconMotd/default.nix10
-rw-r--r--trivionomicon/modules/trivionomiconMotd/sys.nix22
-rw-r--r--trivionomicon/modules/yubico/default.nix13
-rw-r--r--trivionomicon/modules/yubico/hm.nix9
-rw-r--r--trivionomicon/modules/yubico/sys.nix14
-rw-r--r--trivionomicon/pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch25
-rw-r--r--trivionomicon/pkgs/athena-bccr/LaunchGaudi.java12
-rw-r--r--trivionomicon/pkgs/athena-bccr/default.nix30
-rw-r--r--trivionomicon/pkgs/athena-bccr/firmador.nix57
-rw-r--r--trivionomicon/pkgs/athena-bccr/gaudi-env.nix62
-rw-r--r--trivionomicon/pkgs/athena-bccr/releases.nix12
-rw-r--r--trivionomicon/pkgs/athena-bccr/unwrapped.nix226
-rw-r--r--trivionomicon/pkgs/default.nix10
-rw-r--r--trivionomicon/pkgs/snapborg/0001-Remove-env-arg-from-subprocess-calls.patch29
-rw-r--r--trivionomicon/pkgs/snapborg/default.nix34
-rw-r--r--trivionomicon/pkgs/spliit/default.nix76
-rw-r--r--trivionomicon/templates/system-flake/.gitignore3
-rw-r--r--trivionomicon/templates/system-flake/flake.nix28
-rw-r--r--trivionomicon/templates/system-flake/home/default.nix73
-rw-r--r--trivionomicon/templates/system-flake/home/platform/me@foo/default.nix10
-rw-r--r--trivionomicon/templates/system-flake/pkgs/config/default.nix5
-rw-r--r--trivionomicon/templates/system-flake/pkgs/config/unfree.nix7
-rw-r--r--trivionomicon/templates/system-flake/pkgs/default.nix12
-rw-r--r--trivionomicon/templates/system-flake/pkgs/hello-world/Makefile6
-rw-r--r--trivionomicon/templates/system-flake/pkgs/hello-world/default.nix14
-rw-r--r--trivionomicon/templates/system-flake/pkgs/hello-world/hello-world.c7
-rw-r--r--trivionomicon/templates/system-flake/pkgs/lib/default.nix3
-rw-r--r--trivionomicon/templates/system-flake/pkgs/lib/fibonacci.nix7
-rw-r--r--trivionomicon/templates/system-flake/sys/default.nix14
-rw-r--r--trivionomicon/templates/system-flake/sys/platform/foo/default.nix6
262 files changed, 18552 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 46f5006..f094862 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-public/*
+!**/.keep
+result
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..3c17abc
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,60 @@
+{
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
+ unstable.url = "github:nixos/nixpkgs/nixos-unstable";
+
+ home-manager = {
+ url = "github:nix-community/home-manager/release-25.05";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ nur.url = "github:nix-community/NUR";
+ impermanence.url = "github:nix-community/impermanence";
+ hm-isolation.url = "github:3442/hm-isolation";
+
+ nixvirt = {
+ url = "github:AshleyYakeley/NixVirt";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ flake-utils.url = "github:numtide/flake-utils";
+
+ lanzaboote = {
+ url = "github:nix-community/lanzaboote";
+
+ inputs = {
+ nixpkgs.follows = "nixpkgs";
+ pre-commit-hooks-nix.follows = "";
+ };
+ };
+
+ trivionomicon = {
+ url = "./trivionomicon";
+ inputs = {
+ flake-utils.follows = "flake-utils";
+ nixpkgs.follows = "nixpkgs";
+ };
+ };
+
+ vpsadminos.url = "github:vpsfreecz/vpsadminos";
+ };
+
+ outputs = flakes:
+ flakes.trivionomicon.lib.mkSystemFlake {
+ inherit flakes;
+
+ system = "x86_64-linux";
+ doctrinePrefix = "local";
+
+ paths = {
+ localOverlay = "pkgs";
+ nixpkgsConfig = "pkgs/config";
+
+ nixosSource = "sys";
+ nixosPlatforms = "sys/platform";
+
+ hmSource = "home";
+ hmPlatforms = "home/platform";
+ };
+ };
+}
diff --git a/home/baseline/default.nix b/home/baseline/default.nix
new file mode 100644
index 0000000..046a475
--- /dev/null
+++ b/home/baseline/default.nix
@@ -0,0 +1,67 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.baseline;
+in {
+ imports = [
+ ./git.nix
+ ./graphics.nix
+ ./nvim.nix
+ ./zsh.nix
+ ];
+
+ options.local = {
+ hostname = mkOption {
+ type = types.str;
+ };
+
+ uid = mkOption {
+ type = types.int;
+ };
+
+ gecos = mkOption {
+ type = types.str;
+ };
+
+ email = mkOption {
+ type = types.str;
+ };
+ };
+
+ config = {
+ home = {
+ # This value determines the Home Manager release that your
+ # configuration is compatible with. This helps avoid breakage
+ # when a new Home Manager release introduces backwards
+ # incompatible changes.
+ #
+ # You can update Home Manager without changing this value. See
+ # the Home Manager release notes for a list of state version
+ # changes in each release.
+ stateVersion = "21.11";
+
+ homeDirectory = "/home/${config.home.username}";
+
+ packages = [
+ pkgs.file
+ pkgs.killall
+ pkgs.man-pages
+ pkgs.man-pages-posix
+ pkgs.tree
+ pkgs.unzip
+ pkgs.wget
+ pkgs.zip
+ ];
+
+ sessionVariables = {
+ LESSHISTFILE = "/dev/null";
+ };
+ };
+
+ xdg.enable = true;
+ };
+}
diff --git a/home/baseline/git.nix b/home/baseline/git.nix
new file mode 100644
index 0000000..9707f44
--- /dev/null
+++ b/home/baseline/git.nix
@@ -0,0 +1,16 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local;
+in {
+ config = {
+ programs.git = {
+ enable = true;
+ userName = cfg.gecos;
+ userEmail = cfg.email;
+ };
+ };
+}
diff --git a/home/baseline/graphics.nix b/home/baseline/graphics.nix
new file mode 100644
index 0000000..0e349c6
--- /dev/null
+++ b/home/baseline/graphics.nix
@@ -0,0 +1,76 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; {
+ config = {
+ dconf.settings = {
+ "org/gtk/settings/file-chooser".startup-mode = "cwd";
+ "org/gtk/gtk4/settings/file-chooser".startup-mode = "cwd";
+ };
+
+ fonts.fontconfig.enable = true;
+
+ gtk = {
+ enable = true;
+
+ gtk2.extraConfig = ''
+ gtk-toolbar-style=GTK_TOOLBAR_BOTH_HORIZ
+ gtk-menu-images=1
+ gtk-button-images=1
+ '';
+
+ gtk3.extraConfig = {
+ gtk-recent-files-enabled = 0;
+ };
+
+ gtk4.extraConfig = {
+ gtk-recent-files-enabled = 0;
+ };
+
+ font = {
+ package = pkgs.noto-fonts;
+ name = "Noto Sans Regular";
+ #size = 14; <- caga layout de páginas
+ };
+
+ theme = {
+ package = pkgs.materia-theme;
+ name = "Materia-dark";
+ };
+ };
+
+ home = {
+ pointerCursor = {
+ enable = true;
+
+ name = "Adwaita";
+ size = 48;
+
+ package = pkgs.adwaita-icon-theme;
+
+ gtk.enable = true;
+ x11.enable = true;
+ sway.enable = true;
+ dotIcons.enable = true;
+ };
+
+ sessionVariables = {
+ # Usar gtk en aplicaciones de jvm
+ _JAVA_OPTIONS = concatStringsSep " " [
+ "-Dawt.useSystemAAFontSettings=on"
+ "-Dswing.aatext=true"
+ "-Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel"
+ "-Dswing.crossplatformlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel"
+ ];
+ };
+ };
+
+ qt = {
+ enable = true;
+ platformTheme.name = "gtk";
+ };
+ };
+}
diff --git a/home/baseline/nvim.nix b/home/baseline/nvim.nix
new file mode 100644
index 0000000..edcabe8
--- /dev/null
+++ b/home/baseline/nvim.nix
@@ -0,0 +1,29 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.baseline;
+in {
+ config = {
+ home.sessionVariables.EDITOR = "nvim";
+
+ programs.neovim = {
+ enable = true;
+
+ viAlias = true;
+ vimAlias = true;
+ withRuby = false;
+ withPython3 = false;
+
+ extraConfig = ''
+ set number " Enable line numbering
+ set relativenumber " Enable relative line numbering
+ set tabstop=4 " Set tap stop to 4
+ set shiftwidth=4 " Set shift width to 4 (same as tabstop)
+ set viminfo= " No tracking
+ '';
+ };
+ };
+}
diff --git a/home/baseline/zsh.nix b/home/baseline/zsh.nix
new file mode 100644
index 0000000..2be24b7
--- /dev/null
+++ b/home/baseline/zsh.nix
@@ -0,0 +1,20 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.baseline;
+in {
+ config = {
+ programs.zsh = {
+ enable = true;
+
+ autosuggestion.enable = true;
+ syntaxHighlighting.enable = true;
+
+ initContent = lib.mkAfter (import ./zshrc.nix pkgs);
+ };
+ };
+}
diff --git a/home/baseline/zshrc.nix b/home/baseline/zshrc.nix
new file mode 100644
index 0000000..b963649
--- /dev/null
+++ b/home/baseline/zshrc.nix
@@ -0,0 +1,69 @@
+{
+ grml-zsh-config,
+ local,
+ ...
+}: ''
+ source ${grml-zsh-config}/etc/zsh/zshrc
+
+ export PATH="$PATH:$HOME/.cargo/bin"
+
+ alias gpicview='loupe'
+ alias reset='tput reset'
+ alias reload='exec zsh'
+ alias this-date='date +%b%d | sed "s/^\w/\U&/g"'
+
+ function spawn() {
+ if [ ! -x "$(command -v $1)" ]; then
+ echo "spawn: no such command: $1" >&2
+ return 1
+ fi
+
+ $@ >/dev/null 0>&1 2>&1 &
+ disown
+ }
+
+ function xseli() {
+ T=$(mktemp)
+ $EDITOR -n $T
+ xsel -b <$T
+ rm $T
+ }
+
+ autoload -Uz up-line-or-beginning-search
+ zle -N up-line-or-beginning-search
+ autoload -Uz down-line-or-beginning-search
+ zle -N down-line-or-beginning-search
+ bindkey '\eOA' up-line-or-beginning-search
+ bindkey '\e[A' up-line-or-beginning-search
+ bindkey '\eOB' down-line-or-beginning-search
+ bindkey '\e[B' down-line-or-beginning-search
+
+ INSTALLABLES=()
+ while read -d: PATH_ITEM; do
+ if [[ "$PATH_ITEM" =~ "^(/nix/store/[a-z0-9]+-([a-zA-Z][a-zA-Z0-9_]*(-[a-zA-Z][a-zA-Z0-9_]*)*)(-[^/]+)?)/" ]]; then
+ INSTALLABLES+=("''${match[2]}")
+ fi
+ done <<<"$PATH"
+
+ if [ "''${#INSTALLABLES[@]}" -gt 0 ]; then
+ _GRML_NIX_SHELL="{''${INSTALLABLES[@]}} "
+ fi
+
+ unset INSTALLABLES PATH_ITEM
+
+ function grml_nix_shell() {
+ REPLY="$_GRML_NIX_SHELL"
+ }
+
+ grml_theme_add_token nix-shell -f grml_nix_shell '%F{red}' '%f'
+
+ zstyle ':prompt:grml:left:setup' items $([ ''${NO_USERATHOST:-0} -gt 0 ] || echo user at host) path nix-shell percent
+ zstyle ':prompt:grml:right:setup' items sad-smiley vcs $([ ''${NO_BATTERY:-0} -gt 0 ] || echo battery) time
+ zstyle ':prompt:grml:right:items:time' pre ' %F{yellow}'
+
+ unsetopt sharehistory
+ setopt appendhistory
+ setopt extendedhistory
+
+ source ${local.git-aliases}
+''
diff --git a/home/default.nix b/home/default.nix
new file mode 100644
index 0000000..67bc37b
--- /dev/null
+++ b/home/default.nix
@@ -0,0 +1,13 @@
+{flakes, ...}: {
+ imports = [
+ flakes.hm-isolation.homeManagerModule
+ flakes.impermanence.nixosModules.home-manager.impermanence
+ flakes.trivionomicon.homeManagerModules.default
+ ../pki
+ ./baseline
+ ./desktop
+ ./environ
+ ./isolation
+ ./pim
+ ];
+}
diff --git a/home/desktop/default.nix b/home/desktop/default.nix
new file mode 100644
index 0000000..d46e97e
--- /dev/null
+++ b/home/desktop/default.nix
@@ -0,0 +1,18 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.desktop;
+in {
+ imports = [
+ ./firefox.nix
+ ./sway.nix
+ ];
+
+ options.local.desktop = {
+ enable = mkEnableOption "desktop";
+ };
+}
diff --git a/home/desktop/firefox.nix b/home/desktop/firefox.nix
new file mode 100644
index 0000000..f19b3ad
--- /dev/null
+++ b/home/desktop/firefox.nix
@@ -0,0 +1,34 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.desktop;
+in {
+ config = mkIf cfg.enable {
+ programs.firefox = {
+ enable = true;
+
+ package = pkgs.firefox.override {
+ nativeMessagingHosts = [pkgs.passff-host];
+ };
+
+ profiles."main.profile" = {
+ id = 0;
+ name = "default";
+
+ extensions.packages = with pkgs.nur.repos.rycee.firefox-addons; [
+ decentraleyes
+ darkreader
+ old-reddit-redirect
+ passff
+ privacy-badger
+ ublock-origin
+ umatrix
+ ];
+ };
+ };
+ };
+}
diff --git a/home/desktop/sway.nix b/home/desktop/sway.nix
new file mode 100644
index 0000000..d363e11
--- /dev/null
+++ b/home/desktop/sway.nix
@@ -0,0 +1,115 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.desktop;
+in {
+ config = mkIf cfg.enable {
+ home.packages = [
+ pkgs.wlr-randr
+ ];
+
+ programs = {
+ waybar.enable = true;
+
+ wofi.enable = true;
+ };
+
+ services = {
+ swayidle = {
+ enable = true;
+
+ timeouts = [
+ {
+ timeout = 600;
+ command = "${getExe pkgs.gtklock} -d";
+ }
+ ];
+ };
+ };
+
+ systemd.user.services.wl-gammarelay-rs = {
+ Unit.After = ["sway-session.target"];
+ Install.WantedBy = ["sway-session.target"];
+
+ Service.ExecStart = getExe pkgs.wl-gammarelay-rs;
+ };
+
+ wayland.windowManager.sway = {
+ enable = true;
+
+ config = {
+ modifier = "Mod4";
+ focus.followMouse = false;
+
+ fonts = {
+ size = 11.0;
+ names = ["DejaVu Sans Mono"];
+ style = "Bold Semi-Condensed";
+ };
+
+ bars = singleton {
+ command = "waybar";
+ position = "top";
+ };
+
+ keybindings = let
+ mod = config.wayland.windowManager.sway.config.modifier;
+ wofi = config.programs.wofi.package;
+
+ grimshot = getExe pkgs.sway-contrib.grimshot;
+ in
+ mkOptionDefault {
+ "${mod}+a" = "focus parent";
+ "${mod}+c" = "focus child";
+ "${mod}+d" = "exec --no-startup-id ${getExe wofi} -S run";
+ "${mod}+i" = "exec busctl --user call rs.wl-gammarelay / rs.wl.gammarelay ToggleInverted";
+ "${mod}+o" = "exec ${getExe pkgs.gtklock} -d";
+ "${mod}+Return" = "exec ${getExe pkgs.local.st} -e ${getExe pkgs.local.tmux-lift} ${getExe pkgs.local.tmux-open}";
+ "${mod}+Shift+e" = "input * xkb_layout latam";
+ "${mod}+Shift+u" = "input * xkb_layout us";
+ "${mod}+p" = "exec ${grimshot} copy active";
+ "${mod}+Shift+p" = "exec ${grimshot} copy area";
+ "${mod}+Ctrl+p" = "exec ${grimshot} copy window";
+ };
+
+ startup = [
+ #{
+ # command = "${getExe pkgs.xautolock} -time 10 -locker '${pkgs.i3lock-color}/bin/i3lock-color -fe -c222222'";
+ #}
+ ];
+
+ window.commands = [
+ # (No) Title Bars
+ {
+ command = "border pixel 5";
+ criteria.class = "^.*";
+ }
+
+ {
+ command = "floating enabled";
+ criteria.class = "floating";
+ }
+ ];
+ };
+
+ extraSessionCommands = ''
+ export SDL_VIDEODRIVER=wayland
+ # needs qt5.qtwayland in systemPackages
+ export QT_QPA_PLATFORM=wayland
+ export QT_WAYLAND_DISABLE_WINDOWDECORATION="1"
+ # Fix for some Java AWT applications (e.g. Android Studio),
+ # use this if they aren't displayed properly:
+ export _JAVA_AWT_WM_NONREPARENTING=1
+ '';
+
+ swaynag.enable = true;
+ systemd.enable = true;
+
+ xwayland = true;
+ };
+ };
+}
diff --git a/home/environ/default.nix b/home/environ/default.nix
new file mode 100644
index 0000000..fcd4dd0
--- /dev/null
+++ b/home/environ/default.nix
@@ -0,0 +1,17 @@
+{lib, ...}:
+with lib; {
+ imports = [
+ ./gpg.nix
+ ./pass.nix
+ ./path.nix
+ ./source.nix
+ ./ssh.nix
+ ./tmux.nix
+ ./units.nix
+ ./vtmp.nix
+ ];
+
+ options.local.environ = {
+ enable = mkEnableOption "local environment";
+ };
+}
diff --git a/home/environ/gpg.nix b/home/environ/gpg.nix
new file mode 100644
index 0000000..a8173b7
--- /dev/null
+++ b/home/environ/gpg.nix
@@ -0,0 +1,37 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+in {
+ config = mkIf cfg.enable {
+ programs.gpg = {
+ enable = true;
+ scdaemonSettings.disable-ccid = true;
+ };
+
+ services.gpg-agent = {
+ enable = true;
+
+ enableBashIntegration = true;
+ enableZshIntegration = true;
+
+ enableExtraSocket = true;
+ enableSshSupport = true;
+
+ defaultCacheTtl = 3600 * 3;
+ defaultCacheTtlSsh = 3600 * 3;
+
+ maxCacheTtl = 3600 * 6;
+ maxCacheTtlSsh = 3600 * 6;
+
+ pinentry = {
+ package = pkgs.pinentry-gtk2;
+ program = "pinentry-gtk-2";
+ };
+ };
+ };
+}
diff --git a/home/environ/pass.nix b/home/environ/pass.nix
new file mode 100644
index 0000000..cd431a2
--- /dev/null
+++ b/home/environ/pass.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+in {
+ config = mkIf cfg.enable {
+ programs.password-store = {
+ enable = true;
+ package = pkgs.pass.withExtensions (exts:
+ (with exts; [
+ pass-audit
+ pass-genphrase
+ pass-otp
+ pass-tomb
+ pass-update
+ ])
+ ++ [
+ pkgs.local.pass-bcr
+ pkgs.local.pass-tail
+ ]);
+
+ settings = {
+ PASSWORD_STORE_DIR = "${config.home.homeDirectory}/pass";
+ PASSWORD_STORE_TOMB_KEY = "${config.home.homeDirectory}/tomb/pass.key.gpg";
+ PASSWORD_STORE_TOMB_FILE = "${config.home.homeDirectory}/tomb/pass.tomb";
+ };
+ };
+ };
+}
diff --git a/home/environ/path.nix b/home/environ/path.nix
new file mode 100644
index 0000000..9fc0a94
--- /dev/null
+++ b/home/environ/path.nix
@@ -0,0 +1,55 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+
+ py = pkgs.python3Packages;
+in {
+ config = mkIf cfg.enable {
+ home.packages = [
+ pkgs.calc
+ pkgs.cloc
+ pkgs.diceware
+ pkgs.local.athena-bccr.latest.firmador
+ pkgs.gcc
+ pkgs.gnome-screenshot
+ (pkgs.gajim.overrideAttrs (super: {buildInputs = super.buildInputs ++ [pkgs.gsound];}))
+ (pkgs.local.athena-bccr.latest.gaudi.override {gaudiHash = "sha256-0nuku63USr5rC0rIwUC6toDN46qu8/KkezDTsVz9uJo=";})
+ pkgs.gnucash
+ pkgs.gruvbox-dark-icons-gtk
+ pkgs.hack-font
+ pkgs.i3-gaps
+ pkgs.imagemagick
+ py.ipython
+ pkgs.jq
+ pkgs.libreoffice-fresh
+ pkgs.loupe # 'gpicview' has been removed due to lack of maintenance upstream
+ pkgs.lsof
+ pkgs.mosh
+ pkgs.mpv
+ pkgs.libsForQt5.okular
+ pkgs.pavucontrol
+ pkgs.pciutils
+ py.python
+ pkgs.pv
+ pkgs.rustup
+ pkgs.local.scripts
+ pkgs.local.st
+ pkgs.tdesktop
+ pkgs.local.tmux-lift
+ pkgs.tomb
+ pkgs.units
+ pkgs.usbutils
+ pkgs.waypipe
+ pkgs.wl-clipboard
+ pkgs.xsel
+ pkgs.xournalpp
+ pkgs.yubikey-manager
+ pkgs.zoom-us
+ ];
+ };
+}
diff --git a/home/environ/source.nix b/home/environ/source.nix
new file mode 100644
index 0000000..57b990e
--- /dev/null
+++ b/home/environ/source.nix
@@ -0,0 +1,27 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+
+ py = pkgs.python3Packages;
+in {
+ config = mkIf cfg.enable {
+ nix.registry."system".to = {
+ type = "path";
+ path = "${config.home.homeDirectory}/nix";
+ };
+
+ programs = {
+ git.signing.signByDefault = true;
+ home-manager.enable = true;
+ };
+
+ xdg.configFile."home-manager" = {
+ source = config.lib.file.mkOutOfStoreSymlink "${config.home.homeDirectory}/nix";
+ };
+ };
+}
diff --git a/home/environ/ssh-match.nix b/home/environ/ssh-match.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/home/environ/ssh-match.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/home/environ/ssh.nix b/home/environ/ssh.nix
new file mode 100644
index 0000000..d363baf
--- /dev/null
+++ b/home/environ/ssh.nix
@@ -0,0 +1,27 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+in {
+ config = mkIf cfg.enable {
+ programs.ssh = {
+ enable = true;
+
+ compression = true;
+ controlMaster = "auto";
+ controlPath = "/run/user/%i/ssh/master-%r@%n:%p";
+
+ extraOptionOverrides.AddKeysToAgent = "true";
+
+ matchBlocks = import ./ssh-match.nix;
+ };
+
+ systemd.user.tmpfiles.rules = [
+ "d %t/ssh 0700"
+ ];
+ };
+}
diff --git a/home/environ/tmux.nix b/home/environ/tmux.nix
new file mode 100644
index 0000000..8d7b96f
--- /dev/null
+++ b/home/environ/tmux.nix
@@ -0,0 +1,45 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+in {
+ options.local.environ.tmuxPass = {
+ enable = mkEnableOption "tmux-pass plugin";
+ };
+
+ config = mkIf cfg.enable {
+ programs.tmux = {
+ enable = true;
+ aggressiveResize = true;
+ clock24 = true;
+ escapeTime = 10;
+ terminal = "xterm-256color";
+ keyMode = "vi";
+
+ plugins = optional cfg.tmuxPass.enable {
+ plugin = pkgs.local.tmux-pass;
+ extraConfig = ''
+ set -g @pass-key BSpace
+ set -g @pass-copy-to-clipboard on
+ set -g @pass-window-size 15
+ set -g @pass-hide-pw-from-preview 'on'
+ set -g @pass-hide-preview on
+ '';
+ };
+
+ extraConfig = ''
+ set -g mouse on
+ set -ga update-environment " LIFT_PID"
+ set -g set-titles on
+ set -g renumber-windows on
+ set -sa terminal-overrides ',xterm-termite:RGB'
+ set -g status-right "#{?window_bigger,[#{window_offset_x}#,#{window_offset_y}] ,} %H:%M %d-%b-%y"
+ bind-key X set-window-option synchronize-panes\; display-message "synchronize-panes is now #{?pane_synchronized,on,off}"
+ '';
+ };
+ };
+}
diff --git a/home/environ/units.nix b/home/environ/units.nix
new file mode 100644
index 0000000..ae4e680
--- /dev/null
+++ b/home/environ/units.nix
@@ -0,0 +1,37 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+in {
+ config = mkIf cfg.enable {
+ systemd.user = {
+ timers = {
+ units-cur = {
+ Install.WantedBy = ["timers.target"];
+ Timer.OnCalendar = "daily";
+ Unit.Description = "Update currency information for 'units'";
+ };
+ };
+
+ services = {
+ units-cur = {
+ Unit.Description = "Update currency information for 'units'";
+
+ Service = {
+ Type = "exec";
+ ExecStart = "${pkgs.units}/bin/units_cur .units";
+ };
+ };
+ };
+ };
+
+ home.file = {
+ #TODO: .calc_history
+ ".units_history".source = config.lib.file.mkOutOfStoreSymlink "/dev/null";
+ };
+ };
+}
diff --git a/home/environ/vtmp.nix b/home/environ/vtmp.nix
new file mode 100644
index 0000000..bd02699
--- /dev/null
+++ b/home/environ/vtmp.nix
@@ -0,0 +1,23 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.environ;
+in {
+ config = mkIf cfg.enable {
+ systemd.user.tmpfiles.rules = [
+ "d %t/vtmp 0700"
+ ];
+
+ home.file = {
+ "vtmp".source = config.lib.file.mkOutOfStoreSymlink "/run/user/${toString config.local.uid}/vtmp";
+ };
+
+ gtk.gtk3.bookmarks = [
+ "file://${config.home.homeDirectory}/vtmp"
+ "file://${config.home.homeDirectory}/tmp"
+ ];
+ };
+}
diff --git a/home/isolation/default.nix b/home/isolation/default.nix
new file mode 100644
index 0000000..aff006c
--- /dev/null
+++ b/home/isolation/default.nix
@@ -0,0 +1,37 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.shenvs;
+in {
+ options.local.shenvs = {
+ enable = mkEnableOption "hm-isolation shenvs";
+ };
+
+ config = mkIf cfg.enable {
+ home.isolation = {
+ enable = true;
+ btrfsSupport = true;
+
+ defaults = {
+ static = false;
+ bindHome = "home";
+
+ persist = {
+ base = "shenvs";
+ btrfs = true;
+ };
+ };
+
+ modulesUnder = ../shenvs;
+ };
+
+ local = mkIf config.home.isolation.active {
+ desktop.enable = mkForce false;
+ environ.enable = mkForce false;
+ mail.enable = mkForce false;
+ };
+ };
+}
diff --git a/home/pim/.gitignore b/home/pim/.gitignore
new file mode 100644
index 0000000..1d9a3a0
--- /dev/null
+++ b/home/pim/.gitignore
@@ -0,0 +1 @@
+*.svbin
diff --git a/home/pim/0001-gnutls-add-support-for-client-key-URLs-separate-from.patch b/home/pim/0001-gnutls-add-support-for-client-key-URLs-separate-from.patch
new file mode 100644
index 0000000..792a528
--- /dev/null
+++ b/home/pim/0001-gnutls-add-support-for-client-key-URLs-separate-from.patch
@@ -0,0 +1,48 @@
+From cdd4d80aecb29f98d325b5389bdcc0813a37abfd Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sat, 28 Jun 2025 22:50:16 -0600
+Subject: [PATCH] gnutls: add support for client key URLs separate from client
+ certs
+
+---
+ conn/config.c | 3 +++
+ conn/gnutls.c | 8 ++++++--
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/conn/config.c b/conn/config.c
+index e45e81bd7..161e8e584 100644
+--- a/conn/config.c
++++ b/conn/config.c
+@@ -74,6 +74,9 @@ static struct ConfigDef ConnVarsSsl[] = {
+ { "ssl_client_cert", DT_PATH|D_PATH_FILE, 0, 0, NULL,
+ "File containing client certificates"
+ },
++ { "ssl_client_key", DT_PATH|D_PATH_FILE, 0, 0, NULL,
++ "File containing client certificate key"
++ },
+ { "ssl_force_tls", DT_BOOL, true, 0, NULL,
+ "(ssl) Require TLS encryption for all connections"
+ },
+diff --git a/conn/gnutls.c b/conn/gnutls.c
+index 536948e6e..379580871 100644
+--- a/conn/gnutls.c
++++ b/conn/gnutls.c
+@@ -897,9 +897,13 @@ static int tls_negotiate(struct Connection *conn)
+ const char *const c_ssl_client_cert = cs_subset_path(NeoMutt->sub, "ssl_client_cert");
+ if (c_ssl_client_cert)
+ {
+- mutt_debug(LL_DEBUG2, "Using client certificate %s\n", c_ssl_client_cert);
++ const char *c_ssl_client_key = cs_subset_path(NeoMutt->sub, "ssl_client_key");
++ if (!c_ssl_client_key)
++ c_ssl_client_key = c_ssl_client_cert;
++
++ mutt_debug(LL_DEBUG2, "Using client certificate %s, key %s\n", c_ssl_client_cert, c_ssl_client_key);
+ gnutls_certificate_set_x509_key_file(data->xcred, c_ssl_client_cert,
+- c_ssl_client_cert, GNUTLS_X509_FMT_PEM);
++ c_ssl_client_key, GNUTLS_X509_FMT_PEM);
+ }
+
+ #ifdef HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
+--
+2.49.0
+
diff --git a/home/pim/0002-gnutls-implement-token-insertion-and-PKCS-11-PIN-pro.patch b/home/pim/0002-gnutls-implement-token-insertion-and-PKCS-11-PIN-pro.patch
new file mode 100644
index 0000000..2f13e68
--- /dev/null
+++ b/home/pim/0002-gnutls-implement-token-insertion-and-PKCS-11-PIN-pro.patch
@@ -0,0 +1,126 @@
+From 276cf337346e0ea111883a05bc00f764d201d6ab Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sun, 29 Jun 2025 11:35:57 -0600
+Subject: [PATCH 2/2] gnutls: implement token insertion and PKCS#11 PIN prompts
+
+---
+ conn/gnutls.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 71 insertions(+), 1 deletion(-)
+
+diff --git a/conn/gnutls.c b/conn/gnutls.c
+index 379580871..32ad1ae85 100644
+--- a/conn/gnutls.c
++++ b/conn/gnutls.c
+@@ -29,6 +29,7 @@
+
+ #include "config.h"
+ #include <gnutls/gnutls.h>
++#include <gnutls/pkcs11.h>
+ #include <gnutls/x509.h>
+ #include <stdbool.h>
+ #include <stdio.h>
+@@ -39,10 +40,14 @@
+ #include "mutt/lib.h"
+ #include "config/lib.h"
+ #include "core/lib.h"
+-#include "lib.h"
+ #include "connaccount.h"
+ #include "connection.h"
++#include "editor/lib.h"
+ #include "globals.h"
++#include "gui/lib.h"
++#include "history/lib.h"
++#include "lib.h"
++#include "mutt.h"
+ #include "muttlib.h"
+ #include "ssl.h"
+
+@@ -84,6 +89,64 @@ struct TlsSockData
+ gnutls_certificate_credentials_t xcred;
+ };
+
++int tls_pkcs11_token_callback(void *userdata, const char *label, unsigned retry)
++{
++ (void) userdata;
++
++ if (OptNoCurses) {
++ mutt_error(_("Unable to prompt for PKCS#11 token insertion in batch mode"));
++ return GNUTLS_E_INVALID_REQUEST;
++ }
++
++ char msg[256] = { 0 };
++
++ size_t len = 0;
++ if (retry > 0)
++ len += snprintf(msg, sizeof msg, _("[Not found - attempt %u] "), retry + 1);
++
++ snprintf(msg + len, sizeof msg - len, _("Insert PKCS#11 token '%s' and press any key..."), label);
++
++ mutt_any_key_to_continue(msg);
++ return 0;
++}
++
++int tls_pin_callback(void *userdata, int attempt, const char *url, const char *label,
++ unsigned int flags, char *pin, size_t pin_max)
++{
++ (void) url;
++ const intptr_t is_token = (intptr_t) userdata;
++
++ if (OptNoCurses) {
++ mutt_error(_("Unable to prompt for pin in batch mode"));
++ return GNUTLS_E_INVALID_REQUEST;
++ }
++
++ char prompt[256] = { 0 };
++
++ size_t len = 0;
++ if (attempt > 0)
++ len += snprintf(prompt, sizeof prompt, _("[Attempt %d] "), attempt + 1);
++
++ if (flags & GNUTLS_PIN_FINAL_TRY)
++ len += mutt_str_copy(prompt + len, _("FINAL TRY - "), sizeof prompt - len);
++
++ if (is_token)
++ snprintf(prompt + len, sizeof prompt - len, _("Pin for PKCS#11 token '%s': "), label);
++ else
++ snprintf(prompt + len, sizeof prompt - len, _("Password for certificate '%s': "), label);
++
++ struct Buffer *buf = buf_pool_get();
++ const int rc = mw_get_field(prompt, buf, MUTT_COMP_PASS | MUTT_COMP_UNBUFFERED,
++ HC_OTHER, NULL, NULL);
++ mutt_str_copy(pin, buf_string(buf), pin_max);
++ buf_pool_release(&buf);
++
++ if (rc != 0)
++ return GNUTLS_E_APPLICATION_ERROR_MIN;
++
++ return 0;
++}
++
+ /**
+ * tls_init - Set up Gnu TLS
+ * @retval 0 Success
+@@ -104,6 +167,10 @@ static int tls_init(void)
+ return -1;
+ }
+
++ const intptr_t is_token = 1;
++ gnutls_pkcs11_set_pin_function(tls_pin_callback, (void *)is_token);
++ gnutls_pkcs11_set_token_function(tls_pkcs11_token_callback, NULL);
++
+ init_complete = true;
+ return 0;
+ }
+@@ -904,6 +971,9 @@ static int tls_negotiate(struct Connection *conn)
+ mutt_debug(LL_DEBUG2, "Using client certificate %s, key %s\n", c_ssl_client_cert, c_ssl_client_key);
+ gnutls_certificate_set_x509_key_file(data->xcred, c_ssl_client_cert,
+ c_ssl_client_key, GNUTLS_X509_FMT_PEM);
++
++ const intptr_t is_token = 0;
++ gnutls_certificate_set_pin_function(data->xcred, tls_pin_callback, (void *)is_token);
+ }
+
+ #ifdef HAVE_DECL_GNUTLS_VERIFY_DISABLE_TIME_CHECKS
+--
+2.49.0
+
diff --git a/home/pim/dav.nix b/home/pim/dav.nix
new file mode 100644
index 0000000..a0759e2
--- /dev/null
+++ b/home/pim/dav.nix
@@ -0,0 +1,54 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.dav;
+in {
+ options.local.dav = with types; {
+ enable = mkEnableOption "Web/Card/CalDAV";
+ };
+
+ config = mkIf cfg.enable {
+ systemd.user = {
+ services.xandikos = {
+ Unit = {
+ Description = "Xandikos CalDAV/CardDAV server";
+ };
+
+ Service = {
+ ExecStart = escapeShellArgs [
+ (getExe pkgs.xandikos)
+ "-d"
+ "${config.home.homeDirectory}/dav"
+ "--route-prefix"
+ "/${config.home.username}/dav"
+ "--current-user-principal"
+ "/user/"
+ # Hacerlo fallar si no agarra systemd socket activation por cualquier motivo
+ "-p"
+ "1"
+ ];
+
+ Type = "simple";
+ };
+ };
+
+ sockets.xandikos = {
+ Unit = {
+ Description = "Xandikos socket";
+ };
+
+ Socket = {
+ ListenStream = "/run/host-www/ale/dav.sock";
+ };
+
+ Install = {
+ WantedBy = ["sockets.target"];
+ };
+ };
+ };
+ };
+}
diff --git a/home/pim/default.nix b/home/pim/default.nix
new file mode 100644
index 0000000..b8afc81
--- /dev/null
+++ b/home/pim/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./dav.nix
+ ./mail.nix
+ ./syncthing.nix
+ ];
+}
diff --git a/home/pim/mail.nix b/home/pim/mail.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/home/pim/mail.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/home/pim/sieve/mail.sieve b/home/pim/sieve/mail.sieve
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/home/pim/sieve/mail.sieve
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/home/pim/syncthing.nix b/home/pim/syncthing.nix
new file mode 100644
index 0000000..9ed1708
--- /dev/null
+++ b/home/pim/syncthing.nix
@@ -0,0 +1,18 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.syncthing;
+in {
+ options.local.syncthing = {
+ enable = mkEnableOption "syncthing";
+ };
+
+ config = mkIf cfg.enable {
+ services.syncthing = {
+ enable = true;
+ };
+ };
+}
diff --git a/home/platform/README.md b/home/platform/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/home/platform/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/home/profiles/README.md b/home/profiles/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/home/profiles/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/home/shenvs/README.md b/home/shenvs/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/home/shenvs/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/hooks/README b/hooks/README
new file mode 100644
index 0000000..176dc1c
--- /dev/null
+++ b/hooks/README
@@ -0,0 +1,2 @@
+$ git config core.hooksPath hooks
+$ man githooks
diff --git a/hooks/lib/update-zone-serials b/hooks/lib/update-zone-serials
new file mode 100755
index 0000000..e0a8585
--- /dev/null
+++ b/hooks/lib/update-zone-serials
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+nix eval --json '.#nixosConfigurations.gate.config.lib.local.zoneSerialUpdates' \
+ | nix run '.#increment-zone-serials' -- sys/ns \
+ | while read file; do nix fmt -- "$file"; git add -v -- "$file"; done
diff --git a/hooks/pre-commit b/hooks/pre-commit
new file mode 100755
index 0000000..93e9b9a
--- /dev/null
+++ b/hooks/pre-commit
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+
+set -e
+exec >&2
+
+if git diff-index --cached HEAD -- | grep -q $'\tsys/ns/'; then
+ exec hooks/lib/update-zone-serials
+fi
diff --git a/pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch b/pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch
new file mode 100644
index 0000000..e7fc5d5
--- /dev/null
+++ b/pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch
@@ -0,0 +1,25 @@
+From 5e7eb46f46af6a29a2aea19db722ebc28baede25 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sat, 21 Jun 2025 22:37:19 -0600
+Subject: [PATCH] Remove CheckUpdatePlugin from default list
+
+---
+ src/main/java/cr/libre/firmador/Settings.java | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/main/java/cr/libre/firmador/Settings.java b/src/main/java/cr/libre/firmador/Settings.java
+index e5ddf01..a028d6e 100644
+--- a/src/main/java/cr/libre/firmador/Settings.java
++++ b/src/main/java/cr/libre/firmador/Settings.java
+@@ -81,7 +81,7 @@ public class Settings {
+
+ public Settings() {
+ activePlugins.add("cr.libre.firmador.plugins.DummyPlugin");
+- activePlugins.add("cr.libre.firmador.plugins.CheckUpdatePlugin");
++ // activePlugins.add("cr.libre.firmador.plugins.CheckUpdatePlugin");
+ availablePlugins.add("cr.libre.firmador.plugins.DummyPlugin");
+ availablePlugins.add("cr.libre.firmador.plugins.CheckUpdatePlugin");
+ }
+--
+2.49.0
+
diff --git a/pkgs/athena-bccr/LaunchGaudi.java b/pkgs/athena-bccr/LaunchGaudi.java
new file mode 100644
index 0000000..e4bcdbf
--- /dev/null
+++ b/pkgs/athena-bccr/LaunchGaudi.java
@@ -0,0 +1,12 @@
+// Los del BCCR no se molestaron en ponerle un main al Agente Gaudi porque el
+// actualizador (que a su vez sí tiene main) carga el jar en memoria y crea una
+// instancia de Inicializador usando reflexión. El actualizador no es relevante
+// en Nix. En todo caso, dicho actualizador es sumamente frágil y me daría
+// demasiada pereza arreglarlo, así que en su lugar usamos este stub para
+// launchear Gaudi.
+
+public class LaunchGaudi {
+ public static void main(String[] args) {
+ new InicializadorCliente.Inicializador("");
+ }
+}
diff --git a/pkgs/athena-bccr/default.nix b/pkgs/athena-bccr/default.nix
new file mode 100644
index 0000000..a5f79ca
--- /dev/null
+++ b/pkgs/athena-bccr/default.nix
@@ -0,0 +1,30 @@
+{
+ callPackage,
+ lib,
+}: let
+ latest = "deb64-rev26";
+
+ releases = lib.mapAttrs (name: release: release // {name = name;}) (import ./releases.nix);
+
+ overrideUnwrapped = default: new: let
+ args = default // new;
+ unwrappedPkgs = lib.filterAttrs (name: _: ! lib.elem name ["override" "overrideDerivation"]) (callPackage ./unwrapped.nix args);
+ in
+ lib.fix (unwrapped: lib.mapAttrs (_: pkg: callPackage pkg unwrapped) unwrappedPkgs)
+ // {
+ override = overrideUnwrapped args;
+ };
+
+ pkgsForRelease = release: let
+ ase-pkcs11 = unwrapped.ase-idprotect.lib;
+ libasep11 = "${ase-pkcs11}/lib/x64-athena/libASEP11.so";
+ unwrapped = overrideUnwrapped {inherit release;} {};
+ in {
+ inherit ase-pkcs11 libasep11;
+ inherit (unwrapped) ase-idprotect bccr-cacerts;
+
+ gaudi = callPackage ./gaudi-env.nix {inherit unwrapped;};
+ firmador = callPackage ./firmador.nix {inherit libasep11;};
+ };
+in
+ lib.mapAttrs (_: pkgsForRelease) (releases // {latest = releases.${latest};})
diff --git a/pkgs/athena-bccr/firmador.nix b/pkgs/athena-bccr/firmador.nix
new file mode 100644
index 0000000..d280b56
--- /dev/null
+++ b/pkgs/athena-bccr/firmador.nix
@@ -0,0 +1,57 @@
+{
+ fetchgit,
+ lib,
+ makeWrapper,
+ maven,
+ openjdk,
+ wrapGAppsHook,
+ libasep11 ? null,
+}: let
+ jdk = openjdk.override {
+ enableJavaFX = true;
+ };
+
+ version = "1.9.8";
+in
+ maven.buildMavenPackage {
+ pname = "firmador";
+ inherit version;
+
+ src = fetchgit {
+ url = "https://codeberg.org/firmador/firmador";
+ rev = version;
+ hash = "sha256-xdiVPjihRADPK4nG+WQHWsDzVYLCeN6ouQ6SDtjf1qQ=";
+ };
+
+ patches = [
+ ./0001-Remove-CheckUpdatePlugin-from-default-list.patch
+ ];
+
+ mvnHash = "sha256-h1zoStTgaE7toWWKq0Y0ahOORyltChwjmaMYjLgs1VE=";
+
+ nativeBuildInputs = [
+ makeWrapper
+ wrapGAppsHook
+ ];
+
+ postPatch = lib.optionalString (libasep11 != null) ''
+ sed -i 's@/usr/lib/x64-athena/libASEP11.so@${libasep11}@g' src/main/java/cr/libre/firmador/CRSigner.java
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ mkdir -p $out/bin $out/share/java
+ install -Dm644 target/firmador.jar $out/share/java
+
+ makeWrapper ${jdk}/bin/java $out/bin/firmador \
+ --add-flags "-jar $out/share/java/firmador.jar"
+
+ runHook postInstall
+ '';
+
+ meta = {
+ homepage = "https://firmador.libre.cr";
+ license = lib.licenses.gpl3Plus;
+ };
+ }
diff --git a/pkgs/athena-bccr/gaudi-env.nix b/pkgs/athena-bccr/gaudi-env.nix
new file mode 100644
index 0000000..0ca1b82
--- /dev/null
+++ b/pkgs/athena-bccr/gaudi-env.nix
@@ -0,0 +1,62 @@
+{
+ buildFHSEnv,
+ curl,
+ lib,
+ writeShellScriptBin,
+ gaudiHash ? null,
+ unwrapped,
+}: let
+ unwrappedWithGaudi = unwrapped.override {inherit gaudiHash;};
+in
+ buildFHSEnv {
+ name = "gaudi";
+
+ targetPkgs = pkgs: [
+ unwrappedWithGaudi.ase-idprotect.lib
+ unwrappedWithGaudi.gaudi
+
+ (writeShellScriptBin "launch-gaudi" ''
+ set -o errexit
+ set -o pipefail
+ set -o nounset
+
+ PATH="${lib.makeBinPath [curl]}:$PATH"
+
+ echo "$0: testing for incompatible releases..." >&2
+
+ jar_name=bccr-firma-fva-clienteMultiplataforma.jar
+ url="https://www.firmadigital.go.cr/Bccr.Firma.Fva.Actualizador.ClienteFirmadorJava//recursosLiberica17/actualizador/$jar_name"
+ ca_file="${unwrappedWithGaudi.bccr-cacerts}/root-ca.pem"
+ url_hash=$(curl -sS --cacert "$ca_file" "$url" | sha256sum | cut -d' ' -f1)
+ jar_path="${unwrappedWithGaudi.gaudi}/share/java/$jar_name"
+ jar_hash=$(sha256sum "$jar_path" | cut -d' ' -f1)
+
+ if [ "$url_hash" != "$jar_hash" ]; then
+ last_modified=$(curl -sS --head --cacert "$ca_file" "$url" | grep -i '^last-modified:' | head -1)
+
+ echo "$0: sha256 mismatch for $jar_path due to server-side update" >&2
+ echo "$0: expected: $url_hash" >&2
+ echo "$0: actual: $jar_hash" >&2
+ echo "$0: $last_modified" >&2
+ echo "$0: run the following to download the new client JAR, then update your derivation:" >&2
+ echo "$0: \$ ${unwrappedWithGaudi.update-gaudi}" >&2
+
+ exit 1
+ fi
+
+ cache_path_1="''${XDG_CACHE_HOME:-$HOME/.cache}/Agente-GAUDI"
+ cache_path_2="''${XDG_CACHE_HOME:-$HOME/.cache}/Firmador-BCCR"
+
+ for cache_path in "$cache_path_1" "$cache_path_2"; do
+ mkdir -p "$cache_path"
+ ln -sf -- ${unwrappedWithGaudi.gaudi}/share/java/bccr-firma-fva-clienteMultiplataforma.jar "$cache_path"
+ done
+
+ cp -f --no-preserve=mode -t "$cache_path_1" -- "${unwrappedWithGaudi.gaudi}/share/java/config.properties"
+
+ exec gaudi
+ '')
+ ];
+
+ runScript = "launch-gaudi";
+ }
diff --git a/pkgs/athena-bccr/releases.nix b/pkgs/athena-bccr/releases.nix
new file mode 100644
index 0000000..e965172
--- /dev/null
+++ b/pkgs/athena-bccr/releases.nix
@@ -0,0 +1,12 @@
+{
+ "deb64-rev26" = {
+ # nix hash convert --hash-algo sha256 --from base16 --to sri $(sha256sum sfd_ClientesLinux_DEB64_Rev26.zip | cut -d' ' -f1)
+ hash = "sha256-ZPWP9TqJQ5coJAPzUSiaXKVItBWlqFM4smCjOf+gqQM=";
+ basename = "sfd_ClientesLinux_DEB64_Rev26";
+
+ srcPaths = {
+ gaudi = "Firma Digital/Agente GAUDI/agente-gaudi_20.0_amd64.deb";
+ idprotect = "Firma Digital/PinTool/IDProtect PINTool 7.24.02/DEB/idprotectclient_7.24.02-0_amd64.deb";
+ };
+ };
+}
diff --git a/pkgs/athena-bccr/unwrapped.nix b/pkgs/athena-bccr/unwrapped.nix
new file mode 100644
index 0000000..d6f3f38
--- /dev/null
+++ b/pkgs/athena-bccr/unwrapped.nix
@@ -0,0 +1,226 @@
+{
+ lib,
+ requireFile,
+ release,
+ gaudiHash ? null,
+ ...
+}: let
+ inherit (release) srcPaths;
+
+ src = requireFile {
+ url = "https://soportefirmadigital.com";
+ name = "${release.basename}.zip";
+
+ inherit (release) hash;
+ };
+
+ gaudiUpdateSrc = {update-gaudi}:
+ requireFile {
+ url = "${update-gaudi}";
+ name = "gaudi-update-${release.name}.zip";
+
+ hash = gaudiHash;
+ };
+
+ moduleFromDeb = name: args @ {
+ stdenv,
+ dpkg,
+ unzip,
+ srcPath,
+ ...
+ }:
+ stdenv.mkDerivation ({
+ pname = "${name}-unwrapped";
+ version = release.name;
+
+ inherit src;
+
+ nativeBuildInputs = [dpkg unzip] ++ (args.nativeBuildInputs or []);
+
+ postUnpack = ''
+ dpkg -x ${lib.escapeShellArg "${release.basename}/${srcPath}"} ${lib.escapeShellArg release.basename}
+ '';
+ }
+ // lib.removeAttrs args ["stdenv" "dpkg" "unzip" "srcPath" "nativeBuildInputs"]);
+in {
+ ase-idprotect = {
+ autoPatchelfHook,
+ dpkg,
+ fontconfig,
+ freetype,
+ pcsclite,
+ stdenv,
+ unzip,
+ xorg,
+ zlib,
+ ...
+ }:
+ moduleFromDeb "ase-idprotect" {
+ inherit dpkg stdenv unzip;
+ srcPath = srcPaths.idprotect;
+
+ buildInputs = [
+ fontconfig
+ freetype
+ pcsclite
+ stdenv.cc.cc.lib
+ xorg.libX11
+ xorg.libXext
+ zlib
+ ];
+
+ nativeBuildInputs = [
+ autoPatchelfHook
+ ];
+
+ outputs = ["out" "lib"];
+
+ installPhase = ''
+ runHook preInstall
+
+ install -m755 -d $out/bin $lib/{etc,lib/x64-athena}
+ install -m755 usr/bin/IDProtect{_Manager,PINTool} $out/bin/
+ install -m755 usr/lib/x64-athena/* $lib/lib/x64-athena
+ cp -r etc/Athena $lib/etc/Athena
+
+ runHook postInstall
+ '';
+
+ preFixup = ''
+ patchelf --set-rpath $lib/lib/x64-athena $out/bin/*
+ '';
+ };
+
+ gaudi = {
+ autoPatchelfHook,
+ dpkg,
+ makeWrapper,
+ openjdk,
+ pkgs,
+ stdenv,
+ unzip,
+ writeShellScriptBin,
+ update-gaudi,
+ ...
+ }: let
+ jdk = openjdk.override {
+ enableJavaFX = true;
+ openjfx_jdk = pkgs."openjfx${lib.head (lib.splitString "." openjdk.version)}".override {withWebKit = true;};
+ };
+
+ fakeSudo = writeShellScriptBin "sudo" "";
+ gaudiUpdate = gaudiUpdateSrc {inherit update-gaudi;};
+ in
+ moduleFromDeb "gaudi" {
+ inherit dpkg stdenv unzip;
+ srcPath = srcPaths.gaudi;
+
+ nativeBuildInputs = [
+ autoPatchelfHook
+ jdk
+ makeWrapper
+ ];
+
+ preBuild = lib.optionalString (gaudiHash != null) ''
+ unzip -o ${gaudiUpdate} -d opt/Agente-GAUDI/lib/app
+ '';
+
+ buildPhase = ''
+ runHook preBuild
+
+ install -m755 -d $out/{bin,opt/Firmador-BCCR/lib}
+ cp -r opt/Agente-GAUDI/lib/app $out/opt/Firmador-BCCR/lib/app
+
+ # Preserves the original filename and avoids <hash>-LaunchGaudi.java
+ ln -s ${./LaunchGaudi.java} LaunchGaudi.java
+
+ javac \
+ -cp opt/Agente-GAUDI/lib/app/bccr-firma-fva-clienteMultiplataforma.jar \
+ -d $out/opt/Firmador-BCCR/lib/app \
+ LaunchGaudi.java
+
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ install -m755 -d $out/{share,opt/Firmador-BCCR/lib/runtime/lib}
+ install -m755 -D opt/Agente-GAUDI/bin/Agente-GAUDI $out/opt/Firmador-BCCR/bin/Agente-GAUDI
+ install -m755 -D opt/Agente-GAUDI/lib/libapplauncher.so $out/opt/Firmador-BCCR/lib/libapplauncher.so
+
+ ln -s ../opt/Firmador-BCCR/lib/app $out/share/java
+ ln -s Firmador-BCCR $out/opt/Agente-GAUDI
+ ln -s ${jdk}/lib/openjdk/lib/libjli.so $out/opt/Firmador-BCCR/lib/runtime/lib/libjli.so
+
+ makeWrapper ${jdk}/bin/java $out/bin/gaudi \
+ --prefix PATH : ${fakeSudo}/bin \
+ --add-flags "-cp $out/share/java:$out/share/java/bccr-firma-fva-clienteMultiplataforma.jar" \
+ --add-flags "-Djavax.net.ssl.trustStore=$out/opt/Firmador-BCCR/lib/app/bccr.cacerts" \
+ --add-flags "LaunchGaudi"
+
+ runHook postInstall
+ '';
+ };
+
+ bccr-cacerts = {
+ openssl,
+ stdenv,
+ unzip,
+ ...
+ }:
+ stdenv.mkDerivation {
+ pname = "bccr-cacerts";
+ version = release.name;
+
+ inherit src;
+
+ nativeBuildInputs = [
+ openssl
+ unzip
+ ];
+
+ installPhase = ''
+ cp -r Firma\ Digital/Certificados $out
+ openssl x509 -in $out/CA\ RAIZ\ NACIONAL\ -\ COSTA\ RICA\ v2.crt -out $out/root-ca.pem -text
+ '';
+ };
+
+ update-gaudi = {
+ wget,
+ writeShellScript,
+ zip,
+ bccr-cacerts,
+ ...
+ }:
+ writeShellScript "update-gaudi" ''
+ set -o errexit
+ set -o pipefail
+ set -o nounset
+
+ temp_dir="$(mktemp -d)"
+ trap 'cd / && rm -rf -- "$temp_dir"' EXIT
+ cd "$temp_dir"
+
+ PATH="${lib.makeBinPath [wget zip]}:$PATH"
+ ca_cert="${bccr-cacerts}/root-ca.pem"
+ base_url="https://www.firmadigital.go.cr/Bccr.Firma.Fva.Actualizador.ClienteFirmadorJava//recursosLiberica17/actualizador"
+
+ wget --ca-certificate="$ca_cert" "$base_url/bccr.cacerts"
+ wget --ca-certificate="$ca_cert" "$base_url/config.properties"
+ wget --ca-certificate="$ca_cert" "$base_url/bccr-firma-fva-clienteMultiplataforma.jar"
+ wget --ca-certificate="$ca_cert" "$base_url/ServicioActualizadorClienteBCCR.jar"
+
+ # https://gist.github.com/stokito/c588b8d6a6a0aee211393d68eea678f2
+ TZ=UTC find . -exec touch --no-dereference -a -m -t 198002010000.00 {} +
+ zip_path="$PWD/gaudi-update-${release.name}.zip"
+ TZ=UTC zip -q --move --recurse-paths --symlinks -X "$zip_path" .
+ TZ=UTC touch -a -m -t 198002010000.00 "$zip_path"
+
+ set -x
+ nix-store --add-fixed sha256 "$zip_path"
+ set +x
+
+ echo -e "\ngaudiHash: $(nix-hash --to-sri --type sha256 $(sha256sum "$zip_path" | cut -d' ' -f1))"
+ '';
+}
diff --git a/pkgs/btclone/btclone.nix b/pkgs/btclone/btclone.nix
new file mode 100755
index 0000000..68673a7
--- /dev/null
+++ b/pkgs/btclone/btclone.nix
@@ -0,0 +1,108 @@
+''
+ usage() { echo "Usage: $0 <subvolume> <target> [<up-to>]" >&2; exit 1; }
+
+ [[ $# -ge 2 && $# -le 3 && ( $# -ne 3 || $(("$3" + 0)) = "$3" ) ]] || usage
+ [[ $UID -eq 0 ]] || { echo "$0: requires root privileges" >&2; exit 1; }
+
+ SOURCE="$1"
+ TARGET="$2"
+ [ $# -ge 3 ] && UP_TO="$3" || UP_TO=
+
+ get_snapshots() {
+ FILTER="\$1 > 0"
+ [[ -n "$UP_TO" ]] && FILTER="\$1 > 0 && \$1 <= $UP_TO"
+
+ find "$1" -follow -maxdepth 1 -printf '%f\n' \
+ | sed 's@/$@@g' | awk "$FILTER { print }" | sort -n
+ }
+
+ clone() {
+ if [[ -n "$2" ]]; then
+ echo "Cloning $1 (incremental from $2)..." >&2
+ PARENT_ARG="-p$SOURCE/$2/snapshot"
+ else
+ echo "Cloning $1 (non-incremental)..." >&2
+ PARENT_ARG="--"
+ fi
+
+ FROM="$SOURCE/$1"
+ INTO="$TARGET/$1"
+
+ [[ -d "$INTO" ]] || mkdir "$INTO"
+ btrfs send "$PARENT_ARG" "$FROM/snapshot" | pv | btrfs receive "$INTO"
+ cp -a "$FROM/info.xml" "$INTO/"
+ }
+
+ cleanup() {
+ echo "Removing $1..." >&2
+
+ AT="$TARGET/$1"
+ [[ -d "$AT/snapshot" ]] && btrfs subvolume delete "$AT/snapshot"
+ rm -f "$AT/info.xml"
+ rmdir "$AT"
+ }
+
+ while true; do
+ ls -- "$SOURCE/" "$TARGET/" >/dev/null
+ mapfile -t SNAPSHOTS < <(get_snapshots "$SOURCE")
+ [[ ''${#SNAPSHOTS} -eq 0 ]] && { echo "$0: nothing to do" >&2; exit; }
+ mapfile -t EXISTENT < <(get_snapshots "$TARGET")
+
+ RESET=0
+ PARENT=
+ ALL_ARE_BAD=0
+ for SNAPSHOT in "''${SNAPSHOTS[@]}"; do
+ if [[ ! -e "$SOURCE/$SNAPSHOT" ]]; then
+ echo "Notice: resetting listings due to time lapse" >&2
+
+ RESET=1
+ break
+ elif [[ ! -s "$SOURCE/$SNAPSHOT/info.xml" ]]; then
+ echo "Warning: skipping source $SNAPSHOT due to invalid info.xml" >&2
+ continue
+ fi
+
+ CLONE=0
+ if [[ ! -e "$TARGET/$SNAPSHOT" ]]; then
+ CLONE=1
+ elif [[ $ALL_ARE_BAD -eq 1 || ! -f "$TARGET/$SNAPSHOT/info.xml" ]]; then
+ echo -n "Warning: bad copy $SNAPSHOT (" >&2
+ [[ $ALL_ARE_BAD -eq 1 ]] && echo -n "bad chain" >&2 || echo -n "incomplete" >&2
+ echo "), recreating..." >&2
+
+ cleanup "$SNAPSHOT"
+
+ CLONE=1
+ ALL_ARE_BAD=1
+ fi
+
+ if [[ $CLONE -eq 1 ]]; then
+ clone "$SNAPSHOT" "$PARENT"
+ elif [[ -z "$PARENT" ]]; then
+ echo "Initial snapshot present, all copies will be incremental" >&2
+ fi
+
+ chmod 750 "$TARGET/$SNAPSHOT"
+ PARENT="$SNAPSHOT"
+ done
+
+ [[ $RESET -eq 1 ]] && continue
+
+ echo "Copies updated, cleaning up..." >&2
+ for SNAPSHOT in "''${EXISTENT[@]}"; do
+ FOUND=""
+ for KEEP in "''${SNAPSHOTS[@]}"; do
+ if [ "$KEEP" = "$SNAPSHOT" ]; then
+ FOUND=1
+ break
+ fi
+ done
+
+ [ -n "$FOUND" ] || cleanup "$SNAPSHOT"
+ done
+
+ break
+ done
+
+ echo "Done" >&2
+''
diff --git a/pkgs/btclone/default.nix b/pkgs/btclone/default.nix
new file mode 100644
index 0000000..2484f33
--- /dev/null
+++ b/pkgs/btclone/default.nix
@@ -0,0 +1,11 @@
+{
+ btrfs-progs,
+ pv,
+ writeShellApplication,
+ ...
+}:
+writeShellApplication {
+ name = "btclone";
+ runtimeInputs = [btrfs-progs pv];
+ text = import ./btclone.nix;
+}
diff --git a/pkgs/cocotb/default.nix b/pkgs/cocotb/default.nix
new file mode 100644
index 0000000..12aebf4
--- /dev/null
+++ b/pkgs/cocotb/default.nix
@@ -0,0 +1,19 @@
+{
+ cocotb,
+ fetchFromGitHub,
+ find-libpython,
+}:
+cocotb.overridePythonAttrs (prev: {
+ version = "master-2023-03-16";
+
+ src = fetchFromGitHub {
+ repo = "cocotb";
+ owner = "cocotb";
+
+ rev = "7b33df04866ce1e74ff4ebc33ced8e30f59970de";
+ sha256 = "sha256-7IlEaGSnd47tTxRu8QGW9mExCCZe47S41tlQatACLxU=";
+ };
+
+ propagatedBuildInputs = [find-libpython];
+ doCheck = false;
+})
diff --git a/pkgs/cocotb/exts/wishbone.nix b/pkgs/cocotb/exts/wishbone.nix
new file mode 100644
index 0000000..44baa12
--- /dev/null
+++ b/pkgs/cocotb/exts/wishbone.nix
@@ -0,0 +1,25 @@
+{
+ buildPythonPackage,
+ cocotb,
+ cocotb-bus,
+ fetchFromGitHub,
+ git,
+ setuptools-scm,
+}:
+buildPythonPackage {
+ pname = "cocotbext-wishbone";
+ version = "master-2022-04-26";
+
+ src = fetchFromGitHub {
+ repo = "cocotbext-wishbone";
+ owner = "wallento";
+
+ rev = "3c667834f41c3c40dd4647b5a7b9e4e71e1302c4";
+ sha256 = "sha256-vden1hZ9V1aqxFWu/vKmOfWfzINAopJRKTPKOpOiNkU=";
+
+ leaveDotGit = true;
+ };
+
+ nativeBuildInputs = [git setuptools-scm];
+ propagatedBuildInputs = [cocotb cocotb-bus setuptools-scm];
+}
diff --git a/pkgs/config/default.nix b/pkgs/config/default.nix
new file mode 100644
index 0000000..9fc9c79
--- /dev/null
+++ b/pkgs/config/default.nix
@@ -0,0 +1,4 @@
+{lib}: {
+ android_sdk.accept_license = true;
+ allowUnfreePredicate = pkg: import ./unfree.nix lib (lib.getName pkg);
+}
diff --git a/pkgs/config/unfree.nix b/pkgs/config/unfree.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/pkgs/config/unfree.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/pkgs/default.nix b/pkgs/default.nix
new file mode 100644
index 0000000..6ddcb70
--- /dev/null
+++ b/pkgs/default.nix
@@ -0,0 +1,95 @@
+{
+ final,
+ prev,
+ flakes,
+}:
+with prev.lib; let
+ inherit (final) callPackage fetchpatch;
+in {
+ lib = callPackage ./lib {};
+
+ athena-bccr = callPackage ./athena-bccr {};
+ btclone = callPackage ./btclone {};
+ gem5 = callPackage ./gem5.nix {gem5ISA = "x86";};
+ git-aliases = callPackage ./git-aliases.nix {};
+ increment-zone-serials = callPackage ./increment-zone-serials {};
+ kbuild-standalone = callPackage ./kbuild-standalone.nix {};
+ mssql-tools = callPackage ./mssql-tools.nix {};
+ oregano = callPackage ./oregano {};
+ pass-bcr = callPackage ./pass-bcr {};
+ pass-tail = callPackage ./pass-tail {};
+ rqlite = callPackage ./rqlite.nix {};
+ rv8 = callPackage ./rv8.nix {};
+ scripts = callPackage ./scripts {};
+ simple-scalar = callPackage ./simple-scalar {};
+ spliit = callPackage ./spliit {};
+ tmux-lift = callPackage ./tmux-lift {};
+ tmux-open = callPackage ./tmux-open {};
+ tmux-pass = callPackage ./tmux-pass.nix {};
+
+ st = prev.st.override {
+ conf = import ./st.nix {};
+
+ patches = [
+ (fetchpatch {
+ url = "https://st.suckless.org/patches/clipboard/st-clipboard-0.8.3.diff";
+ sha256 = "cbb37675e9b4986836c19aadacc616a006df81c9bf394e9e3573e164fa1867cf";
+ })
+ ];
+ };
+
+ override =
+ {
+ home-assistant-custom-components =
+ prev.home-assistant-custom-components
+ // {
+ dreame_vacuum = final.home-assistant.python.pkgs.callPackage ./dreame-vacuum.nix {};
+ smartthinq_sensors = final.home-assistant.python.pkgs.callPackage ./smartthinq-sensors.nix {};
+ };
+
+ home-assistant-custom-lovelace-modules =
+ prev.home-assistant-custom-lovelace-modules
+ // {
+ xiaomi-vacuum-map-card = final.callPackage ./lovelace-xiaomi-vacuum-map-card {};
+ };
+
+ # Tomado de all-packages.nix
+ msmtp = callPackage ./msmtp {
+ inherit (final.darwin.apple_sdk.frameworks) Security;
+ autoreconfHook = final.buildPackages.autoreconfHook269;
+ };
+
+ postfix = callPackage ./postfix {inherit (prev) postfix;};
+ xandikos = final.python3Packages.callPackage ./xandikos {inherit (prev) xandikos;};
+ }
+ // (
+ let
+ makePyOverrides = version: let
+ name = "python3${toString version}";
+ in {
+ inherit name;
+
+ value = prev.${name}.override {
+ packageOverrides = nextPy: prevPy: {
+ cocotb = nextPy.callPackage ./cocotb {inherit (prevPy) cocotb;};
+ cocotbext-wishbone = nextPy.callPackage ./cocotb/exts/wishbone.nix {};
+ find-libpython = nextPy.callPackage ./find-libpython.nix {};
+ hdl-convertor = nextPy.callPackage ./hdl-convertor {};
+ hdl-convertor-ast = nextPy.callPackage ./hdl-convertor/ast.nix {};
+ iced-x86 = nextPy.callPackage ./iced-x86 {};
+ };
+ };
+ };
+
+ pyVersionRange' = start: end: let
+ next = end + 1;
+ in
+ if prev ? "python3${toString next}"
+ then pyVersionRange' start next
+ else range start end;
+
+ pyVersionRange = start: pyVersionRange' start start;
+ in
+ listToAttrs (map makePyOverrides (pyVersionRange 9))
+ );
+}
diff --git a/pkgs/dreame-vacuum.nix b/pkgs/dreame-vacuum.nix
new file mode 100644
index 0000000..1dd7255
--- /dev/null
+++ b/pkgs/dreame-vacuum.nix
@@ -0,0 +1,40 @@
+{
+ buildHomeAssistantComponent,
+ callPackage,
+ fetchFromGitHub,
+ numpy,
+ paho-mqtt,
+ pillow,
+ pybase64,
+ pycryptodome,
+ python-miio,
+ requests,
+}: let
+ version = "2.0.0b15";
+in
+ buildHomeAssistantComponent {
+ owner = "tasshack";
+ domain = "dreame_vacuum";
+ inherit version;
+
+ src = fetchFromGitHub {
+ repo = "dreame-vacuum";
+ owner = "Tasshack";
+
+ rev = "v${version}";
+ hash = "sha256-ydWirMQsO6DYU5UdygHRXCx8I3M7haYX9zPLela9H7E=";
+ };
+
+ dontBuild = true;
+
+ propagatedBuildInputs = [
+ numpy
+ paho-mqtt
+ pillow
+ pybase64
+ pycryptodome
+ python-miio
+ requests
+ (callPackage ./py-mini-racer.nix {})
+ ];
+ }
diff --git a/pkgs/find-libpython.nix b/pkgs/find-libpython.nix
new file mode 100644
index 0000000..cc351c3
--- /dev/null
+++ b/pkgs/find-libpython.nix
@@ -0,0 +1,15 @@
+{
+ buildPythonPackage,
+ fetchPypi,
+}: let
+ pname = "find_libpython";
+ version = "0.3.0";
+in
+ buildPythonPackage {
+ inherit pname version;
+
+ src = fetchPypi {
+ inherit pname version;
+ sha256 = "sha256-bn/l2a9/rW3AZstVFaDpyQpx8f6yuy+OTNu0+DJ26eU=";
+ };
+ }
diff --git a/pkgs/force-riscv/default.nix b/pkgs/force-riscv/default.nix
new file mode 100644
index 0000000..097fb8d
--- /dev/null
+++ b/pkgs/force-riscv/default.nix
@@ -0,0 +1,72 @@
+{
+ fetchFromGitHub,
+ lib,
+ makeWrapper,
+ python3,
+ stdenv,
+}:
+with lib;
+ stdenv.mkDerivation {
+ pname = "force-riscv";
+ version = "master-2023-01-31";
+
+ src = fetchFromGitHub {
+ repo = "force-riscv";
+ owner = "openhwgroup";
+
+ rev = "192bcc15e0dde8aaf25621da4317569b3f374047";
+ sha256 = "sha256-Eol973IMGRVAuw/rsYiK61+KVYkmbqq9yudaNbMCzJ0=";
+ };
+
+ buildInputs = [python3];
+ nativeBuildInputs = [makeWrapper];
+
+ patches = [
+ ./remove-pyeval-initthreads.patch
+ ./wno-error-range-loop-construct.patch
+ ./imageio-include-string.patch
+ ./testio-include-string.patch
+ ./urbg-static-constexpr-min-max.patch
+ ];
+
+ postPatch = ''
+ patchShebangs utils/ fpix/utils/
+ '';
+
+ makeFlags = [
+ "FORCE_CC=${stdenv.cc.targetPrefix}c++"
+ "FORCE_PYTHON_LIB=${python3}/lib"
+ "FORCE_PYTHON_INC=${python3}/include/${python3.libPrefix}"
+ ];
+
+ # Ver setenv.bash
+ installPhase = let
+ paths = [
+ "3rd_party/py"
+ "utils"
+ "utils/builder"
+ "utils/builder/test_builder"
+ "utils/builder/shared"
+ "utils/regression"
+ ];
+
+ pythonPath = concatStringsSep ":" (map (p: "$out/${p}") paths);
+ in ''
+ mkdir -p $out/ $out/fpix/ $out/riscv/ $out/3rd_party/
+
+ # SimApiHANDCAR.so queda en bin (?), al parecer es así
+ cp -r bin/ py/ $out/
+ cp -r fpix/bin/ $out/fpix/
+
+ for BIN in $out/bin/friscv $out/fpix/bin/fpix_riscv; do
+ wrapProgram $BIN \
+ --prefix PYTHONPATH : ${pythonPath}
+ done
+
+ rm -r utils/handcar/make_area
+
+ cp -r 3rd_party/py/ $out/3rd_party/
+ cp -r config/ utils/ $out/
+ cp -r riscv/arch_data/ $out/riscv/
+ '';
+ }
diff --git a/pkgs/force-riscv/imageio-include-string.patch b/pkgs/force-riscv/imageio-include-string.patch
new file mode 100644
index 0000000..90417c1
--- /dev/null
+++ b/pkgs/force-riscv/imageio-include-string.patch
@@ -0,0 +1,12 @@
+diff --git a/base/inc/ImageIO.h b/base/inc/ImageIO.h
+index f93866c..046dacb 100644
+--- a/base/inc/ImageIO.h
++++ b/base/inc/ImageIO.h
+@@ -17,6 +17,7 @@
+ #define Force_ImageIO_H
+
+ #include <map>
++#include <string>
+
+ #include "Defines.h"
+
diff --git a/pkgs/force-riscv/remove-pyeval-initthreads.patch b/pkgs/force-riscv/remove-pyeval-initthreads.patch
new file mode 100644
index 0000000..b31f0e2
--- /dev/null
+++ b/pkgs/force-riscv/remove-pyeval-initthreads.patch
@@ -0,0 +1,12 @@
+diff --git a/3rd_party/inc/pybind11/detail/internals.h b/3rd_party/inc/pybind11/detail/internals.h
+index 86fbe92..31ff371 100644
+--- a/3rd_party/inc/pybind11/detail/internals.h
++++ b/3rd_party/inc/pybind11/detail/internals.h
+@@ -265,7 +265,6 @@ PYBIND11_NOINLINE inline internals &get_internals() {
+ auto *&internals_ptr = *internals_pp;
+ internals_ptr = new internals();
+ #if defined(WITH_THREAD)
+- PyEval_InitThreads();
+ PyThreadState *tstate = PyThreadState_Get();
+ #if PY_VERSION_HEX >= 0x03070000
+ internals_ptr->tstate = PyThread_tss_alloc();
diff --git a/pkgs/force-riscv/testio-include-string.patch b/pkgs/force-riscv/testio-include-string.patch
new file mode 100644
index 0000000..5b36d9f
--- /dev/null
+++ b/pkgs/force-riscv/testio-include-string.patch
@@ -0,0 +1,12 @@
+diff --git a/base/inc/TestIO.h b/base/inc/TestIO.h
+index 7d28c32..08a9167 100644
+--- a/base/inc/TestIO.h
++++ b/base/inc/TestIO.h
+@@ -17,6 +17,7 @@
+ #define Force_TestIO_H
+
+ #include <map>
++#include <string>
+
+ #include "Defines.h"
+
diff --git a/pkgs/force-riscv/urbg-static-constexpr-min-max.patch b/pkgs/force-riscv/urbg-static-constexpr-min-max.patch
new file mode 100644
index 0000000..a047fd0
--- /dev/null
+++ b/pkgs/force-riscv/urbg-static-constexpr-min-max.patch
@@ -0,0 +1,15 @@
+diff --git a/base/inc/Random.h b/base/inc/Random.h
+index 6354dee..21660a9 100644
+--- a/base/inc/Random.h
++++ b/base/inc/Random.h
+@@ -56,8 +56,8 @@ namespace Force {
+ class RandomURBG32 {
+ public:
+ typedef uint32 result_type; //!< Type define required by STL
+- uint32 min() const { return 0; } //!< min function required by STL
+- uint32 max() const { return MAX_UINT32; } //!< max function required by STL
++ static constexpr uint32 min() { return 0; } //!< min function required by STL
++ static constexpr uint32 max() { return MAX_UINT32; } //!< max function required by STL
+ uint32 operator () () const { return mpRandomInstance->Random32(min(), max()); }
+
+ explicit RandomURBG32(const Random* randomInstance) : mpRandomInstance(randomInstance) { } //!< Constructor with pointer to a Random object provieded.
diff --git a/pkgs/force-riscv/wno-error-range-loop-construct.patch b/pkgs/force-riscv/wno-error-range-loop-construct.patch
new file mode 100644
index 0000000..034d522
--- /dev/null
+++ b/pkgs/force-riscv/wno-error-range-loop-construct.patch
@@ -0,0 +1,13 @@
+diff --git a/utils/make/Makefile.common b/utils/make/Makefile.common
+index d0c96d3..422f6eb 100644
+--- a/utils/make/Makefile.common
++++ b/utils/make/Makefile.common
+@@ -60,7 +60,7 @@ else
+ PYTHON_LIB_TYPE=
+ endif
+
+-CFLAGS = -Wall -std=c++11 -gdwarf-3 -m64 -Werror $(OPTIMIZATION) $(PICKY_FLAGS) $(VISIBILITY) -D $(ARCH_ENUM_HEADER)
++CFLAGS = -Wall -std=c++11 -gdwarf-3 -m64 -Werror $(OPTIMIZATION) $(PICKY_FLAGS) $(VISIBILITY) -D $(ARCH_ENUM_HEADER) -Wno-error=range-loop-construct
+ LFLAGS = -lpthread -static-libstdc++ -static-libgcc -L$(PYTHON_LIB) -lpython$(PYTHON_VER)$(PYTHON_LIB_TYPE) -lutil -ldl -rdynamic
+
+ ALL_OBJS := $(ALL_SRCS:%.cc=$(OBJ_DIR)/%.o)
diff --git a/pkgs/gem5.nix b/pkgs/gem5.nix
new file mode 100644
index 0000000..9795c0e
--- /dev/null
+++ b/pkgs/gem5.nix
@@ -0,0 +1,66 @@
+{
+ boost,
+ lib,
+ fetchFromGitHub,
+ gnum4,
+ gperftools,
+ hdf5-cpp,
+ libpng,
+ protobuf,
+ python3,
+ scons,
+ stdenv,
+ zlib,
+ enableHdf5 ? true,
+ enableLibpng ? true,
+ enableTrace ? true,
+ enableSystemC ? true,
+ enableTcmalloc ? true,
+ gem5ISA,
+}: let
+ version = "22.1.0.0";
+
+ isa = assert lib.assertMsg (lib.elem gem5ISA ["arm" "null" "mips" "power" "x86"])
+ "${gem5ISA} is not a valid gem5 target ISA";
+ lib.toUpper gem5ISA;
+
+ target = "build/${isa}/gem5.opt";
+in
+ stdenv.mkDerivation {
+ pname = "gem5";
+ version = "${gem5ISA}-${version}";
+
+ src = fetchFromGitHub {
+ repo = "gem5";
+ owner = "gem5";
+
+ rev = "v${version}";
+ sha256 = "sha256-Yxag8emR6hf7oX4GAtQi/YYcKrpXicUoQg5+rjKyjc0=";
+ };
+
+ buildInputs =
+ [zlib]
+ ++ lib.optional enableHdf5 hdf5-cpp
+ ++ lib.optional enableLibpng libpng
+ ++ lib.optional enableTrace boost
+ ++ lib.optional enableSystemC protobuf
+ ++ lib.optional enableTcmalloc gperftools;
+
+ nativeBuildInputs = [gnum4 scons];
+
+ sconsFlags = [target];
+
+ enableParallelBuilding = true;
+
+ # Without this we get "ValueError: invalid width 0 (must be > 0)"
+ COLUMNS = 80;
+
+ postPatch = ''
+ patchShebangs util/
+ '';
+
+ installPhase = ''
+ mkdir -p $out/bin/
+ cp ${target} $out/bin/
+ '';
+ }
diff --git a/pkgs/git-aliases.nix b/pkgs/git-aliases.nix
new file mode 100644
index 0000000..0b88f12
--- /dev/null
+++ b/pkgs/git-aliases.nix
@@ -0,0 +1,107 @@
+{writeText, ...}:
+writeText "git-aliases.zsh" ''
+ alias g='git'
+ alias ga='git add'
+ alias gaa='git add --all'
+ alias gapa='git add --patch'
+ alias gau='git add --update'
+ alias gap='git apply'
+ alias gb='git branch'
+ alias gba='git branch -a'
+ alias gbd='git branch -d'
+ alias gbl='git blame -b -w'
+ alias gbnm='git branch --no-merged'
+ alias gbr='git branch --remote'
+ alias gbs='git bisect'
+ alias gbsb='git bisect bad'
+ alias gbsg='git bisect good'
+ alias gbsr='git bisect reset'
+ alias gbss='git bisect start'
+ alias gc='git commit -v'
+ alias gc!='git commit -v --amend'
+ alias gcn!='git commit -v --no-edit --amend'
+ alias gca='git commit -v -a'
+ alias gca!='git commit -v -a --amend'
+ alias gcan!='git commit -v -a --no-edit --amend'
+ alias gcans!='git commit -v -a -s --no-edit --amend'
+ alias gcam='git commit -a -m'
+ alias gcsm='git commit -s -m'
+ alias gcb='git checkout -b'
+ alias gcf='git config --list'
+ alias gcl='git clone --recursive'
+ alias gclean='git clean -fd'
+ alias gpristine='git reset --hard && git clean -dfx'
+ alias gcm='git checkout master'
+ alias gcd='git checkout develop'
+ alias gcmsg='git commit -m'
+ alias gco='git checkout'
+ alias gcount='git shortlog -sn'
+ alias gcp='git cherry-pick'
+ alias gcpa='git cherry-pick --abort'
+ alias gcpc='git cherry-pick --continue'
+ alias gcs='git commit -S'
+ alias gd='git diff'
+ alias gdca='git diff --cached'
+ alias gdcw='git diff --cached --word-diff'
+ alias gdct='git describe --tags `git rev-list --tags --max-count=1`'
+ alias gdt='git diff-tree --no-commit-id --name-only -r'
+ alias gdw='git diff --word-diff'
+ alias gf='git fetch'
+ alias ghh='git help'
+ alias gl='git pull'
+ alias glg='git log --stat'
+ alias glgp='git log --stat -p'
+ alias glgg='git log --graph'
+ alias glgga='git log --graph --decorate --all'
+ alias glgm='git log --graph --max-count=10'
+ alias glo='git log --oneline --decorate'
+ alias glol="git log --graph --pretty='%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
+ alias glola="git log --graph --pretty='%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --all"
+ alias glog='git log --oneline --decorate --graph'
+ alias gloga='git log --oneline --decorate --graph --all'
+ alias gm='git merge'
+ alias gmom='git merge origin/master'
+ alias gmt='git mergetool --no-prompt'
+ alias gmtvim='git mergetool --no-prompt --tool=vimdiff'
+ alias gmum='git merge upstream/master'
+ alias gma='git merge --abort'
+ alias gp='git push'
+ alias gpd='git push --dry-run'
+ alias gpu='git push upstream'
+ alias gpv='git push -v'
+ alias gr='git remote'
+ alias gra='git remote add'
+ alias grb='git rebase'
+ alias grba='git rebase --abort'
+ alias grbc='git rebase --continue'
+ alias grbi='git rebase -i'
+ alias grbm='git rebase master'
+ alias grbs='git rebase --skip'
+ alias grh='git reset HEAD'
+ alias grhh='git reset HEAD --hard'
+ alias grmv='git remote rename'
+ alias grrm='git remote remove'
+ alias grset='git remote set-url'
+ alias gru='git reset --'
+ alias grup='git remote update'
+ alias grv='git remote -v'
+ alias gsb='git status -sb'
+ alias gsi='git submodule init'
+ alias gsps='git show --pretty=short --show-signature'
+ alias gss='git status -s'
+ alias gst='git status'
+ alias gsta='git stash save'
+ alias gstaa='git stash apply'
+ alias gstc='git stash clear'
+ alias gstd='git stash drop'
+ alias gstl='git stash list'
+ alias gstp='git stash pop'
+ alias gsts='git stash show --text'
+ alias gsu='git submodule update'
+ alias gts='git tag -s'
+ alias gtv='git tag | sort -V'
+ alias gunwip='git log -n 1 | grep -q -c "\-\-wip\-\-" && git reset HEAD~1'
+ alias gwip='git add -A; git rm $(git ls-files --deleted) 2> /dev/null; git commit --no-verify -m "--wip-- [skip ci]"'
+
+ alias gmnoff='git merge --no-ff --no-edit'
+''
diff --git a/pkgs/hdl-convertor/0001-to.verilog-fix-always_ff-sensitivity-list.patch b/pkgs/hdl-convertor/0001-to.verilog-fix-always_ff-sensitivity-list.patch
new file mode 100644
index 0000000..876751a
--- /dev/null
+++ b/pkgs/hdl-convertor/0001-to.verilog-fix-always_ff-sensitivity-list.patch
@@ -0,0 +1,25 @@
+From 6fa92c4aab7b212de79c023ef8320a9cc6fd45c3 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sun, 2 Apr 2023 00:00:44 -0600
+Subject: [PATCH] to.verilog: fix always_ff sensitivity list
+
+---
+ hdlConvertorAst/to/verilog/stm.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/hdlConvertorAst/to/verilog/stm.py b/hdlConvertorAst/to/verilog/stm.py
+index 28f3676..7b7dd99 100644
+--- a/hdlConvertorAst/to/verilog/stm.py
++++ b/hdlConvertorAst/to/verilog/stm.py
+@@ -92,7 +92,7 @@ class ToVerilog2005Stm(ToVerilog2005Expr):
+ w("always_latch ")
+ else:
+ raise ValueError(proc.trigger_constrain)
+- if tr is None:
++ if tr in (None, HdlStmProcessTriggerConstrain.FF):
+ w("@(")
+ for last, item in iter_with_last(sens):
+ self.visit_iHdlExpr(item)
+--
+2.38.4
+
diff --git a/pkgs/hdl-convertor/0002-to.hdl_ast_-visit-sensitivity-lists.patch b/pkgs/hdl-convertor/0002-to.hdl_ast_-visit-sensitivity-lists.patch
new file mode 100644
index 0000000..9e97551
--- /dev/null
+++ b/pkgs/hdl-convertor/0002-to.hdl_ast_-visit-sensitivity-lists.patch
@@ -0,0 +1,39 @@
+From 495dd2b13abe4aa1f3fb8cd40f6d81706e5c8943 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Wed, 5 Apr 2023 13:47:35 -0600
+Subject: [PATCH 2/2] to.hdl_ast_*: visit sensitivity lists
+
+---
+ hdlConvertorAst/to/hdl_ast_modifier.py | 2 ++
+ hdlConvertorAst/to/hdl_ast_visitor.py | 2 ++
+ 2 files changed, 4 insertions(+)
+
+diff --git a/hdlConvertorAst/to/hdl_ast_modifier.py b/hdlConvertorAst/to/hdl_ast_modifier.py
+index 7431ab9..9289475 100644
+--- a/hdlConvertorAst/to/hdl_ast_modifier.py
++++ b/hdlConvertorAst/to/hdl_ast_modifier.py
+@@ -163,6 +163,8 @@ class HdlAstModifier(HdlAstVisitor):
+ """
+ self.visit_doc(o)
+ o.body = self.visit_iHdlStatement(o.body)
++ if o.sensitivity:
++ self.visit_iHdlObj_list(o.sensitivity, self.visit_iHdlExpr)
+ return o
+
+ def visit_HdlStmBlock(self, o):
+diff --git a/hdlConvertorAst/to/hdl_ast_visitor.py b/hdlConvertorAst/to/hdl_ast_visitor.py
+index 5258b74..1441c39 100644
+--- a/hdlConvertorAst/to/hdl_ast_visitor.py
++++ b/hdlConvertorAst/to/hdl_ast_visitor.py
+@@ -224,6 +224,8 @@ class HdlAstVisitor(object):
+ """
+ self.visit_doc(o)
+ self.visit_iHdlStatement(o.body)
++ for expr in o.sensitivity or ():
++ self.visit_iHdlExpr(expr)
+ return o
+
+ def visit_HdlStmBlock(self, o):
+--
+2.38.4
+
diff --git a/pkgs/hdl-convertor/ast.nix b/pkgs/hdl-convertor/ast.nix
new file mode 100644
index 0000000..d6f833b
--- /dev/null
+++ b/pkgs/hdl-convertor/ast.nix
@@ -0,0 +1,22 @@
+{
+ lib,
+ buildPythonPackage,
+ fetchFromGitHub,
+}:
+buildPythonPackage {
+ pname = "hdl-convertor-ast";
+ version = "master-2022-07-25";
+
+ src = fetchFromGitHub {
+ repo = "hdlConvertorAst";
+ owner = "Nic30";
+
+ rev = "d2670f0374bd7a303a4bd8ce60da7206c45e8ac3";
+ sha256 = "sha256-u0lBzltM/6l3EuW0ppAVAGWhU7QEx0Cx6mTgaZKdHkg=";
+ };
+
+ patches = [
+ ./0001-to.verilog-fix-always_ff-sensitivity-list.patch
+ ./0002-to.hdl_ast_-visit-sensitivity-lists.patch
+ ];
+}
diff --git a/pkgs/hdl-convertor/default.nix b/pkgs/hdl-convertor/default.nix
new file mode 100644
index 0000000..12581aa
--- /dev/null
+++ b/pkgs/hdl-convertor/default.nix
@@ -0,0 +1,45 @@
+{
+ antlr,
+ buildPythonPackage,
+ cmake,
+ cython,
+ fetchFromGitHub,
+ hdl-convertor-ast,
+ jre,
+ python3,
+ scikit-build,
+}:
+buildPythonPackage {
+ pname = "hdl-convertor";
+ version = "master-2023-03-21";
+
+ src = fetchFromGitHub {
+ repo = "hdlConvertor";
+ owner = "Nic30";
+
+ rev = "b6ba0f4e61adf776cad8ed08760f8d232a4fc663";
+ sha256 = "sha256-Ketz5r7Z8kjshr7mjfdqF+QAOHGM/iTDpT6TMbYl6QU=";
+ };
+
+ nativeBuildInputs = [antlr cmake jre cython];
+ propagatedBuildInputs = [antlr.runtime.cpp hdl-convertor-ast];
+ propagatedNativeBuildInputs = [scikit-build];
+
+ postPatch = ''
+ sed -i 's/antlr4\(-complete\)/${antlr.name}\1/g' src/CMake_antlr4.txt
+ '';
+
+ doCheck = false;
+ dontUseCmakeConfigure = true;
+
+ # src/CMake_antlr4.txt espera una env var, no hay otra forma
+ ANTLR_COMPLETE_PATH = "${antlr}/share/java";
+
+ # No usamos cmakeArgs ya que esto lo interpreta skbuild y no el cmake hook de nixpkgs
+ CMAKE_ARGS = [
+ "-DHDLCONVERTOR_PYTHON=true"
+ "-DANTLR_COMPLETE_PATH=${antlr}/share/java"
+ "-DANTLR4CPP_LIBRARIES=${antlr.runtime.cpp}/lib/libantlr4-runtime.so"
+ "-DANTLR4CPP_INCLUDE_DIRS=${antlr.runtime.cpp.dev}/include/antlr4-runtime"
+ ];
+}
diff --git a/pkgs/iced-x86/0001-add-Cargo.lock.patch b/pkgs/iced-x86/0001-add-Cargo.lock.patch
new file mode 100644
index 0000000..c19accd
--- /dev/null
+++ b/pkgs/iced-x86/0001-add-Cargo.lock.patch
@@ -0,0 +1,325 @@
+From 37a120acff59bf997c7272c61e330338d174b4ad Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sun, 11 Jun 2023 20:52:02 -0600
+Subject: [PATCH] add Cargo.lock
+
+---
+ Cargo.lock | 306 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 306 insertions(+)
+ create mode 100644 Cargo.lock
+
+diff --git a/Cargo.lock b/Cargo.lock
+new file mode 100644
+index 0000000..ff4224e
+--- /dev/null
++++ b/Cargo.lock
+@@ -0,0 +1,306 @@
++# This file is automatically @generated by Cargo.
++# It is not intended for manual editing.
++version = 3
++
++[[package]]
++name = "autocfg"
++version = "1.1.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
++
++[[package]]
++name = "bincode"
++version = "1.3.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
++dependencies = [
++ "serde",
++]
++
++[[package]]
++name = "bitflags"
++version = "1.3.2"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
++
++[[package]]
++name = "cfg-if"
++version = "1.0.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
++
++[[package]]
++name = "iced-x86"
++version = "1.19.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "b7cc8d38244d84278262c8ebe6930cc44283d194cbabae2651f6112103802fb5"
++dependencies = [
++ "lazy_static",
++ "serde",
++]
++
++[[package]]
++name = "iced-x86-py"
++version = "1.19.0"
++dependencies = [
++ "bincode",
++ "iced-x86",
++ "pyo3",
++]
++
++[[package]]
++name = "indoc"
++version = "1.0.9"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
++
++[[package]]
++name = "lazy_static"
++version = "1.4.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
++
++[[package]]
++name = "libc"
++version = "0.2.146"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
++
++[[package]]
++name = "lock_api"
++version = "0.4.10"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
++dependencies = [
++ "autocfg",
++ "scopeguard",
++]
++
++[[package]]
++name = "memoffset"
++version = "0.6.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
++dependencies = [
++ "autocfg",
++]
++
++[[package]]
++name = "once_cell"
++version = "1.18.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
++
++[[package]]
++name = "parking_lot"
++version = "0.12.1"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
++dependencies = [
++ "lock_api",
++ "parking_lot_core",
++]
++
++[[package]]
++name = "parking_lot_core"
++version = "0.9.8"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
++dependencies = [
++ "cfg-if",
++ "libc",
++ "redox_syscall",
++ "smallvec",
++ "windows-targets",
++]
++
++[[package]]
++name = "proc-macro2"
++version = "1.0.60"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
++dependencies = [
++ "unicode-ident",
++]
++
++[[package]]
++name = "pyo3"
++version = "0.17.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "268be0c73583c183f2b14052337465768c07726936a260f480f0857cb95ba543"
++dependencies = [
++ "cfg-if",
++ "indoc",
++ "libc",
++ "memoffset",
++ "parking_lot",
++ "pyo3-build-config",
++ "pyo3-ffi",
++ "pyo3-macros",
++ "unindent",
++]
++
++[[package]]
++name = "pyo3-build-config"
++version = "0.17.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "28fcd1e73f06ec85bf3280c48c67e731d8290ad3d730f8be9dc07946923005c8"
++dependencies = [
++ "once_cell",
++ "target-lexicon",
++]
++
++[[package]]
++name = "pyo3-ffi"
++version = "0.17.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "0f6cb136e222e49115b3c51c32792886defbfb0adead26a688142b346a0b9ffc"
++dependencies = [
++ "libc",
++ "pyo3-build-config",
++]
++
++[[package]]
++name = "pyo3-macros"
++version = "0.17.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "94144a1266e236b1c932682136dc35a9dee8d3589728f68130c7c3861ef96b28"
++dependencies = [
++ "proc-macro2",
++ "pyo3-macros-backend",
++ "quote",
++ "syn",
++]
++
++[[package]]
++name = "pyo3-macros-backend"
++version = "0.17.3"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "c8df9be978a2d2f0cdebabb03206ed73b11314701a5bfe71b0d753b81997777f"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "syn",
++]
++
++[[package]]
++name = "quote"
++version = "1.0.28"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
++dependencies = [
++ "proc-macro2",
++]
++
++[[package]]
++name = "redox_syscall"
++version = "0.3.5"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
++dependencies = [
++ "bitflags",
++]
++
++[[package]]
++name = "scopeguard"
++version = "1.1.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
++
++[[package]]
++name = "serde"
++version = "1.0.164"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
++
++[[package]]
++name = "smallvec"
++version = "1.10.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
++
++[[package]]
++name = "syn"
++version = "1.0.109"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
++dependencies = [
++ "proc-macro2",
++ "quote",
++ "unicode-ident",
++]
++
++[[package]]
++name = "target-lexicon"
++version = "0.12.7"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5"
++
++[[package]]
++name = "unicode-ident"
++version = "1.0.9"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
++
++[[package]]
++name = "unindent"
++version = "0.1.11"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c"
++
++[[package]]
++name = "windows-targets"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
++dependencies = [
++ "windows_aarch64_gnullvm",
++ "windows_aarch64_msvc",
++ "windows_i686_gnu",
++ "windows_i686_msvc",
++ "windows_x86_64_gnu",
++ "windows_x86_64_gnullvm",
++ "windows_x86_64_msvc",
++]
++
++[[package]]
++name = "windows_aarch64_gnullvm"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
++
++[[package]]
++name = "windows_aarch64_msvc"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
++
++[[package]]
++name = "windows_i686_gnu"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
++
++[[package]]
++name = "windows_i686_msvc"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
++
++[[package]]
++name = "windows_x86_64_gnu"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
++
++[[package]]
++name = "windows_x86_64_gnullvm"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
++
++[[package]]
++name = "windows_x86_64_msvc"
++version = "0.48.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+--
+2.40.1
+
diff --git a/pkgs/iced-x86/Cargo.lock b/pkgs/iced-x86/Cargo.lock
new file mode 100644
index 0000000..ff4224e
--- /dev/null
+++ b/pkgs/iced-x86/Cargo.lock
@@ -0,0 +1,306 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "iced-x86"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7cc8d38244d84278262c8ebe6930cc44283d194cbabae2651f6112103802fb5"
+dependencies = [
+ "lazy_static",
+ "serde",
+]
+
+[[package]]
+name = "iced-x86-py"
+version = "1.19.0"
+dependencies = [
+ "bincode",
+ "iced-x86",
+ "pyo3",
+]
+
+[[package]]
+name = "indoc"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa799dd5ed20a7e349f3b4639aa80d74549c81716d9ec4f994c9b5815598306"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.146"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
+
+[[package]]
+name = "lock_api"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.18.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "pyo3"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "268be0c73583c183f2b14052337465768c07726936a260f480f0857cb95ba543"
+dependencies = [
+ "cfg-if",
+ "indoc",
+ "libc",
+ "memoffset",
+ "parking_lot",
+ "pyo3-build-config",
+ "pyo3-ffi",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-build-config"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28fcd1e73f06ec85bf3280c48c67e731d8290ad3d730f8be9dc07946923005c8"
+dependencies = [
+ "once_cell",
+ "target-lexicon",
+]
+
+[[package]]
+name = "pyo3-ffi"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f6cb136e222e49115b3c51c32792886defbfb0adead26a688142b346a0b9ffc"
+dependencies = [
+ "libc",
+ "pyo3-build-config",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94144a1266e236b1c932682136dc35a9dee8d3589728f68130c7c3861ef96b28"
+dependencies = [
+ "proc-macro2",
+ "pyo3-macros-backend",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.17.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8df9be978a2d2f0cdebabb03206ed73b11314701a5bfe71b0d753b81997777f"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "serde"
+version = "1.0.164"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d"
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.12.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd1ba337640d60c3e96bc6f0638a939b9c9a7f2c316a1598c279828b3d1dc8c5"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
+
+[[package]]
+name = "unindent"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1766d682d402817b5ac4490b3c3002d91dfa0d22812f341609f97b08757359c"
+
+[[package]]
+name = "windows-targets"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
diff --git a/pkgs/iced-x86/default.nix b/pkgs/iced-x86/default.nix
new file mode 100644
index 0000000..ac1ad06
--- /dev/null
+++ b/pkgs/iced-x86/default.nix
@@ -0,0 +1,36 @@
+{
+ buildPythonPackage,
+ cargo,
+ lib,
+ fetchPypi,
+ setuptools-rust,
+ rustc,
+ rustPlatform,
+}: let
+ pname = "iced-x86";
+ version = "1.19.0";
+
+ src = fetchPypi {
+ inherit pname version;
+ sha256 = "sha256-YljWeJNOk7eF1iPymarxNLj3rLnXJGC/Qsajb9YWXnE=";
+ };
+in
+ buildPythonPackage {
+ inherit pname src version;
+
+ nativeBuildInputs = [
+ cargo
+ rustc
+ rustPlatform.cargoSetupHook
+ setuptools-rust
+ ];
+
+ # Esta gente no le puso Cargo.lock
+ cargoDeps = rustPlatform.importCargoLock {
+ lockFile = ./Cargo.lock;
+ };
+
+ patches = [
+ ./0001-add-Cargo.lock.patch
+ ];
+ }
diff --git a/pkgs/increment-zone-serials/default.nix b/pkgs/increment-zone-serials/default.nix
new file mode 100644
index 0000000..f2d6f02
--- /dev/null
+++ b/pkgs/increment-zone-serials/default.nix
@@ -0,0 +1,18 @@
+{
+ python3,
+ stdenv,
+}:
+stdenv.mkDerivation {
+ pname = "increment-zone-serials";
+ version = "1.0.0";
+
+ propagatedBuildInputs = [
+ (python3.withPackages (py: []))
+ ];
+
+ dontUnpack = true;
+
+ installPhase = ''
+ install -Dm755 ${./increment-zone-serials.py} $out/bin/increment-zone-serials
+ '';
+}
diff --git a/pkgs/increment-zone-serials/increment-zone-serials.py b/pkgs/increment-zone-serials/increment-zone-serials.py
new file mode 100755
index 0000000..394075a
--- /dev/null
+++ b/pkgs/increment-zone-serials/increment-zone-serials.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+
+import datetime, json, os.path, sys
+
+root_dir = sys.argv[1]
+
+serial_num = lambda n: f'{today}{n:02}'
+today_str = datetime.datetime.now(datetime.UTC).date().strftime('%Y%m%d')
+today = int(today_str)
+
+def update_serial(*, zone_class, name, expected, serial):
+ old_serial_int = serial
+ new_serial = serial_num(0)
+
+ if old_serial_int is not None:
+ old_serial = str(old_serial_int)
+ if len(old_serial) > len(new_serial):
+ new_serial = None
+ elif len(old_serial) == len(new_serial):
+ old_day = int(old_serial[:len(today_str)])
+ if old_day >= today:
+ new_serial = None
+
+ if new_serial is None:
+ new_serial = str(old_serial_int + 1)
+
+ path = os.path.join(root_dir, zone_class, name, 'serial.nix')
+ with open(path, 'w') as serial_file:
+ print(f'''\
+{{
+ config = {{
+ soa.serial = {new_serial};
+ nullSerialHash = "{expected}";
+ }};
+}}
+''', file=serial_file)
+
+ return path
+
+paths = []
+
+for zone_class, zones in json.load(sys.stdin).items():
+ for zone in zones.values():
+ paths.append(update_serial(**zone, zone_class=zone_class))
+
+# Se imprime al final para evitar estados intermedios si algo tira excepción
+for path in paths:
+ print(path)
diff --git a/pkgs/kbuild-standalone.nix b/pkgs/kbuild-standalone.nix
new file mode 100644
index 0000000..2296b50
--- /dev/null
+++ b/pkgs/kbuild-standalone.nix
@@ -0,0 +1,36 @@
+{
+ autoreconfHook,
+ bison,
+ fetchFromGitHub,
+ flex,
+ ncurses,
+ lib,
+ pkg-config,
+ stdenv,
+}:
+with lib;
+ stdenv.mkDerivation {
+ pname = "kbuild-standalone";
+ version = "6.0";
+
+ src = fetchFromGitHub {
+ repo = "kbuild-standalone";
+ owner = "WangNan0";
+
+ rev = "5e8d3496b69162684d682bda8a165cecdb66bfec";
+ sha256 = "sha256-OugvJToOiczFM6G6GkcoN8GdjOd3wLhPhh7huBGA8io=";
+ };
+
+ buildInputs = [ncurses];
+ nativeBuildInputs = [autoreconfHook bison flex pkg-config];
+
+ preBuild = ''
+ mkdir -p $out/lib/pkgconfig $out/share
+
+ patchShebangs kbuild/_fixdep
+ cp kbuild-standalone.pc $out/lib/pkgconfig/
+ export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$out/lib/pkgconfig"
+
+ cp -r kbuild/ $out/share/kbuild-standalone/
+ '';
+ }
diff --git a/pkgs/lib/default.nix b/pkgs/lib/default.nix
new file mode 100644
index 0000000..e3ab56e
--- /dev/null
+++ b/pkgs/lib/default.nix
@@ -0,0 +1,3 @@
+{callPackage}: {
+ importAll = callPackage ./importAll.nix {};
+}
diff --git a/pkgs/lib/importAll.nix b/pkgs/lib/importAll.nix
new file mode 100644
index 0000000..6acabe9
--- /dev/null
+++ b/pkgs/lib/importAll.nix
@@ -0,0 +1,20 @@
+{lib}: {
+ root,
+ exclude ? [],
+}:
+with builtins;
+with lib;
+# http://chriswarbo.net/projects/nixos/useful_hacks.html
+ let
+ basename = removeSuffix ".nix";
+
+ isMatch = name: type:
+ (hasSuffix ".nix" name || type == "directory")
+ && ! elem name (map basename exclude);
+
+ entry = name: _: {
+ name = basename name;
+ value = import (root + "/${name}");
+ };
+ in
+ mapAttrs' entry (filterAttrs isMatch (readDir root))
diff --git a/pkgs/lovelace-xiaomi-vacuum-map-card/0001-Fix-error-during-rollup-c.patch b/pkgs/lovelace-xiaomi-vacuum-map-card/0001-Fix-error-during-rollup-c.patch
new file mode 100644
index 0000000..653b8c3
--- /dev/null
+++ b/pkgs/lovelace-xiaomi-vacuum-map-card/0001-Fix-error-during-rollup-c.patch
@@ -0,0 +1,25 @@
+From c5c99802bd0735cbf9c7ab4b7ffdf2c6fc2143e4 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sat, 20 Jul 2024 14:14:57 -0600
+Subject: [PATCH] Fix error during `rollup -c`
+
+---
+ package.json | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/package.json b/package.json
+index 2c74741..0ea570d 100644
+--- a/package.json
++++ b/package.json
+@@ -43,7 +43,7 @@
+ "rollup-plugin-node-resolve": "^5.2.0",
+ "rollup-plugin-serve": "^1.1.0",
+ "rollup-plugin-terser": "^7.0.2",
+- "rollup-plugin-typescript2": "^0.30.0",
++ "rollup-plugin-typescript2": "^0.36.0",
+ "typescript": "^4.4.3"
+ },
+ "scripts": {
+--
+2.44.1
+
diff --git a/pkgs/lovelace-xiaomi-vacuum-map-card/default.nix b/pkgs/lovelace-xiaomi-vacuum-map-card/default.nix
new file mode 100644
index 0000000..4b837de
--- /dev/null
+++ b/pkgs/lovelace-xiaomi-vacuum-map-card/default.nix
@@ -0,0 +1,39 @@
+{
+ buildNpmPackage,
+ fetchFromGitHub,
+}: let
+ pname = "lovelace-xiaomi-vacuum-map-card";
+ version = "2.2.4";
+in
+ buildNpmPackage rec {
+ inherit pname version;
+
+ src = fetchFromGitHub {
+ repo = pname;
+ owner = "PiotrMachowski";
+
+ rev = "v${version}";
+ hash = "sha256-ameZzwhs1XRB31w2993MiP03hAUvf4aLM1syDmPZF60=";
+ };
+
+ npmDepsHash = "sha256-H72nYi+9zEC2daSbchfKcNECofw0eaLBTvLCsVAk9Hc=";
+
+ patches = [
+ ./0001-Fix-error-during-rollup-c.patch
+ ];
+
+ postPatch = ''
+ cp -v ${./package-lock.json} package-lock.json
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ mkdir $out
+ cp dist/xiaomi-vacuum-map-card.js $out
+
+ runHook postInstall
+ '';
+
+ passthru.entrypoint = "xiaomi-vacuum-map-card.js";
+ }
diff --git a/pkgs/lovelace-xiaomi-vacuum-map-card/package-lock.json b/pkgs/lovelace-xiaomi-vacuum-map-card/package-lock.json
new file mode 100644
index 0000000..ac54ce8
--- /dev/null
+++ b/pkgs/lovelace-xiaomi-vacuum-map-card/package-lock.json
@@ -0,0 +1,6214 @@
+{
+ "name": "xiaomi-vacuum-map-card",
+ "version": "v2.2.4",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "xiaomi-vacuum-map-card",
+ "version": "v2.2.4",
+ "license": "MIT",
+ "dependencies": {
+ "change-perspective": "^1.0.1",
+ "custom-card-helpers": "^1.9.0",
+ "home-assistant-js-websocket": "^8.0.1",
+ "lit": "^2.0.0",
+ "pointer-tracker": "^2.4.0",
+ "transformation-matrix": "^2.8.0"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.15.0",
+ "@babel/plugin-proposal-class-properties": "^7.14.5",
+ "@babel/plugin-proposal-decorators": "^7.14.5",
+ "@rollup/plugin-json": "^4.1.0",
+ "@typescript-eslint/eslint-plugin": "^4.33.0",
+ "@typescript-eslint/parser": "^4.33.0",
+ "cross-var": "^1.1.0",
+ "eslint": "^7.32.0",
+ "eslint-config-airbnb-base": "^14.2.1",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-plugin-import": "^2.24.0",
+ "eslint-plugin-prettier": "^4.0.0",
+ "prettier": "^2.4.1",
+ "replace-in-file": "^6.3.5",
+ "rollup": "^2.58.0",
+ "rollup-plugin-babel": "^4.4.0",
+ "rollup-plugin-commonjs": "^10.1.0",
+ "rollup-plugin-node-resolve": "^5.2.0",
+ "rollup-plugin-serve": "^1.1.0",
+ "rollup-plugin-terser": "^7.0.2",
+ "rollup-plugin-typescript2": "^0.36.0",
+ "typescript": "^4.4.3"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
+ "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.24.7",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz",
+ "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz",
+ "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.2.0",
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.9",
+ "@babel/helper-compilation-targets": "^7.24.8",
+ "@babel/helper-module-transforms": "^7.24.9",
+ "@babel/helpers": "^7.24.8",
+ "@babel/parser": "^7.24.8",
+ "@babel/template": "^7.24.7",
+ "@babel/traverse": "^7.24.8",
+ "@babel/types": "^7.24.9",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.24.10",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz",
+ "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.9",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jsesc": "^2.5.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
+ "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz",
+ "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/compat-data": "^7.24.8",
+ "@babel/helper-validator-option": "^7.24.8",
+ "browserslist": "^4.23.1",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.8.tgz",
+ "integrity": "sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.8",
+ "@babel/helper-optimise-call-expression": "^7.24.7",
+ "@babel/helper-replace-supers": "^7.24.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-environment-visitor": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
+ "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
+ "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
+ "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz",
+ "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.8",
+ "@babel/types": "^7.24.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
+ "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz",
+ "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-module-imports": "^7.24.7",
+ "@babel/helper-simple-access": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/helper-validator-identifier": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz",
+ "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz",
+ "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz",
+ "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.7",
+ "@babel/helper-optimise-call-expression": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
+ "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz",
+ "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
+ "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
+ "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz",
+ "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz",
+ "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.8"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
+ "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.24.7",
+ "chalk": "^2.4.2",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz",
+ "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==",
+ "dev": true,
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-class-properties": {
+ "version": "7.18.6",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz",
+ "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==",
+ "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.18.6",
+ "@babel/helper-plugin-utils": "^7.18.6"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-proposal-decorators": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.7.tgz",
+ "integrity": "sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-create-class-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
+ "@babel/plugin-syntax-decorators": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-decorators": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.7.tgz",
+ "integrity": "sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
+ "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/parser": "^7.24.7",
+ "@babel/types": "^7.24.7"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz",
+ "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.8",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-hoist-variables": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/parser": "^7.24.8",
+ "@babel/types": "^7.24.8",
+ "debug": "^4.3.1",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.24.9",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz",
+ "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.24.8",
+ "@babel/helper-validator-identifier": "^7.24.7",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
+ "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.1.1",
+ "espree": "^7.3.0",
+ "globals": "^13.9.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@formatjs/ecma402-abstract": {
+ "version": "1.11.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.4.tgz",
+ "integrity": "sha512-EBikYFp2JCdIfGEb5G9dyCkTGDmC57KSHhRQOC3aYxoPWVZvfWCDjZwkGYHN7Lis/fmuWl906bnNTJifDQ3sXw==",
+ "dependencies": {
+ "@formatjs/intl-localematcher": "0.2.25",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/fast-memoize": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz",
+ "integrity": "sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-messageformat-parser": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.1.0.tgz",
+ "integrity": "sha512-Qxv/lmCN6hKpBSss2uQ8IROVnta2r9jd3ymUEIjm2UyIkUCHVcbUVRGL/KS/wv7876edvsPe+hjHVJ4z8YuVaw==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.11.4",
+ "@formatjs/icu-skeleton-parser": "1.3.6",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/icu-skeleton-parser": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.6.tgz",
+ "integrity": "sha512-I96mOxvml/YLrwU2Txnd4klA7V8fRhb6JG/4hm3VMNmeJo1F03IpV2L3wWt7EweqNLES59SZ4d6hVOPCSf80Bg==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.11.4",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/intl-localematcher": {
+ "version": "0.2.25",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.2.25.tgz",
+ "integrity": "sha512-YmLcX70BxoSopLFdLr1Ds99NdlTI2oWoLbaUW2M406lxOIPzE1KQhRz2fPUkq34xVZQaihCoU29h0KK7An3bhA==",
+ "dependencies": {
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/@formatjs/intl-utils": {
+ "version": "3.8.4",
+ "resolved": "https://registry.npmjs.org/@formatjs/intl-utils/-/intl-utils-3.8.4.tgz",
+ "integrity": "sha512-j5C6NyfKevIxsfLK8KwO1C0vvP7k1+h4A9cFpc+cr6mEwCc1sPkr17dzh0Ke6k9U5pQccAQoXdcNBl3IYa4+ZQ==",
+ "deprecated": "the package is rather renamed to @formatjs/ecma-abstract with some changes in functionality (primarily selectUnit is removed and we don't plan to make any further changes to this package",
+ "dependencies": {
+ "emojis-list": "^3.0.0"
+ }
+ },
+ "node_modules/@humanwhocodes/config-array": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
+ "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
+ "deprecated": "Use @eslint/config-array instead",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^1.2.0",
+ "debug": "^4.1.1",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@humanwhocodes/object-schema": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+ "deprecated": "Use @eslint/object-schema instead",
+ "dev": true
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.6",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz",
+ "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@lit-labs/ssr-dom-shim": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz",
+ "integrity": "sha512-yWJKmpGE6lUURKAaIltoPIE/wrbY3TEkqQt+X0m+7fQNnAv0keydnYvbiJFP1PnMhizmIWRWOG5KLhYyc/xl+g=="
+ },
+ "node_modules/@lit/reactive-element": {
+ "version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz",
+ "integrity": "sha512-QuTgnG52Poic7uM1AN5yJ09QMe0O28e10XzSvWDz02TJiiKee4stsiownEIadWm8nYzyDAyT+gKzUoZmiWQtsQ==",
+ "dependencies": {
+ "@lit-labs/ssr-dom-shim": "^1.0.0"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@rollup/plugin-json": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-4.1.0.tgz",
+ "integrity": "sha512-yfLbTdNS6amI/2OpmbiBoW12vngr5NW2jCJVZSBEz+H5KfUJZ2M7sDjk0U6GOOdCWFVScShte29o9NezJ53TPw==",
+ "dev": true,
+ "dependencies": {
+ "@rollup/pluginutils": "^3.0.8"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0 || ^2.0.0"
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+ "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "0.0.39",
+ "estree-walker": "^1.0.1",
+ "picomatch": "^2.2.2"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "0.0.39",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+ "dev": true
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true
+ },
+ "node_modules/@types/json5": {
+ "version": "0.0.29",
+ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
+ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "20.14.11",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz",
+ "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/resolve": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz",
+ "integrity": "sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz",
+ "integrity": "sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/experimental-utils": "4.33.0",
+ "@typescript-eslint/scope-manager": "4.33.0",
+ "debug": "^4.3.1",
+ "functional-red-black-tree": "^1.0.1",
+ "ignore": "^5.1.8",
+ "regexpp": "^3.1.0",
+ "semver": "^7.3.5",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^4.0.0",
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/experimental-utils": {
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz",
+ "integrity": "sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.7",
+ "@typescript-eslint/scope-manager": "4.33.0",
+ "@typescript-eslint/types": "4.33.0",
+ "@typescript-eslint/typescript-estree": "4.33.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.33.0.tgz",
+ "integrity": "sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "4.33.0",
+ "@typescript-eslint/types": "4.33.0",
+ "@typescript-eslint/typescript-estree": "4.33.0",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz",
+ "integrity": "sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "4.33.0",
+ "@typescript-eslint/visitor-keys": "4.33.0"
+ },
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.33.0.tgz",
+ "integrity": "sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==",
+ "dev": true,
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz",
+ "integrity": "sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "4.33.0",
+ "@typescript-eslint/visitor-keys": "4.33.0",
+ "debug": "^4.3.1",
+ "globby": "^11.0.3",
+ "is-glob": "^4.0.1",
+ "semver": "^7.3.5",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz",
+ "integrity": "sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "4.33.0",
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+ "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+ "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+ "dev": true,
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
+ "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-includes": {
+ "version": "3.1.8",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
+ "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.4",
+ "is-string": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/array.prototype.findlastindex": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
+ "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flat": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
+ "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array.prototype.flatmap": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
+ "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "es-shim-unscopables": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/arraybuffer.prototype.slice": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
+ "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
+ "dev": true,
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.22.3",
+ "es-errors": "^1.2.1",
+ "get-intrinsic": "^1.2.3",
+ "is-array-buffer": "^3.0.4",
+ "is-shared-array-buffer": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dev": true,
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/babel-code-frame": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+ "integrity": "sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "esutils": "^2.0.2",
+ "js-tokens": "^3.0.2"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/js-tokens": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+ "integrity": "sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==",
+ "dev": true
+ },
+ "node_modules/babel-code-frame/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-code-frame/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/babel-core": {
+ "version": "6.26.3",
+ "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
+ "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
+ "dev": true,
+ "dependencies": {
+ "babel-code-frame": "^6.26.0",
+ "babel-generator": "^6.26.0",
+ "babel-helpers": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-register": "^6.26.0",
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "convert-source-map": "^1.5.1",
+ "debug": "^2.6.9",
+ "json5": "^0.5.1",
+ "lodash": "^4.17.4",
+ "minimatch": "^3.0.4",
+ "path-is-absolute": "^1.0.1",
+ "private": "^0.1.8",
+ "slash": "^1.0.0",
+ "source-map": "^0.5.7"
+ }
+ },
+ "node_modules/babel-core/node_modules/convert-source-map": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
+ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
+ "dev": true
+ },
+ "node_modules/babel-core/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/babel-core/node_modules/json5": {
+ "version": "0.5.1",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+ "integrity": "sha512-4xrs1aW+6N5DalkqSVA8fxh458CXvR99WU8WLKmq4v8eWAL86Xo3BVqyd3SkA9wEVjCMqyvvRRkshAdOnBp5rw==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/babel-core/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
+ },
+ "node_modules/babel-generator": {
+ "version": "6.26.1",
+ "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+ "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+ "dev": true,
+ "dependencies": {
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "detect-indent": "^4.0.0",
+ "jsesc": "^1.3.0",
+ "lodash": "^4.17.4",
+ "source-map": "^0.5.7",
+ "trim-right": "^1.0.1"
+ }
+ },
+ "node_modules/babel-generator/node_modules/jsesc": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+ "integrity": "sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ }
+ },
+ "node_modules/babel-helper-bindify-decorators": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz",
+ "integrity": "sha512-TYX2QQATKA6Wssp6j7jqlw4QLmABDN1olRdEHndYvBXdaXM5dcx6j5rN0+nd+aVL+Th40fAEYvvw/Xxd/LETuQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-builder-binary-assignment-operator-visitor": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz",
+ "integrity": "sha512-gCtfYORSG1fUMX4kKraymq607FWgMWg+j42IFPc18kFQEsmtaibP4UrqsXt8FlEJle25HUd4tsoDR7H2wDhe9Q==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-explode-assignable-expression": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-call-delegate": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
+ "integrity": "sha512-RL8n2NiEj+kKztlrVJM9JT1cXzzAdvWFh76xh/H1I4nKwunzE4INBXn8ieCZ+wh4zWszZk7NBS1s/8HR5jDkzQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-hoist-variables": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-define-map": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
+ "integrity": "sha512-bHkmjcC9lM1kmZcVpA5t2om2nzT/xiZpo6TJq7UlZ3wqKfzia4veeXbIhKvJXAMzhhEBd3cR1IElL5AenWEUpA==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-helper-explode-assignable-expression": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz",
+ "integrity": "sha512-qe5csbhbvq6ccry9G7tkXbzNtcDiH4r51rrPUbwwoTzZ18AqxWYRZT6AOmxrpxKnQBW0pYlBI/8vh73Z//78nQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-explode-class": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz",
+ "integrity": "sha512-SFbWewr0/0U4AiRzsHqwsbOQeLXVa9T1ELdqEa2efcQB5KopTnunAqoj07TuHlN2lfTQNPGO/rJR4FMln5fVcA==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-bindify-decorators": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-function-name": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
+ "integrity": "sha512-Oo6+e2iX+o9eVvJ9Y5eKL5iryeRdsIkwRYheCuhYdVHsdEQysbc2z2QkqCLIYnNxkT5Ss3ggrHdXiDI7Dhrn4Q==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-get-function-arity": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-get-function-arity": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
+ "integrity": "sha512-WfgKFX6swFB1jS2vo+DwivRN4NB8XUdM3ij0Y1gnC21y1tdBoe6xjVnd7NSI6alv+gZXCtJqvrTeMW3fR/c0ng==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-hoist-variables": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
+ "integrity": "sha512-zAYl3tqerLItvG5cKYw7f1SpvIxS9zi7ohyGHaI9cgDUjAT6YcY9jIEH5CstetP5wHIVSceXwNS7Z5BpJg+rOw==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-optimise-call-expression": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
+ "integrity": "sha512-Op9IhEaxhbRT8MDXx2iNuMgciu2V8lDvYCNQbDGjdBNCjaMvyLf4wl4A3b8IgndCyQF8TwfgsQ8T3VD8aX1/pA==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-regex": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
+ "integrity": "sha512-VlPiWmqmGJp0x0oK27Out1D+71nVVCTSdlbhIVoaBAj2lUgrNjBCRR9+llO4lTSb2O4r7PJg+RobRkhBrf6ofg==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-helper-remap-async-to-generator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz",
+ "integrity": "sha512-RYqaPD0mQyQIFRu7Ho5wE2yvA/5jxqCIj/Lv4BXNq23mHYu/vxikOy2JueLiBxQknwapwrJeNCesvY0ZcfnlHg==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helper-replace-supers": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
+ "integrity": "sha512-sLI+u7sXJh6+ToqDr57Bv973kCepItDhMou0xCP2YPVmR1jkHSCY+p1no8xErbV1Siz5QE8qKT1WIwybSWlqjw==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-optimise-call-expression": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-helpers": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+ "integrity": "sha512-n7pFrqQm44TCYvrCDb0MqabAF+JUBq+ijBvNMUxpkLjJaAu32faIexewMumrH5KLLJ1HDyT0PTEqRyAe/GwwuQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-messages": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+ "integrity": "sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-check-es2015-constants": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+ "integrity": "sha512-B1M5KBP29248dViEo1owyY32lk1ZSH2DaNNrXLGt8lyjjHm7pBqAdQ7VKUPR6EEDO323+OvT3MQXbCin8ooWdA==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-syntax-async-functions": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz",
+ "integrity": "sha512-4Zp4unmHgw30A1eWI5EpACji2qMocisdXhAftfhXoSV9j0Tvj6nRFE3tOmRY912E0FMRm/L5xWE7MGVT2FoLnw==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-async-generators": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz",
+ "integrity": "sha512-EbciFN5Jb9iqU9bqaLmmFLx2G8pAUsvpWJ6OzOWBNrSY9qTohXj+7YfZx6Ug1Qqh7tCb1EA7Jvn9bMC1HBiucg==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-class-constructor-call": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-constructor-call/-/babel-plugin-syntax-class-constructor-call-6.18.0.tgz",
+ "integrity": "sha512-EEuBcXz/wZ81Jaac0LnMHtD4Mfz9XWn2oH2Xj+CHwz2SZWUqqdtR2BgWPSdTGMmxN/5KLSh4PImt9+9ZedDarA==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-class-properties": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz",
+ "integrity": "sha512-chI3Rt9T1AbrQD1s+vxw3KcwC9yHtF621/MacuItITfZX344uhQoANjpoSJZleAmW2tjlolqB/f+h7jIqXa7pA==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-decorators": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz",
+ "integrity": "sha512-AWj19x2aDm8qFQ5O2JcD6pwJDW1YdcnO+1b81t7gxrGjz5VHiUqeYWAR4h7zueWMalRelrQDXprv2FrY1dbpbw==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-do-expressions": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-do-expressions/-/babel-plugin-syntax-do-expressions-6.13.0.tgz",
+ "integrity": "sha512-HD/5qJB9oSXzl0caxM+aRD7ENICXqcc3Up/8toDQk7zNIDE7TzsqtxC5f4t9Rwhu2Ya8l9l4j6b3vOsy+a6qxg==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-dynamic-import": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz",
+ "integrity": "sha512-MioUE+LfjCEz65Wf7Z/Rm4XCP5k2c+TbMd2Z2JKc7U9uwjBhAfNPE48KC4GTGKhppMeYVepwDBNO/nGY6NYHBA==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-exponentiation-operator": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz",
+ "integrity": "sha512-Z/flU+T9ta0aIEKl1tGEmN/pZiI1uXmCiGFRegKacQfEJzp7iNsKloZmyJlQr+75FCJtiFfGIK03SiCvCt9cPQ==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-export-extensions": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-export-extensions/-/babel-plugin-syntax-export-extensions-6.13.0.tgz",
+ "integrity": "sha512-Eo0rcRaIDMld/W6mVhePiudIuLW+Cr/8eveW3mBREfZORScZgx4rh6BAPyvzdEc/JZvQ+LkC80t0VGFs6FX+lg==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-function-bind": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-function-bind/-/babel-plugin-syntax-function-bind-6.13.0.tgz",
+ "integrity": "sha512-m8yMoh9LIiNyeLdQs5I9G+3YXo4nqVsKQkk7YplrG4qAFbNi9hkZlow8HDHxhH9QOVFPHmy8+03NzRCdyChIKw==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-object-rest-spread": {
+ "version": "6.13.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz",
+ "integrity": "sha512-C4Aq+GaAj83pRQ0EFgTvw5YO6T3Qz2KGrNRwIj9mSoNHVvdZY4KO2uA6HNtNXCw993iSZnckY1aLW8nOi8i4+w==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-syntax-trailing-function-commas": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz",
+ "integrity": "sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ==",
+ "dev": true
+ },
+ "node_modules/babel-plugin-transform-async-generator-functions": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz",
+ "integrity": "sha512-uT7eovUxtXe8Q2ufcjRuJIOL0hg6VAUJhiWJBLxH/evYAw+aqoJLcYTR8hqx13iOx/FfbCMHgBmXWZjukbkyPg==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-remap-async-to-generator": "^6.24.1",
+ "babel-plugin-syntax-async-generators": "^6.5.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-async-to-generator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz",
+ "integrity": "sha512-7BgYJujNCg0Ti3x0c/DL3tStvnKS6ktIYOmo9wginv/dfZOrbSZ+qG4IRRHMBOzZ5Awb1skTiAsQXg/+IWkZYw==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-remap-async-to-generator": "^6.24.1",
+ "babel-plugin-syntax-async-functions": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-class-constructor-call": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-constructor-call/-/babel-plugin-transform-class-constructor-call-6.24.1.tgz",
+ "integrity": "sha512-RvYukT1Nh7njz8P8326ztpQUGCKwmjgu6aRIx1lkvylWITYcskg29vy1Kp8WXIq7FvhXsz0Crf2kS94bjB690A==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-class-constructor-call": "^6.18.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-class-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz",
+ "integrity": "sha512-n4jtBA3OYBdvG5PRMKsMXJXHfLYw/ZOmtxCLOOwz6Ro5XlrColkStLnz1AS1L2yfPA9BKJ1ZNlmVCLjAL9DSIg==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-plugin-syntax-class-properties": "^6.8.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-decorators": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz",
+ "integrity": "sha512-skQ2CImwDkCHu0mkWvCOlBCpBIHW4/49IZWVwV4A/EnWjL9bB6UBvLyMNe3Td5XDStSZNhe69j4bfEW8dvUbew==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-explode-class": "^6.24.1",
+ "babel-plugin-syntax-decorators": "^6.13.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-do-expressions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-do-expressions/-/babel-plugin-transform-do-expressions-6.22.0.tgz",
+ "integrity": "sha512-yQwYqYg+Tnj1InA8W1rsItsZVhkv1Euc4KVua9ledtPz5PDWYz7LVyy6rDBpVYUWFZj5k6GUm3YZpCbIm8Tqew==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-do-expressions": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-arrow-functions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+ "integrity": "sha512-PCqwwzODXW7JMrzu+yZIaYbPQSKjDTAsNNlK2l5Gg9g4rz2VzLnZsStvp/3c46GfXpwkyufb3NCyG9+50FF1Vg==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-block-scoped-functions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+ "integrity": "sha512-2+ujAT2UMBzYFm7tidUsYh+ZoIutxJ3pN9IYrF1/H6dCKtECfhmB8UkHVpyxDwkj0CYbQG35ykoz925TUnBc3A==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-block-scoping": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
+ "integrity": "sha512-YiN6sFAQ5lML8JjCmr7uerS5Yc/EMbgg9G8ZNmk2E3nYX4ckHR01wrkeeMijEf5WHNK5TW0Sl0Uu3pv3EdOJWw==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-classes": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
+ "integrity": "sha512-5Dy7ZbRinGrNtmWpquZKZ3EGY8sDgIVB4CU8Om8q8tnMLrD/m94cKglVcHps0BCTdZ0TJeeAWOq2TK9MIY6cag==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-define-map": "^6.24.1",
+ "babel-helper-function-name": "^6.24.1",
+ "babel-helper-optimise-call-expression": "^6.24.1",
+ "babel-helper-replace-supers": "^6.24.1",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-computed-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
+ "integrity": "sha512-C/uAv4ktFP/Hmh01gMTvYvICrKze0XVX9f2PdIXuriCSvUmV9j+u+BB9f5fJK3+878yMK6dkdcq+Ymr9mrcLzw==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-destructuring": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+ "integrity": "sha512-aNv/GDAW0j/f4Uy1OEPZn1mqD+Nfy9viFGBfQ5bZyT35YqOiqx7/tXdyfZkJ1sC21NyEsBdfDY6PYmLHF4r5iA==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-duplicate-keys": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
+ "integrity": "sha512-ossocTuPOssfxO2h+Z3/Ea1Vo1wWx31Uqy9vIiJusOP4TbF7tPs9U0sJ9pX9OJPf4lXRGj5+6Gkl/HHKiAP5ug==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-for-of": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+ "integrity": "sha512-DLuRwoygCoXx+YfxHLkVx5/NpeSbVwfoTeBykpJK7JhYWlL/O8hgAK/reforUnZDlxasOrVPPJVI/guE3dCwkw==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-function-name": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
+ "integrity": "sha512-iFp5KIcorf11iBqu/y/a7DK3MN5di3pNCzto61FqCNnUX4qeBwcV1SLqe10oXNnCaxBUImX3SckX2/o1nsrTcg==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-function-name": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-literals": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+ "integrity": "sha512-tjFl0cwMPpDYyoqYA9li1/7mGFit39XiNX5DKC/uCNjBctMxyL1/PT/l4rSlbvBG1pOKI88STRdUsWXB3/Q9hQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-amd": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
+ "integrity": "sha512-LnIIdGWIKdw7zwckqx+eGjcS8/cl8D74A3BpJbGjKTFFNJSMrjN4bIh22HY1AlkUbeLG6X6OZj56BDvWD+OeFA==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-commonjs": {
+ "version": "6.26.2",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
+ "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-strict-mode": "^6.24.1",
+ "babel-runtime": "^6.26.0",
+ "babel-template": "^6.26.0",
+ "babel-types": "^6.26.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-systemjs": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
+ "integrity": "sha512-ONFIPsq8y4bls5PPsAWYXH/21Hqv64TBxdje0FvU3MhIV6QM2j5YS7KvAzg/nTIVLot2D2fmFQrFWCbgHlFEjg==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-hoist-variables": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-modules-umd": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
+ "integrity": "sha512-LpVbiT9CLsuAIp3IG0tfbVo81QIhn6pE8xBJ7XSeCtFlMltuar5VuBV6y6Q45tpui9QWcy5i0vLQfCfrnF7Kiw==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-object-super": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
+ "integrity": "sha512-8G5hpZMecb53vpD3mjs64NhI1au24TAmokQ4B+TBFBjN9cVoGoOvotdrMMRmHvVZUEvqGUPWL514woru1ChZMA==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-replace-supers": "^6.24.1",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-parameters": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
+ "integrity": "sha512-8HxlW+BB5HqniD+nLkQ4xSAVq3bR/pcYW9IigY+2y0dI+Y7INFeTbfAQr+63T3E4UDsZGjyb+l9txUnABWxlOQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-call-delegate": "^6.24.1",
+ "babel-helper-get-function-arity": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-template": "^6.24.1",
+ "babel-traverse": "^6.24.1",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-shorthand-properties": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
+ "integrity": "sha512-mDdocSfUVm1/7Jw/FIRNw9vPrBQNePy6wZJlR8HAUBLybNp1w/6lr6zZ2pjMShee65t/ybR5pT8ulkLzD1xwiw==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-spread": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+ "integrity": "sha512-3Ghhi26r4l3d0Js933E5+IhHwk0A1yiutj9gwvzmFbVV0sPMYk2lekhOufHBswX7NCoSeF4Xrl3sCIuSIa+zOg==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-sticky-regex": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
+ "integrity": "sha512-CYP359ADryTo3pCsH0oxRo/0yn6UsEZLqYohHmvLQdfS9xkf+MbCzE3/Kolw9OYIY4ZMilH25z/5CbQbwDD+lQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-regex": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-template-literals": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+ "integrity": "sha512-x8b9W0ngnKzDMHimVtTfn5ryimars1ByTqsfBDwAqLibmuuQY6pgBQi5z1ErIsUOWBdw1bW9FSz5RZUojM4apg==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-typeof-symbol": {
+ "version": "6.23.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+ "integrity": "sha512-fz6J2Sf4gYN6gWgRZaoFXmq93X+Li/8vf+fb0sGDVtdeWvxC9y5/bTD7bvfWMEq6zetGEHpWjtzRGSugt5kNqw==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-es2015-unicode-regex": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
+ "integrity": "sha512-v61Dbbihf5XxnYjtBN04B/JBvsScY37R1cZT5r9permN1cp+b70DY3Ib3fIkgn1DI9U3tGgBJZVD8p/mE/4JbQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-regex": "^6.24.1",
+ "babel-runtime": "^6.22.0",
+ "regexpu-core": "^2.0.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-exponentiation-operator": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz",
+ "integrity": "sha512-LzXDmbMkklvNhprr20//RStKVcT8Cu+SQtX18eMHLhjHf2yFzwtQ0S2f0jQ+89rokoNdmwoSqYzAhq86FxlLSQ==",
+ "dev": true,
+ "dependencies": {
+ "babel-helper-builder-binary-assignment-operator-visitor": "^6.24.1",
+ "babel-plugin-syntax-exponentiation-operator": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-export-extensions": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-export-extensions/-/babel-plugin-transform-export-extensions-6.22.0.tgz",
+ "integrity": "sha512-mtzELzINaYqdVglyZrDDVwkcFRuE7s6QUFWXxwffKAHB/NkfbJ2NJSytugB43ytIC8UVt30Ereyx+7gNyTkDLg==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-export-extensions": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-function-bind": {
+ "version": "6.22.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-function-bind/-/babel-plugin-transform-function-bind-6.22.0.tgz",
+ "integrity": "sha512-9Ec4KYf1GurT39mlUjDSlN7HWSlB3u3mWRMogQbb+Y88lO0ZM3rJ0ADhPnQwWK9TbO6e/4E+Et1rrfGY9mFimA==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-function-bind": "^6.8.0",
+ "babel-runtime": "^6.22.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-object-rest-spread": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.26.0.tgz",
+ "integrity": "sha512-ocgA9VJvyxwt+qJB0ncxV8kb/CjfTcECUY4tQ5VT7nP6Aohzobm8CDFaQ5FHdvZQzLmf0sgDxB8iRXZXxwZcyA==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-object-rest-spread": "^6.8.0",
+ "babel-runtime": "^6.26.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-regenerator": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
+ "integrity": "sha512-LS+dBkUGlNR15/5WHKe/8Neawx663qttS6AGqoOUhICc9d1KciBvtrQSuc0PI+CxQ2Q/S1aKuJ+u64GtLdcEZg==",
+ "dev": true,
+ "dependencies": {
+ "regenerator-transform": "^0.10.0"
+ }
+ },
+ "node_modules/babel-plugin-transform-strict-mode": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
+ "integrity": "sha512-j3KtSpjyLSJxNoCDrhwiJad8kw0gJ9REGj8/CqL0HeRyLnvUNYV9zcqluL6QJSXh3nfsLEmSLvwRfGzrgR96Pw==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.22.0",
+ "babel-types": "^6.24.1"
+ }
+ },
+ "node_modules/babel-preset-es2015": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
+ "integrity": "sha512-XfwUqG1Ry6R43m4Wfob+vHbIVBIqTg/TJY4Snku1iIzeH7mUnwHA8Vagmv+ZQbPwhS8HgsdQvy28Py3k5zpoFQ==",
+ "deprecated": "🙌 Thanks for using Babel: we recommend using babel-preset-env now: please read https://babeljs.io/env to update!",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-check-es2015-constants": "^6.22.0",
+ "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
+ "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
+ "babel-plugin-transform-es2015-block-scoping": "^6.24.1",
+ "babel-plugin-transform-es2015-classes": "^6.24.1",
+ "babel-plugin-transform-es2015-computed-properties": "^6.24.1",
+ "babel-plugin-transform-es2015-destructuring": "^6.22.0",
+ "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1",
+ "babel-plugin-transform-es2015-for-of": "^6.22.0",
+ "babel-plugin-transform-es2015-function-name": "^6.24.1",
+ "babel-plugin-transform-es2015-literals": "^6.22.0",
+ "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
+ "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
+ "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1",
+ "babel-plugin-transform-es2015-modules-umd": "^6.24.1",
+ "babel-plugin-transform-es2015-object-super": "^6.24.1",
+ "babel-plugin-transform-es2015-parameters": "^6.24.1",
+ "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
+ "babel-plugin-transform-es2015-spread": "^6.22.0",
+ "babel-plugin-transform-es2015-sticky-regex": "^6.24.1",
+ "babel-plugin-transform-es2015-template-literals": "^6.22.0",
+ "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0",
+ "babel-plugin-transform-es2015-unicode-regex": "^6.24.1",
+ "babel-plugin-transform-regenerator": "^6.24.1"
+ }
+ },
+ "node_modules/babel-preset-stage-0": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-stage-0/-/babel-preset-stage-0-6.24.1.tgz",
+ "integrity": "sha512-MJD+xBbpsApbKlzAX0sOBF+VeFaUmv5s8FSOO7SSZpes1QgphCjq/UIGRFWSmQ/0i5bqQjLGCTXGGXqcLQ9JDA==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-do-expressions": "^6.22.0",
+ "babel-plugin-transform-function-bind": "^6.22.0",
+ "babel-preset-stage-1": "^6.24.1"
+ }
+ },
+ "node_modules/babel-preset-stage-1": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-stage-1/-/babel-preset-stage-1-6.24.1.tgz",
+ "integrity": "sha512-rn+UOcd7BHDniq1SVxv2/AVVSVI1NK+hfS0I/iR6m6KbOi/aeBRcqBilqO73pd9VUpRXF2HFtlDuC9F2BEQqmg==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-transform-class-constructor-call": "^6.24.1",
+ "babel-plugin-transform-export-extensions": "^6.22.0",
+ "babel-preset-stage-2": "^6.24.1"
+ }
+ },
+ "node_modules/babel-preset-stage-2": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz",
+ "integrity": "sha512-9F+nquz+37PrlTSBdpeQBKnQfAMNBnryXw+m4qBh35FNbJPfzZz+sjN2G5Uf1CRedU9PH7fJkTbYijxmkLX8Og==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-dynamic-import": "^6.18.0",
+ "babel-plugin-transform-class-properties": "^6.24.1",
+ "babel-plugin-transform-decorators": "^6.24.1",
+ "babel-preset-stage-3": "^6.24.1"
+ }
+ },
+ "node_modules/babel-preset-stage-3": {
+ "version": "6.24.1",
+ "resolved": "https://registry.npmjs.org/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz",
+ "integrity": "sha512-eCbEOF8uN0KypFXJmZXn2sTk7bPV9uM5xov7G/7BM08TbQEObsVs0cEWfy6NQySlfk7JBi/t+XJP1JkruYfthA==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-syntax-trailing-function-commas": "^6.22.0",
+ "babel-plugin-transform-async-generator-functions": "^6.24.1",
+ "babel-plugin-transform-async-to-generator": "^6.24.1",
+ "babel-plugin-transform-exponentiation-operator": "^6.24.1",
+ "babel-plugin-transform-object-rest-spread": "^6.22.0"
+ }
+ },
+ "node_modules/babel-register": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+ "integrity": "sha512-veliHlHX06wjaeY8xNITbveXSiI+ASFnOqvne/LaIJIqOWi2Ogmj91KOugEz/hoh/fwMhXNBJPCv8Xaz5CyM4A==",
+ "dev": true,
+ "dependencies": {
+ "babel-core": "^6.26.0",
+ "babel-runtime": "^6.26.0",
+ "core-js": "^2.5.0",
+ "home-or-tmp": "^2.0.0",
+ "lodash": "^4.17.4",
+ "mkdirp": "^0.5.1",
+ "source-map-support": "^0.4.15"
+ }
+ },
+ "node_modules/babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g==",
+ "dev": true,
+ "dependencies": {
+ "core-js": "^2.4.0",
+ "regenerator-runtime": "^0.11.0"
+ }
+ },
+ "node_modules/babel-template": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+ "integrity": "sha512-PCOcLFW7/eazGUKIoqH97sO9A2UYMahsn/yRQ7uOk37iutwjq7ODtcTNF+iFDSHNfkctqsLRjLP7URnOx0T1fg==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "babel-traverse": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-traverse": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+ "integrity": "sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA==",
+ "dev": true,
+ "dependencies": {
+ "babel-code-frame": "^6.26.0",
+ "babel-messages": "^6.23.0",
+ "babel-runtime": "^6.26.0",
+ "babel-types": "^6.26.0",
+ "babylon": "^6.18.0",
+ "debug": "^2.6.8",
+ "globals": "^9.18.0",
+ "invariant": "^2.2.2",
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/babel-traverse/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/babel-traverse/node_modules/globals": {
+ "version": "9.18.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+ "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babel-traverse/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
+ },
+ "node_modules/babel-types": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+ "integrity": "sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.26.0",
+ "esutils": "^2.0.2",
+ "lodash": "^4.17.4",
+ "to-fast-properties": "^1.0.3"
+ }
+ },
+ "node_modules/babel-types/node_modules/to-fast-properties": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+ "integrity": "sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/babylon": {
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+ "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+ "dev": true,
+ "bin": {
+ "babylon": "bin/babylon.js"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.23.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz",
+ "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001640",
+ "electron-to-chromium": "^1.4.820",
+ "node-releases": "^2.0.14",
+ "update-browserslist-db": "^1.1.0"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "dev": true
+ },
+ "node_modules/builtin-modules": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+ "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001642",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz",
+ "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ]
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/change-perspective": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/change-perspective/-/change-perspective-1.0.1.tgz",
+ "integrity": "sha512-x2w4Zv6lCAv85RXVSVFsL5MpOe1SveXyVmIcoT6RN+Kij22V9U8oNzzd4hxAmoZpvyK+/mUS0/2upGxu/FV09g=="
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "dev": true
+ },
+ "node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "dev": true
+ },
+ "node_modules/commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+ "dev": true
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/confusing-browser-globals": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
+ "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
+ "dev": true
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true
+ },
+ "node_modules/core-js": {
+ "version": "2.6.12",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
+ "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
+ "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
+ "dev": true,
+ "hasInstallScript": true
+ },
+ "node_modules/cross-spawn": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+ "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ }
+ },
+ "node_modules/cross-spawn/node_modules/lru-cache": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
+ "dev": true,
+ "dependencies": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "node_modules/cross-spawn/node_modules/yallist": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+ "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==",
+ "dev": true
+ },
+ "node_modules/cross-var": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/cross-var/-/cross-var-1.1.0.tgz",
+ "integrity": "sha512-wIcFax9RNm5ayuORUeJ5MLxPbfh8XdZhhUpKutIszU46Fs9UIhEdPJ7+YguM+7FxEj+68hSQVyathVsIu84SiA==",
+ "dev": true,
+ "dependencies": {
+ "babel-preset-es2015": "^6.18.0",
+ "babel-preset-stage-0": "^6.16.0",
+ "babel-register": "^6.18.0",
+ "cross-spawn": "^5.0.1",
+ "exit": "^0.1.2"
+ },
+ "bin": {
+ "cross-var": "index.js"
+ }
+ },
+ "node_modules/custom-card-helpers": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/custom-card-helpers/-/custom-card-helpers-1.9.0.tgz",
+ "integrity": "sha512-5IW4OXq3MiiCqDvqeu+MYsM1NmntKW1WfJhyJFsdP2tbzqEI4BOnqRz2qzdp08lE4QLVhYfRLwe0WAqgQVNeFg==",
+ "dependencies": {
+ "@formatjs/intl-utils": "^3.8.4",
+ "home-assistant-js-websocket": "^6.0.1",
+ "intl-messageformat": "^9.11.1",
+ "lit": "^2.1.1",
+ "rollup": "^2.63.0",
+ "superstruct": "^0.15.3",
+ "typescript": "^4.5.4"
+ }
+ },
+ "node_modules/custom-card-helpers/node_modules/home-assistant-js-websocket": {
+ "version": "6.1.1",
+ "resolved": "https://registry.npmjs.org/home-assistant-js-websocket/-/home-assistant-js-websocket-6.1.1.tgz",
+ "integrity": "sha512-TnZFzF4mn5F/v0XKUTK2GMQXrn/+eQpgaSDSELl6U0HSwSbFwRhGWLz330YT+hiKMspDflamsye//RPL+zwhDw=="
+ },
+ "node_modules/data-view-buffer": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
+ "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
+ "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/data-view-byte-offset": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
+ "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-data-view": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+ "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+ "dev": true,
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+ "dev": true
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/detect-indent": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+ "integrity": "sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A==",
+ "dev": true,
+ "dependencies": {
+ "repeating": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+ "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.4.832",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.832.tgz",
+ "integrity": "sha512-cTen3SB0H2SGU7x467NRe1eVcQgcuS6jckKfWJHia2eo0cHIGOqHoAxevIYZD4eRHcWjkvFzo93bi3vJ9W+1lA==",
+ "dev": true
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/emojis-list": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/enquirer": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz",
+ "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^4.1.1",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.23.3",
+ "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
+ "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
+ "dev": true,
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.1",
+ "arraybuffer.prototype.slice": "^1.0.3",
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "data-view-buffer": "^1.0.1",
+ "data-view-byte-length": "^1.0.1",
+ "data-view-byte-offset": "^1.0.0",
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.0.0",
+ "es-set-tostringtag": "^2.0.3",
+ "es-to-primitive": "^1.2.1",
+ "function.prototype.name": "^1.1.6",
+ "get-intrinsic": "^1.2.4",
+ "get-symbol-description": "^1.0.2",
+ "globalthis": "^1.0.3",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2",
+ "has-proto": "^1.0.3",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.2",
+ "internal-slot": "^1.0.7",
+ "is-array-buffer": "^3.0.4",
+ "is-callable": "^1.2.7",
+ "is-data-view": "^1.0.1",
+ "is-negative-zero": "^2.0.3",
+ "is-regex": "^1.1.4",
+ "is-shared-array-buffer": "^1.0.3",
+ "is-string": "^1.0.7",
+ "is-typed-array": "^1.1.13",
+ "is-weakref": "^1.0.2",
+ "object-inspect": "^1.13.1",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.5",
+ "regexp.prototype.flags": "^1.5.2",
+ "safe-array-concat": "^1.1.2",
+ "safe-regex-test": "^1.0.3",
+ "string.prototype.trim": "^1.2.9",
+ "string.prototype.trimend": "^1.0.8",
+ "string.prototype.trimstart": "^1.0.8",
+ "typed-array-buffer": "^1.0.2",
+ "typed-array-byte-length": "^1.0.1",
+ "typed-array-byte-offset": "^1.0.2",
+ "typed-array-length": "^1.0.6",
+ "unbox-primitive": "^1.0.2",
+ "which-typed-array": "^1.1.15"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
+ "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
+ "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.2.4",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-shim-unscopables": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
+ "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+ "dev": true,
+ "dependencies": {
+ "hasown": "^2.0.0"
+ }
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
+ "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+ "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "7.32.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
+ "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "7.12.11",
+ "@eslint/eslintrc": "^0.4.3",
+ "@humanwhocodes/config-array": "^0.5.0",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^2.0.0",
+ "espree": "^7.3.1",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.1.2",
+ "globals": "^13.6.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^6.0.9",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-airbnb-base": {
+ "version": "14.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz",
+ "integrity": "sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA==",
+ "dev": true,
+ "dependencies": {
+ "confusing-browser-globals": "^1.0.10",
+ "object.assign": "^4.1.2",
+ "object.entries": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "eslint": "^5.16.0 || ^6.8.0 || ^7.2.0",
+ "eslint-plugin-import": "^2.22.1"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "8.10.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz",
+ "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-import-resolver-node": {
+ "version": "0.3.9",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
+ "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^3.2.7",
+ "is-core-module": "^2.13.0",
+ "resolve": "^1.22.4"
+ }
+ },
+ "node_modules/eslint-import-resolver-node/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-module-utils": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
+ "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^3.2.7"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "eslint": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-module-utils/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import": {
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
+ "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.7",
+ "array.prototype.findlastindex": "^1.2.3",
+ "array.prototype.flat": "^1.3.2",
+ "array.prototype.flatmap": "^1.3.2",
+ "debug": "^3.2.7",
+ "doctrine": "^2.1.0",
+ "eslint-import-resolver-node": "^0.3.9",
+ "eslint-module-utils": "^2.8.0",
+ "hasown": "^2.0.0",
+ "is-core-module": "^2.13.1",
+ "is-glob": "^4.0.3",
+ "minimatch": "^3.1.2",
+ "object.fromentries": "^2.0.7",
+ "object.groupby": "^1.0.1",
+ "object.values": "^1.1.7",
+ "semver": "^6.3.1",
+ "tsconfig-paths": "^3.15.0"
+ },
+ "engines": {
+ "node": ">=4"
+ },
+ "peerDependencies": {
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/debug": {
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+ "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.1.1"
+ }
+ },
+ "node_modules/eslint-plugin-import/node_modules/doctrine": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
+ "dev": true,
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/eslint-plugin-prettier": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz",
+ "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==",
+ "dev": true,
+ "dependencies": {
+ "prettier-linter-helpers": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.28.0",
+ "prettier": ">=2.0.0"
+ },
+ "peerDependenciesMeta": {
+ "eslint-config-prettier": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+ "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=5"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+ "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint/node_modules/@babel/code-frame": {
+ "version": "7.12.11",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
+ "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/eslint/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/eslint/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/eslint/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/eslint/node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+ "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+ "dev": true,
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/eslint/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-utils": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
+ "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
+ "dev": true,
+ "dependencies": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint/node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/ignore": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
+ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/eslint/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint/node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/espree": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
+ "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.3.1",
+ "eslint-visitor-keys": "^1.3.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/espree/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
+ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true,
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+ "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "dev": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
+ "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+ "dev": true
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/exit": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+ "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "dev": true
+ },
+ "node_modules/fast-diff": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
+ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
+ "dev": true
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+ "dev": true
+ },
+ "node_modules/fast-uri": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz",
+ "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==",
+ "dev": true
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/find-cache-dir": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+ "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+ "dev": true,
+ "dependencies": {
+ "commondir": "^1.0.1",
+ "make-dir": "^3.0.2",
+ "pkg-dir": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz",
+ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
+ "dev": true
+ },
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dev": true,
+ "dependencies": {
+ "is-callable": "^1.1.3"
+ }
+ },
+ "node_modules/fs-extra": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/function.prototype.name": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
+ "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.2.0",
+ "es-abstract": "^1.22.1",
+ "functions-have-names": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functional-red-black-tree": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+ "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+ "dev": true
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-symbol-description": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
+ "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/globals": {
+ "version": "11.12.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+ "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/globalthis": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+ "dev": true,
+ "dependencies": {
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby/node_modules/slash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dev": true,
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-ansi/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-bigints": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+ "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dev": true,
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/home-assistant-js-websocket": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/home-assistant-js-websocket/-/home-assistant-js-websocket-8.2.0.tgz",
+ "integrity": "sha512-B163iuvC1hsObkbSXm89JfjjOguyQXSQeQsGf6KQblUj9QwMgFkQt13TiCYjeFFTMzhQ8Qj3/gKx/6MnSeYUqA=="
+ },
+ "node_modules/home-or-tmp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+ "integrity": "sha512-ycURW7oUxE2sNiPVw1HVEFsW+ecOpJ5zaj7eC0RlwhibhRBod20muUN8qu/gzx956YrLolVvs1MTXwKgC2rVEg==",
+ "dev": true,
+ "dependencies": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
+ "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+ "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+ "dev": true,
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/internal-slot": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
+ "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
+ "dev": true,
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.0",
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/intl-messageformat": {
+ "version": "9.13.0",
+ "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.13.0.tgz",
+ "integrity": "sha512-7sGC7QnSQGa5LZP7bXLDhVDtQOeKGeBFGHF2Y8LVBwYZoQZCgWeKoPGTa5GMG8g/TzDgeXuYJQis7Ggiw2xTOw==",
+ "dependencies": {
+ "@formatjs/ecma402-abstract": "1.11.4",
+ "@formatjs/fast-memoize": "1.2.1",
+ "@formatjs/icu-messageformat-parser": "2.1.0",
+ "tslib": "^2.1.0"
+ }
+ },
+ "node_modules/invariant": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
+ "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
+ "dev": true,
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
+ "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+ "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "dev": true,
+ "dependencies": {
+ "has-bigints": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+ "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.15.0",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz",
+ "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==",
+ "dev": true,
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-data-view": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
+ "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
+ "dev": true,
+ "dependencies": {
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+ "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-finite": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz",
+ "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
+ "dev": true
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
+ "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+ "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-reference": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+ "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+ "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+ "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "dev": true,
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+ "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "dev": true,
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
+ "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+ "dev": true,
+ "dependencies": {
+ "which-typed-array": "^1.1.14"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakref": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
+ "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/jest-worker": {
+ "version": "26.6.2",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
+ "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/jest-worker/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jest-worker/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true
+ },
+ "node_modules/js-yaml": {
+ "version": "3.14.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+ "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+ "dev": true,
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/jsesc": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/json-buffer": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+ "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+ "dev": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+ "dev": true
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "dev": true,
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+ "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+ "dev": true,
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lit": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/lit/-/lit-2.8.0.tgz",
+ "integrity": "sha512-4Sc3OFX9QHOJaHbmTMk28SYgVxLN3ePDjg7hofEft2zWlehFL3LiAuapWc4U/kYwMYJSh2hTCPZ6/LIC7ii0MA==",
+ "dependencies": {
+ "@lit/reactive-element": "^1.6.0",
+ "lit-element": "^3.3.0",
+ "lit-html": "^2.8.0"
+ }
+ },
+ "node_modules/lit-element": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-3.3.3.tgz",
+ "integrity": "sha512-XbeRxmTHubXENkV4h8RIPyr8lXc+Ff28rkcQzw3G6up2xg5E8Zu1IgOWIwBLEQsu3cOVFqdYwiVi0hv0SlpqUA==",
+ "dependencies": {
+ "@lit-labs/ssr-dom-shim": "^1.1.0",
+ "@lit/reactive-element": "^1.3.0",
+ "lit-html": "^2.8.0"
+ }
+ },
+ "node_modules/lit-html": {
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-2.8.0.tgz",
+ "integrity": "sha512-o9t+MQM3P4y7M7yNzqAyjp7z+mQGa4NS4CxiyLqFPyFWyc4O+nodLrkrxSaCTrla6M5YOLaT3RpbbqjszB5g3Q==",
+ "dependencies": {
+ "@types/trusted-types": "^2.0.2"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+ "dev": true
+ },
+ "node_modules/lodash.truncate": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+ "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
+ "dev": true
+ },
+ "node_modules/loose-envify": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
+ "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "dependencies": {
+ "js-tokens": "^3.0.0 || ^4.0.0"
+ },
+ "bin": {
+ "loose-envify": "cli.js"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.25.9",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
+ "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
+ "dev": true,
+ "dependencies": {
+ "sourcemap-codec": "^1.4.8"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "dev": true
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
+ "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
+ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==",
+ "dev": true,
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "0.5.6",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
+ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.6"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+ "dev": true
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+ "dev": true
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.17.tgz",
+ "integrity": "sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==",
+ "dev": true
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz",
+ "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
+ "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "has-symbols": "^1.0.3",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.entries": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
+ "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.fromentries": {
+ "version": "2.0.8",
+ "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
+ "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.groupby": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
+ "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.values": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
+ "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/opener": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+ "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+ "dev": true,
+ "bin": {
+ "opener": "bin/opener-bin.js"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+ "dev": true,
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/os-homedir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+ "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/os-tmpdir": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+ "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dev": true,
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+ "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+ "dev": true,
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
+ "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==",
+ "dev": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+ "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+ "dev": true,
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pointer-tracker": {
+ "version": "2.5.3",
+ "resolved": "https://registry.npmjs.org/pointer-tracker/-/pointer-tracker-2.5.3.tgz",
+ "integrity": "sha512-LiJUeIbzk4dXq678YeyrZ++mdY17q4n/2sBHfU9wIuvmSzdiPgMvmvWN2g8mY4J7YwYOIrqrZUWP/MfFHVwYtg=="
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
+ "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/prelude-ls": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+ "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "dependencies": {
+ "fast-diff": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/private": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+ "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
+ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/pseudomap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+ "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
+ "dev": true
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/regenerate": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+ "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+ "dev": true
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+ "dev": true
+ },
+ "node_modules/regenerator-transform": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
+ "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
+ "dev": true,
+ "dependencies": {
+ "babel-runtime": "^6.18.0",
+ "babel-types": "^6.19.0",
+ "private": "^0.1.6"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
+ "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "set-function-name": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+ "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/regexpu-core": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
+ "integrity": "sha512-tJ9+S4oKjxY8IZ9jmjnp/mtytu1u3iyIQAfmI51IKWH6bFf7XR1ybtaO6j7INhZKXOTYADk7V5qxaqLkmNxiZQ==",
+ "dev": true,
+ "dependencies": {
+ "regenerate": "^1.2.1",
+ "regjsgen": "^0.2.0",
+ "regjsparser": "^0.1.4"
+ }
+ },
+ "node_modules/regjsgen": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
+ "integrity": "sha512-x+Y3yA24uF68m5GA+tBjbGYo64xXVJpbToBaWCoSNSc1hdk6dfctaRWrNFTVJZIIhL5GxW8zwjoixbnifnK59g==",
+ "dev": true
+ },
+ "node_modules/regjsparser": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+ "integrity": "sha512-jlQ9gYLfk2p3V5Ag5fYhA7fv7OHzd1KUH0PRP46xc3TgwjwgROIW572AfYg/X9kaNq/LJnu6oJcFRXlIrGoTRw==",
+ "dev": true,
+ "dependencies": {
+ "jsesc": "~0.5.0"
+ },
+ "bin": {
+ "regjsparser": "bin/parser"
+ }
+ },
+ "node_modules/regjsparser/node_modules/jsesc": {
+ "version": "0.5.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+ "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+ "dev": true,
+ "bin": {
+ "jsesc": "bin/jsesc"
+ }
+ },
+ "node_modules/repeating": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+ "integrity": "sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A==",
+ "dev": true,
+ "dependencies": {
+ "is-finite": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/replace-in-file": {
+ "version": "6.3.5",
+ "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-6.3.5.tgz",
+ "integrity": "sha512-arB9d3ENdKva2fxRnSjwBEXfK1npgyci7ZZuwysgAp7ORjHSyxz6oqIjTEv8R0Ydl4Ll7uOAZXL4vbkhGIizCg==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^4.1.2",
+ "glob": "^7.2.0",
+ "yargs": "^17.2.1"
+ },
+ "bin": {
+ "replace-in-file": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/replace-in-file/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/replace-in-file/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/replace-in-file/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/replace-in-file/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/replace-in-file/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/replace-in-file/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+ "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+ "deprecated": "Rimraf versions prior to v4 are no longer supported",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "2.79.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
+ "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/rollup-plugin-babel": {
+ "version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-4.4.0.tgz",
+ "integrity": "sha512-Lek/TYp1+7g7I+uMfJnnSJ7YWoD58ajo6Oarhlex7lvUce+RCKRuGRSgztDO3/MF/PuGKmUL5iTHKf208UNszw==",
+ "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-babel.",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.0.0",
+ "rollup-pluginutils": "^2.8.1"
+ },
+ "peerDependencies": {
+ "@babel/core": "7 || ^7.0.0-rc.2",
+ "rollup": ">=0.60.0 <3"
+ }
+ },
+ "node_modules/rollup-plugin-commonjs": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz",
+ "integrity": "sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q==",
+ "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-commonjs.",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.6.1",
+ "is-reference": "^1.1.2",
+ "magic-string": "^0.25.2",
+ "resolve": "^1.11.0",
+ "rollup-pluginutils": "^2.8.1"
+ },
+ "peerDependencies": {
+ "rollup": ">=1.12.0"
+ }
+ },
+ "node_modules/rollup-plugin-commonjs/node_modules/estree-walker": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+ "dev": true
+ },
+ "node_modules/rollup-plugin-node-resolve": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
+ "integrity": "sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw==",
+ "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-node-resolve.",
+ "dev": true,
+ "dependencies": {
+ "@types/resolve": "0.0.8",
+ "builtin-modules": "^3.1.0",
+ "is-module": "^1.0.0",
+ "resolve": "^1.11.1",
+ "rollup-pluginutils": "^2.8.1"
+ },
+ "peerDependencies": {
+ "rollup": ">=1.11.0"
+ }
+ },
+ "node_modules/rollup-plugin-serve": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-serve/-/rollup-plugin-serve-1.1.1.tgz",
+ "integrity": "sha512-H0VarZRtFR0lfiiC9/P8jzCDvtFf1liOX4oSdIeeYqUCKrmFA7vNiQ0rg2D+TuoP7leaa/LBR8XBts5viF6lnw==",
+ "dev": true,
+ "dependencies": {
+ "mime": "^2",
+ "opener": "1"
+ }
+ },
+ "node_modules/rollup-plugin-terser": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
+ "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
+ "deprecated": "This package has been deprecated and is no longer maintained. Please use @rollup/plugin-terser",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.10.4",
+ "jest-worker": "^26.2.1",
+ "serialize-javascript": "^4.0.0",
+ "terser": "^5.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^2.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2": {
+ "version": "0.36.0",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-typescript2/-/rollup-plugin-typescript2-0.36.0.tgz",
+ "integrity": "sha512-NB2CSQDxSe9+Oe2ahZbf+B4bh7pHwjV5L+RSYpCu7Q5ROuN94F9b6ioWwKfz3ueL3KTtmX4o2MUH2cgHDIEUsw==",
+ "dev": true,
+ "dependencies": {
+ "@rollup/pluginutils": "^4.1.2",
+ "find-cache-dir": "^3.3.2",
+ "fs-extra": "^10.0.0",
+ "semver": "^7.5.4",
+ "tslib": "^2.6.2"
+ },
+ "peerDependencies": {
+ "rollup": ">=1.26.3",
+ "typescript": ">=2.4.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/@rollup/pluginutils": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz",
+ "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^2.0.1",
+ "picomatch": "^2.2.2"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true
+ },
+ "node_modules/rollup-plugin-typescript2/node_modules/semver": {
+ "version": "7.6.3",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
+ "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/rollup-pluginutils": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
+ "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
+ "dev": true,
+ "dependencies": {
+ "estree-walker": "^0.6.1"
+ }
+ },
+ "node_modules/rollup-pluginutils/node_modules/estree-walker": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
+ "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
+ "dev": true
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-array-concat": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
+ "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "get-intrinsic": "^1.2.4",
+ "has-symbols": "^1.0.3",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">=0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safe-regex-test": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
+ "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "es-errors": "^1.3.0",
+ "is-regex": "^1.1.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/serialize-javascript": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+ "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+ "dev": true,
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dev": true,
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/shebang-command": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+ "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
+ "dev": true,
+ "dependencies": {
+ "shebang-regex": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+ "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+ "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.4.18",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+ "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+ "dev": true,
+ "dependencies": {
+ "source-map": "^0.5.6"
+ }
+ },
+ "node_modules/sourcemap-codec": {
+ "version": "1.4.8",
+ "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+ "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+ "deprecated": "Please use @jridgewell/sourcemap-codec instead",
+ "dev": true
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+ "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+ "dev": true
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string.prototype.trim": {
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
+ "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.0",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
+ "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
+ "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
+ "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+ "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/superstruct": {
+ "version": "0.15.5",
+ "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
+ "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ=="
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/table": {
+ "version": "6.8.2",
+ "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz",
+ "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^8.0.1",
+ "lodash.truncate": "^4.4.2",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/table/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/table/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "node_modules/terser": {
+ "version": "5.31.3",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.3.tgz",
+ "integrity": "sha512-pAfYn3NIZLyZpa83ZKigvj6Rn9c/vd5KfYGX7cN1mnzqgDcxWvrU5ZtAfIKhEXz9nRecw4z3LXkjaq96/qZqAA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.8.2",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser/node_modules/acorn": {
+ "version": "8.12.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
+ "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
+ "dev": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/terser/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/terser/node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "dev": true,
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+ "dev": true
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+ "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/transformation-matrix": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/transformation-matrix/-/transformation-matrix-2.16.1.tgz",
+ "integrity": "sha512-tdtC3wxVEuzU7X/ydL131Q3JU5cPMEn37oqVLITjRDSDsnSHVFzW2JiCLfZLIQEgWzZHdSy3J6bZzvKEN24jGA==",
+ "funding": {
+ "url": "https://github.com/sponsors/chrvadala"
+ }
+ },
+ "node_modules/trim-right": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+ "integrity": "sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tsconfig-paths": {
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
+ "dev": true,
+ "dependencies": {
+ "@types/json5": "^0.0.29",
+ "json5": "^1.0.2",
+ "minimist": "^1.2.6",
+ "strip-bom": "^3.0.0"
+ }
+ },
+ "node_modules/tsconfig-paths/node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.6.3",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
+ "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ=="
+ },
+ "node_modules/tsutils": {
+ "version": "3.21.0",
+ "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+ "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/tsutils/node_modules/tslib": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+ "dev": true
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+ "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/typed-array-buffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
+ "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/typed-array-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
+ "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-byte-offset": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
+ "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typed-array-length": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
+ "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-proto": "^1.0.3",
+ "is-typed-array": "^1.1.13",
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.9.5",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
+ "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
+ "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+ "dev": true,
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-bigints": "^1.0.2",
+ "has-symbols": "^1.0.3",
+ "which-boxed-primitive": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ },
+ "node_modules/universalify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+ "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
+ "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.1.2",
+ "picocolors": "^1.0.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "dev": true,
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/v8-compile-cache": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz",
+ "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==",
+ "dev": true
+ },
+ "node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
+ "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+ "dev": true,
+ "dependencies": {
+ "is-bigint": "^1.0.1",
+ "is-boolean-object": "^1.1.0",
+ "is-number-object": "^1.0.4",
+ "is-string": "^1.0.5",
+ "is-symbol": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.15",
+ "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
+ "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
+ "dev": true,
+ "dependencies": {
+ "available-typed-arrays": "^1.0.7",
+ "call-bind": "^1.0.7",
+ "for-each": "^0.3.3",
+ "gopd": "^1.0.1",
+ "has-tostringtag": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+ "dev": true
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ }
+ }
+}
diff --git a/pkgs/msmtp/0001-msmtp-run-passwordeval-if-tls_key_file-is-provided-e.patch b/pkgs/msmtp/0001-msmtp-run-passwordeval-if-tls_key_file-is-provided-e.patch
new file mode 100644
index 0000000..469b666
--- /dev/null
+++ b/pkgs/msmtp/0001-msmtp-run-passwordeval-if-tls_key_file-is-provided-e.patch
@@ -0,0 +1,26 @@
+From 6febfc0f87c0aa4ed595f05441f8b3c9b59b2f50 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Wed, 31 Jul 2024 15:38:29 -0600
+Subject: [PATCH] msmtp: run passwordeval if tls_key_file is provided, even
+ without auth
+
+---
+ src/msmtp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/msmtp.c b/src/msmtp.c
+index 71a871a..37f2601 100644
+--- a/src/msmtp.c
++++ b/src/msmtp.c
+@@ -4048,7 +4048,7 @@ int main(int argc, char *argv[])
+
+ /* OK, we're using the settings in 'account'. Complete them and check
+ * them. */
+- if (account->auth_mech && !account->password && account->passwordeval)
++ if ((account->auth_mech || account->tls_key_file) && !account->password && account->passwordeval)
+ {
+ if (eval(account->passwordeval, &account->password, &errstr) != 0)
+ {
+--
+2.44.1
+
diff --git a/pkgs/msmtp/default.nix b/pkgs/msmtp/default.nix
new file mode 100644
index 0000000..23559c5
--- /dev/null
+++ b/pkgs/msmtp/default.nix
@@ -0,0 +1,151 @@
+{
+ resholve,
+ stdenv,
+ symlinkJoin,
+ lib,
+ fetchFromGitHub,
+ autoreconfHook,
+ pkg-config,
+ bash,
+ coreutils,
+ gnugrep,
+ gnutls,
+ gsasl,
+ libidn2,
+ netcat-gnu,
+ texinfo,
+ which,
+ Security,
+ withKeyring ? true,
+ libsecret,
+ withSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd,
+ systemd,
+ withScripts ? true,
+}: let
+ inherit (lib) getBin getExe optionals;
+
+ version = "1.8.22";
+
+ src = fetchFromGitHub {
+ owner = "marlam";
+ repo = "msmtp-mirror";
+ rev = "msmtp-${version}";
+ hash = "sha256-Jt/uvGBrYYr6ua6LVPiP0nuRiIkxBJASdgHBNHivzxQ=";
+ };
+
+ meta = with lib; {
+ description = "Simple and easy to use SMTP client with excellent sendmail compatibility";
+ homepage = "https://marlam.de/msmtp/";
+ license = licenses.gpl3Plus;
+ maintainers = with maintainers; [peterhoeg];
+ platforms = platforms.unix;
+ mainProgram = "msmtp";
+ };
+
+ binaries = stdenv.mkDerivation {
+ pname = "msmtp-binaries";
+ inherit version src meta;
+
+ patches = [
+ ./0001-msmtp-run-passwordeval-if-tls_key_file-is-provided-e.patch
+ ];
+
+ configureFlags =
+ ["--sysconfdir=/etc" "--with-libgsasl"]
+ ++ optionals stdenv.isDarwin ["--with-macosx-keyring"];
+
+ buildInputs =
+ [gnutls gsasl libidn2]
+ ++ optionals stdenv.isDarwin [Security]
+ ++ optionals withKeyring [libsecret];
+
+ nativeBuildInputs = [autoreconfHook pkg-config texinfo];
+
+ enableParallelBuilding = true;
+
+ postInstall = ''
+ install -Dm444 -t $out/share/doc/msmtp doc/*.example
+ ln -s msmtp $out/bin/sendmail
+ '';
+ };
+
+ scripts = resholve.mkDerivation {
+ pname = "msmtp-scripts";
+ inherit version src meta;
+
+ patches = [./paths.patch];
+
+ postPatch = ''
+ substituteInPlace scripts/msmtpq/msmtpq \
+ --replace @journal@ ${
+ if withSystemd
+ then "Y"
+ else "N"
+ }
+ '';
+
+ dontConfigure = true;
+ dontBuild = true;
+
+ installPhase = ''
+ runHook preInstall
+
+ install -Dm555 -t $out/bin scripts/msmtpq/msmtp*
+ install -Dm444 -t $out/share/doc/msmtp/scripts scripts/msmtpq/README*
+ install -Dm444 -t $out/share/doc/msmtp/scripts scripts/{find_alias,msmtpqueue,set_sendmail}/*
+
+ if grep --quiet -E '@.+@' $out/bin/*; then
+ echo "Unsubstituted variables found. Aborting!"
+ grep -E '@.+@' $out/bin/*
+ exit 1
+ fi
+
+ runHook postInstall
+ '';
+
+ solutions = {
+ msmtpq = {
+ scripts = ["bin/msmtpq"];
+ interpreter = getExe bash;
+ inputs =
+ [
+ binaries
+ coreutils
+ gnugrep
+ netcat-gnu
+ which
+ ]
+ ++ optionals withSystemd [systemd];
+ execer =
+ [
+ "cannot:${getBin binaries}/bin/msmtp"
+ "cannot:${getBin netcat-gnu}/bin/nc"
+ ]
+ ++ optionals withSystemd [
+ "cannot:${getBin systemd}/bin/systemd-cat"
+ ];
+ fix."$MSMTP" = ["msmtp"];
+ fake.external =
+ ["ping"]
+ ++ optionals (!withSystemd) ["systemd-cat"];
+ };
+
+ msmtp-queue = {
+ scripts = ["bin/msmtp-queue"];
+ interpreter = getExe bash;
+ inputs = ["${placeholder "out"}/bin"];
+ execer = ["cannot:${placeholder "out"}/bin/msmtpq"];
+ };
+ };
+ };
+in
+ if withScripts
+ then
+ symlinkJoin
+ {
+ name = "msmtp-${version}";
+ inherit version meta;
+ paths = [binaries scripts];
+ passthru = {inherit binaries scripts;};
+ }
+ else binaries
diff --git a/pkgs/msmtp/paths.patch b/pkgs/msmtp/paths.patch
new file mode 100644
index 0000000..9298519
--- /dev/null
+++ b/pkgs/msmtp/paths.patch
@@ -0,0 +1,64 @@
+diff --git a/scripts/msmtpq/msmtpq b/scripts/msmtpq/msmtpq
+index d8b4039..1f2a7b5 100755
+--- a/scripts/msmtpq/msmtpq
++++ b/scripts/msmtpq/msmtpq
+@@ -60,8 +60,8 @@ err() { dsp '' "$@" '' ; exit 1 ; }
+ ## e.g. ( export MSMTP=/path/to/msmtp )
+ if [ "$MSMTP" = "" ] ; then # If MSMTP is unset or empty...
+ MSMTP=msmtp
+-elif [ ! -x "$MSMTP" ] ; then
+- log -e 1 "msmtpq : can't find the msmtp executable [ $MSMTP ]" # if not found - complain ; quit
++# elif [ ! -x "$MSMTP" ] ; then
++# log -e 1 "msmtpq : can't find the msmtp executable [ $MSMTP ]" # if not found - complain ; quit
+ fi
+ ##
+ ## set the queue var to the location of the msmtp queue directory
+@@ -71,7 +71,7 @@ fi
+ ## ( chmod 0700 msmtp.queue )
+ ##
+ ## the queue dir - export this variable to reflect where you'd like it to be (no quotes !!)
+-Q=${Q:-~/.msmtp.queue}
++Q=${MSMTP_QUEUE:-~/.msmtp.queue}
+ [ -d "$Q" ] || mkdir -m 0700 -p "$Q" || \
+ err '' "msmtpq : can't find or create msmtp queue directory [ $Q ]" '' # if not present - complain ; quit
+ ##
+@@ -85,8 +85,10 @@ Q=${Q:-~/.msmtp.queue}
+ ##
+ ## the queue log file - export this variable to change where logs are stored (but no quotes !!)
+ ## Set it to "" (empty string) to disable logging.
+-[ -v LOG ] || LOG=~/log/msmtp.queue.log
++LOG=${MSMTP_LOG:-~/log/msmtp.queue.log}
+ [ -d "$(dirname "$LOG")" ] || mkdir -p "$(dirname "$LOG")"
++
++JOURNAL=@journal@
+ ## ======================================================================================
+
+ ## msmtpq can use the following environment variables :
+@@ -139,6 +141,7 @@ on_exit() { # unlock the queue on exit if the lock was
+ ## display msg to user, as well
+ ##
+ log() {
++ local NAME=msmtpq
+ local ARG RC PFX
+ PFX="$('date' +'%Y %d %b %H:%M:%S')"
+ # time stamp prefix - "2008 13 Mar 03:59:45 "
+@@ -156,10 +159,19 @@ log() {
+ done
+ fi
+
++ if [ "$JOURNAL" = "Y" ]; then
++ for ARG; do
++ [ -n "$ARG" ] &&
++ echo "$ARG" | systemd-cat -t "$NAME" -p info
++ done
++ fi
++
+ if [ -n "$RC" ] ; then # an error ; leave w/error return
+ [ -n "$LKD" ] && lock_queue -u # unlock here (if locked)
+ [ -n "$LOG" ] && \
+ echo " exit code = $RC" >> "$LOG" # logging ok ; send exit code to log
++ [ "$JOURNAL" = "Y" ] && \
++ echo "exit code= $RC" | systemd-cat -t "$NAME" -p emerg
+ exit "$RC" # exit w/return code
+ fi
+ }
diff --git a/pkgs/mssql-tools.nix b/pkgs/mssql-tools.nix
new file mode 100644
index 0000000..ecf2b37
--- /dev/null
+++ b/pkgs/mssql-tools.nix
@@ -0,0 +1,55 @@
+# Basado en derivación para skypeforlinux en nixpkgs
+# Ver environment.unixODBCDrivers
+{
+ lib,
+ stdenv,
+ fetchurl,
+ dpkg,
+ glibc,
+ unixODBC,
+}: let
+ version = "17.9.1.1-1";
+ ubuntuRelease = "21.10";
+in
+ stdenv.mkDerivation {
+ pname = "mssql-tools";
+ inherit version;
+
+ system = "x86_64-linux";
+
+ src =
+ if stdenv.hostPlatform.system == "x86_64-linux"
+ then
+ fetchurl
+ {
+ url = "https://packages.microsoft.com/ubuntu/${ubuntuRelease}/prod/pool/main/m/mssql-tools/mssql-tools_${version}_amd64.deb";
+ sha256 = "0ya9643assr80yh6g0nd3i6iw819frhbb1m421khwplk9iq793kk";
+ }
+ else throw "mssql-tools is not supported on ${stdenv.hostPlatform.system}";
+
+ buildInputs = [dpkg];
+ dontUnpack = true;
+ outputs = ["out" "doc"];
+
+ installPhase = ''
+ mkdir -p $out
+ dpkg -x $src $out
+ mv $out/opt/mssql-tools/{bin,share} $out
+ mv $out/usr/share/doc/mssql-tools $doc
+ rm -r $out/opt $out/usr
+ '';
+
+ postFixup = let
+ rpath = lib.makeLibraryPath [glibc stdenv.cc.cc unixODBC];
+ in ''
+ for file in $(find $out/bin -type f); do
+ patchelf --set-interpreter "$(cat $NIX_CC/nix-support/dynamic-linker)" "$file"
+ patchelf --set-rpath ${rpath} $file
+ done
+ '';
+
+ meta = with lib; {
+ license = licenses.unfree;
+ platforms = ["x86_64-linux"];
+ };
+ }
diff --git a/pkgs/oregano/check-cfg-gio-unix.patch b/pkgs/oregano/check-cfg-gio-unix.patch
new file mode 100644
index 0000000..a20bf0d
--- /dev/null
+++ b/pkgs/oregano/check-cfg-gio-unix.patch
@@ -0,0 +1,12 @@
+diff --git a/wscript b/wscript
+index 03de4b3..f64ccc4 100644
+--- a/wscript
++++ b/wscript
+@@ -68,6 +68,7 @@ def configure(conf):
+
+ conf.check_cfg(atleast_pkgconfig_version='0.26')
+ conf.check_cfg(package='glib-2.0', uselib_store='GLIB', args=['glib-2.0 >= 2.44', '--cflags', '--libs'], mandatory=True)
++ conf.check_cfg(package='gio-unix-2.0', uselib_store='GLIB', args=['--cflags', '--libs'], mandatory=True)
+ conf.check_cfg(package='gobject-2.0', uselib_store='GOBJECT', args=['--cflags', '--libs'], mandatory=True)
+ conf.check_cfg(package='gtk+-3.0', uselib_store='GTK3', args=['gtk+-3.0 >= 3.12', '--cflags', '--libs'], mandatory=True)
+ conf.check_cfg(package='libxml-2.0', uselib_store='XML', args=['--cflags', '--libs'], mandatory=True)
diff --git a/pkgs/oregano/default.nix b/pkgs/oregano/default.nix
new file mode 100644
index 0000000..14108d5
--- /dev/null
+++ b/pkgs/oregano/default.nix
@@ -0,0 +1,75 @@
+{
+ fetchFromGitHub,
+ glib,
+ goocanvas2,
+ gnucap,
+ groff,
+ gtk3,
+ gtksourceview,
+ intltool,
+ libxml2,
+ lib,
+ makeWrapper,
+ ngspice,
+ perl,
+ pkg-config,
+ python3,
+ stdenv,
+ wafHook,
+ wrapGAppsHook,
+ useNgspice ? false,
+}: let
+ version = "0.84.43";
+in
+ stdenv.mkDerivation {
+ pname = "oregano";
+ inherit version;
+
+ src = fetchFromGitHub {
+ owner = "drahnr";
+ repo = "oregano";
+ rev = "v${version}";
+ hash = "sha256-1GsL0N3O0clqdgkXoPKMhvW+y4Rzg4QSeOA54nH4kz4=";
+ };
+
+ nativeBuildInputs = [makeWrapper wafHook wrapGAppsHook];
+ patches = [./check-cfg-gio-unix.patch];
+
+ buildInputs = [
+ glib
+ goocanvas2
+ groff
+ gtk3
+ gtksourceview
+ intltool
+ libxml2
+ perl
+ pkg-config
+ python3
+ ];
+
+ postFixup = ''
+ wrapProgram $out/bin/oregano \
+ --suffix PATH : ${lib.makeBinPath [
+ (
+ if useNgspice
+ then ngspice
+ else gnucap
+ )
+ ]}
+ '';
+
+ meta = with lib; {
+ description = "Schematic capture and circuit simulator";
+ longDescription = ''
+ Oregano is an application for schematic capture and simulation of
+ electronic circuits. The actual simulation is performed by Berkeley
+ Spice, GNUcap or the new generation ngspice.
+ '';
+
+ homepage = "https://github.com/drahnr/oregano/";
+ license = licenses.gpl2;
+ platforms = lib.platforms.linux;
+ maintainers = with maintainers; [_3442];
+ };
+ }
diff --git a/pkgs/pass-bcr/bcr.bash b/pkgs/pass-bcr/bcr.bash
new file mode 100755
index 0000000..5d02748
--- /dev/null
+++ b/pkgs/pass-bcr/bcr.bash
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [ $# -eq 0 ]; then
+ echo "Usage: $0 <challenge>..." >&2
+ exit 1
+fi
+
+function index_for_each() {
+ keys="$1"
+ shift
+
+ for entry in "$@"; do
+ if echo "$entry" | grep -vq "^[a-jA-J][1-5]$"; then
+ echo "Bad challenge: $entry" >&2
+ exit 1
+ fi
+
+ echo "$entry: $(echo "$keys" | tail -n+$(echo "$entry" | tail -c+2) | head -1 | cut -d' ' -f$((1 + $(echo "$entry" | head -c1 | tr 'a-jA-J' '0-90-9'))))"
+ done
+}
+
+index_for_each "$(pass show any/bank/bcr/default | grep -A6 '^Clave dinámica:$' | tail -5 | sed 's/^[0-9]\s\+//g')" "$@"
diff --git a/pkgs/pass-bcr/completions/bash b/pkgs/pass-bcr/completions/bash
new file mode 100644
index 0000000..8fe1887
--- /dev/null
+++ b/pkgs/pass-bcr/completions/bash
@@ -0,0 +1,8 @@
+# pass-update completion file for bash
+
+PASSWORD_STORE_EXTENSION_COMMANDS+=(bcr)
+
+__password_store_extension_complete_bcr() {
+ local args=()
+ COMPREPLY+=($(compgen -W "${args[*]}" -- ${cur}))
+}
diff --git a/pkgs/pass-bcr/completions/zsh b/pkgs/pass-bcr/completions/zsh
new file mode 100644
index 0000000..9d120a5
--- /dev/null
+++ b/pkgs/pass-bcr/completions/zsh
@@ -0,0 +1,8 @@
+#compdef pass-bcr
+#description Clave dinámica BCR
+
+_pass-ubcr () {
+ _arguments :
+}
+
+_pass-bcr "$@"
diff --git a/pkgs/pass-bcr/default.nix b/pkgs/pass-bcr/default.nix
new file mode 100644
index 0000000..72d08fb
--- /dev/null
+++ b/pkgs/pass-bcr/default.nix
@@ -0,0 +1,19 @@
+{stdenv, ...}:
+stdenv.mkDerivation {
+ pname = "pass-bcr";
+ version = "1.0";
+
+ src = ./.;
+
+ installPhase = ''
+ runHook preInstall
+
+ mkdir -p $out/{lib/password-store/extensions,share/{bash-completion/completions,zsh/site-functions}}
+ cp bcr.bash $out/lib/password-store/extensions
+ cp completions/zsh $out/share/zsh/site-functions/_pass-bcr
+ cp completions/bash $out/share/bash-completion/completions/pass-bcr
+ chmod +x $out/lib/password-store/extensions/bcr.bash
+
+ runHook postInstall
+ '';
+}
diff --git a/pkgs/pass-tail/default.nix b/pkgs/pass-tail/default.nix
new file mode 100644
index 0000000..e664a93
--- /dev/null
+++ b/pkgs/pass-tail/default.nix
@@ -0,0 +1,25 @@
+{
+ fetchFromGitHub,
+ lib,
+ stdenv,
+}:
+stdenv.mkDerivation {
+ pname = "pass-tail";
+ version = "master-20220426";
+
+ src = fetchFromGitHub {
+ repo = "pass-extension-tail";
+ owner = "palortoff";
+
+ rev = "e8455bc0ada9b25722d2826063b1dfdc521d5b24";
+ hash = "sha256-62jTEbNuNZr6g6zvqUdfeseGNnn8Z1s3cY7i5U+a4PU=";
+ };
+
+ installPhase = ''
+ runHook preInstall
+
+ make install PREFIX=$out BASHCOMPDIR=$out/share/bash-completion/completions
+
+ runHook postInstall
+ '';
+}
diff --git a/pkgs/postfix/0001-smtpd-implement-CCERTS-action-for-access-5-tables.patch b/pkgs/postfix/0001-smtpd-implement-CCERTS-action-for-access-5-tables.patch
new file mode 100644
index 0000000..ceec3dc
--- /dev/null
+++ b/pkgs/postfix/0001-smtpd-implement-CCERTS-action-for-access-5-tables.patch
@@ -0,0 +1,55 @@
+From e50dd20ed36e3031a049e1fdb99894d2a974adfa Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sat, 27 Jul 2024 14:42:37 -0600
+Subject: [PATCH] smtpd: implement CCERTS action for access(5) tables
+
+Permits access if a valid TLS client certificate is present and matches
+any item from a space or comma-separated list of certificate
+fingerprints given as argument. Otherwise, behaves as DUNNO.
+
+Example usage:
+
+/etc/postfix/sender_ccerts:
+ user@example.com CCERTS AA:BB:CC:DD:EE:FF:12:34:56:67:2E:FB:3F:34:99:90:AB:CD:EF:4C
+---
+ postfix/src/smtpd/smtpd_check.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+diff --git a/src/smtpd/smtpd_check.c b/src/smtpd/smtpd_check.c
+index 6aeda7475..b4232194d 100644
+--- a/src/smtpd/smtpd_check.c
++++ b/src/smtpd/smtpd_check.c
+@@ -2677,6 +2677,30 @@ static int check_table_result(SMTPD_STATE *state, const char *table,
+ }
+ }
+
++ // Advertencia: buf para value usa un límite de 10 chars (ver inicio de esta función)
++ // FIXME: Posible timing attack, solo determinaría fingerprint
++ if (STREQUAL(value, "CCERTS", cmd_len)) {
++#ifdef USE_TLS
++ if (TLS_CERT_IS_PRESENT(state->tls_context)) {
++ const char *fprint = state->tls_context->peer_cert_fprint;
++ if (fprint && *fprint) {
++ size_t fprint_len = strlen(fprint);
++
++ const char *ccerts = cmd_text;
++ while (*ccerts) {
++ size_t ccert_len = strcspn(ccerts, ", \t");
++ if (ccert_len == fprint_len && strncmp(ccerts, fprint, fprint_len) == 0)
++ return (smtpd_acl_permit(state, STR(buf), reply_class, reply_name,
++ "from %s", table));
++
++ ccerts += ccert_len + strspn(ccerts + ccert_len, ", \t");
++ }
++ }
++ }
++#endif
++ return (SMTPD_CHECK_DUNNO);
++ }
++
+ /*
+ * All-numeric result probably means OK - some out-of-band authentication
+ * mechanism uses this as time stamp.
+--
+2.44.1
+
diff --git a/pkgs/postfix/default.nix b/pkgs/postfix/default.nix
new file mode 100644
index 0000000..b625a71
--- /dev/null
+++ b/pkgs/postfix/default.nix
@@ -0,0 +1,9 @@
+{postfix}:
+postfix.overrideAttrs {
+ # Nota: hay que cambiar prefix postfix/src/ -> src/ en el patch porque las release tarballs vienen así
+ patches =
+ (postfix.patches or [])
+ ++ [
+ ./0001-smtpd-implement-CCERTS-action-for-access-5-tables.patch
+ ];
+}
diff --git a/pkgs/py-mini-racer.nix b/pkgs/py-mini-racer.nix
new file mode 100644
index 0000000..e51fbe8
--- /dev/null
+++ b/pkgs/py-mini-racer.nix
@@ -0,0 +1,20 @@
+{
+ buildPythonPackage,
+ fetchPypi,
+ pytest,
+ six,
+ tox,
+}: let
+ pname = "py_mini_racer";
+ version = "0.6.0";
+in
+ buildPythonPackage {
+ inherit pname version;
+
+ src = fetchPypi {
+ inherit pname version;
+ hash = "sha256-9x42tkPZR7ppjFfNm9IjLIPKmXsIAvwvf3lYI3cEDBE=";
+ };
+
+ doCheck = false;
+ }
diff --git a/pkgs/rqlite.nix b/pkgs/rqlite.nix
new file mode 100644
index 0000000..4dd8f74
--- /dev/null
+++ b/pkgs/rqlite.nix
@@ -0,0 +1,21 @@
+{
+ lib,
+ buildGoModule,
+ fetchFromGitHub,
+}: let
+ version = "7.5.0";
+in
+ buildGoModule {
+ pname = "rqlite";
+ inherit version;
+
+ src = fetchFromGitHub {
+ owner = "rqlite";
+ repo = "rqlite";
+ rev = "v${version}";
+ sha256 = "0hi5kq8w26i8azlcxy750zmbciga6l5n090ir261n00djigm5m59";
+ };
+
+ vendorHash = "sha256-YT1nK1vFmNCRJyWOiQhSJr83qW8uxkHXCZ81/Ch6qpg=";
+ doCheck = false;
+ }
diff --git a/pkgs/rv8.nix b/pkgs/rv8.nix
new file mode 100644
index 0000000..63579de
--- /dev/null
+++ b/pkgs/rv8.nix
@@ -0,0 +1,55 @@
+{
+ callPackage,
+ lib,
+ fetchFromGitHub,
+ stdenv,
+ writeText,
+ ...
+}:
+stdenv.mkDerivation {
+ pname = "rv8";
+ version = "master";
+
+ src = fetchFromGitHub {
+ owner = "michaeljclark";
+ repo = "rv8";
+ rev = "834259098a5c182874aac97d82a164d144244e1a";
+ sha256 = "sha256-I1lMKxfu+04Ap9WNjr8S1FLcUpQ3pVlTu61L/LFFGJ0=";
+ fetchSubmodules = true;
+ };
+
+ makeFlags = ["AR=${stdenv.cc.targetPrefix}ar" "DEST_DIR=$(out)"];
+
+ preInstall = ''
+ mkdir -p $out/bin $out/lib
+ '';
+
+ patches = [
+ (writeText "rv8-include-limits.patch" ''
+ diff --git a/src/gen/gen-cc.cc b/src/gen/gen-cc.cc
+ index fd9f948..44c8bf7 100644
+ --- a/src/gen/gen-cc.cc
+ +++ b/src/gen/gen-cc.cc
+ @@ -12,6 +12,7 @@
+ #include <deque>
+ #include <map>
+ #include <set>
+ +#include <limits>
+
+ #include "util.h"
+ #include "cmdline.h"
+ diff --git a/src/gen/gen-fpu-test.cc b/src/gen/gen-fpu-test.cc
+ index f1b8f84..d0a2f32 100644
+ --- a/src/gen/gen-fpu-test.cc
+ +++ b/src/gen/gen-fpu-test.cc
+ @@ -12,6 +12,7 @@
+ #include <deque>
+ #include <map>
+ #include <set>
+ +#include <limits>
+
+ #include "util.h"
+ #include "cmdline.h"
+ '')
+ ];
+}
diff --git a/pkgs/scripts/clip.nix b/pkgs/scripts/clip.nix
new file mode 100644
index 0000000..3e16e3e
--- /dev/null
+++ b/pkgs/scripts/clip.nix
@@ -0,0 +1,50 @@
+{
+ lib,
+ writeShellScriptBin,
+ gnome-screenshot,
+ xclip,
+ file,
+ imagemagick,
+ toPDF,
+ ...
+}:
+with lib; let
+ name =
+ if toPDF
+ then "clip-pdf"
+ else "clip";
+
+ pdfCmdline = optionalString toPDF ''
+ if [ $# -lt 1 ]; then
+ echo "Usage: $0 <out.pdf> [opts...]" >&2
+ exit 1
+ fi
+
+ OUT="$1"
+ shift
+ '';
+
+ copyOut =
+ if toPDF
+ then ''
+ ${imagemagick}/bin/convert "$CLIP" "$OUT"
+ ''
+ else ''
+ ${xclip}/bin/xclip -selection clipboard \
+ -t $(${file}/bin/file -b --mime-type $CLIP) <"$CLIP"
+ '';
+in
+ writeShellScriptBin name ''
+ ${pdfCmdline}
+
+ OPTIONS=-a
+ if [ "x$@" != "x" ]; then
+ OPTIONS="$@"
+ fi
+
+ CLIP="$HOME/vtmp/$$.png"
+ ${gnome-screenshot}/bin/gnome-screenshot "$OPTIONS" -f "$CLIP"
+ ${copyOut}
+
+ rm "$CLIP"
+ ''
diff --git a/pkgs/scripts/default.nix b/pkgs/scripts/default.nix
new file mode 100644
index 0000000..ed18647
--- /dev/null
+++ b/pkgs/scripts/default.nix
@@ -0,0 +1,13 @@
+{
+ callPackage,
+ symlinkJoin,
+ ...
+}:
+symlinkJoin {
+ name = "scripts";
+ paths = [
+ (callPackage ./clip.nix {toPDF = false;})
+ (callPackage ./clip.nix {toPDF = true;})
+ (callPackage ./merge-pdfs.nix {})
+ ];
+}
diff --git a/pkgs/scripts/merge-pdfs.nix b/pkgs/scripts/merge-pdfs.nix
new file mode 100644
index 0000000..cb7d678
--- /dev/null
+++ b/pkgs/scripts/merge-pdfs.nix
@@ -0,0 +1,38 @@
+{
+ writeShellScriptBin,
+ pdftk,
+ ...
+}:
+writeShellScriptBin "merge-pdfs" ''
+ set -e
+ export PATH="$PATH:${pdftk}/bin"
+
+ if [ $# -lt 3 ]; then
+ echo "Usage: $0 <output> <PDFs...>" >&2
+ exit 1
+ fi
+
+ OUTPUT="$1"
+ shift
+
+ WORKDIR="$HOME/vtmp/merge-pdfs.$$"
+ BOOKMARKS="$WORKDIR/bookmarks.txt"
+ FMT="BookmarkBegin
+ BookmarkTitle: %s
+ BookmarkLevel: 1
+ BookmarkPageNumber: 1
+ "
+
+ mkdir "$WORKDIR"
+
+ N=0
+ for SOURCE in "$@"; do
+ BASE="$(basename "$SOURCE")"
+ printf "$FMT" "''${BASE%.*}" >"$BOOKMARKS"
+ pdftk "$SOURCE" update_info "$BOOKMARKS" output "$WORKDIR/"$(printf "%04d" $N).pdf
+ N=$((N+1))
+ done
+
+ pdftk "$WORKDIR"/*.pdf cat output "$OUTPUT"
+ rm -r "$WORKDIR"
+''
diff --git a/pkgs/simple-scalar/0001-fix-case-of-YY_CURRENT_BUFFER.patch b/pkgs/simple-scalar/0001-fix-case-of-YY_CURRENT_BUFFER.patch
new file mode 100644
index 0000000..5d7cf85
--- /dev/null
+++ b/pkgs/simple-scalar/0001-fix-case-of-YY_CURRENT_BUFFER.patch
@@ -0,0 +1,25 @@
+From 33f6fb023c09464467eea4538f18e2a131acee3a Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Wed, 26 Apr 2023 13:37:32 -0600
+Subject: [PATCH] fix case of YY_CURRENT_BUFFER
+
+---
+ ld/ldlex.l | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/simpleutils-990811/ld/ldlex.l b/simpleutils-990811/ld/ldlex.l
+index 2eef80f..561b8af 100644
+--- a/simpleutils-990811/ld/ldlex.l
++++ b/simpleutils-990811/ld/ldlex.l
+@@ -585,7 +585,7 @@ yy_input (buf, result, max_size)
+ int max_size;
+ {
+ *result = 0;
+- if (yy_current_buffer->yy_input_file)
++ if (YY_CURRENT_BUFFER->yy_input_file)
+ {
+ if (yyin)
+ {
+--
+2.38.4
+
diff --git a/pkgs/simple-scalar/0002-define-sys_nerr.patch b/pkgs/simple-scalar/0002-define-sys_nerr.patch
new file mode 100644
index 0000000..021d157
--- /dev/null
+++ b/pkgs/simple-scalar/0002-define-sys_nerr.patch
@@ -0,0 +1,24 @@
+From 442edcc1d281a62a0092bcde19038ba3c976e499 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Wed, 26 Apr 2023 13:35:21 -0600
+Subject: [PATCH 1/3] define sys_nerr
+
+---
+ gcc.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/gcc-2.7.2.3/gcc.c b/gcc-2.7.2.3/gcc.c
+index fe7de5b..1ac933f 100644
+--- a/gcc-2.7.2.3/gcc.c
++++ b/gcc-2.7.2.3/gcc.c
+@@ -176,6 +176,7 @@ extern int errno;
+ #endif
+
+ extern int sys_nerr;
++int __attribute__((weak)) sys_nerr = 0;
+ #ifndef HAVE_STRERROR
+ #if defined(bsd4_4)
+ extern const char *const sys_errlist[];
+--
+2.38.4
+
diff --git a/pkgs/simple-scalar/0003-fix-obstack.h-post-increment.patch b/pkgs/simple-scalar/0003-fix-obstack.h-post-increment.patch
new file mode 100644
index 0000000..8e38a80
--- /dev/null
+++ b/pkgs/simple-scalar/0003-fix-obstack.h-post-increment.patch
@@ -0,0 +1,25 @@
+From b074acb822459a42d2507ad5729e9e60bb1de572 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Wed, 26 Apr 2023 13:35:42 -0600
+Subject: [PATCH 2/3] fix obstack.h post-increment
+
+---
+ obstack.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/gcc-2.7.2.3/obstack.h b/gcc-2.7.2.3/obstack.h
+index 28bcd44..3a517b5 100644
+--- a/gcc-2.7.2.3/obstack.h
++++ b/gcc-2.7.2.3/obstack.h
+@@ -338,7 +338,7 @@ __extension__ \
+ if (__o->next_free + sizeof (void *) > __o->chunk_limit) \
+ _obstack_newchunk (__o, sizeof (void *)); \
+ if (!__o->alloc_failed) \
+- *((void **)__o->next_free)++ = ((void *)datum); \
++ *((void **)__o->next_free++) = ((void *)datum); \
+ (void) 0; })
+
+ #define obstack_int_grow(OBSTACK,datum) \
+--
+2.38.4
+
diff --git a/pkgs/simple-scalar/0004-stdarg.h-instead-of-varargs.h.patch b/pkgs/simple-scalar/0004-stdarg.h-instead-of-varargs.h.patch
new file mode 100644
index 0000000..5e8fc7b
--- /dev/null
+++ b/pkgs/simple-scalar/0004-stdarg.h-instead-of-varargs.h.patch
@@ -0,0 +1,25 @@
+From 12c34c7ff8e4e00ba54bd0b90f2ca6905109cb5d Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Wed, 26 Apr 2023 13:35:57 -0600
+Subject: [PATCH 3/3] stdarg.h instead of varargs.h
+
+---
+ protoize.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/gcc-2.7.2.3/protoize.c b/gcc-2.7.2.3/protoize.c
+index 9728bf2..fb82ef0 100644
+--- a/gcc-2.7.2.3/protoize.c
++++ b/gcc-2.7.2.3/protoize.c
+@@ -57,7 +57,7 @@ Boston, MA 02111-1307, USA. */
+ #define _POSIX_SOURCE
+ #endif
+
+-#include <varargs.h>
++#include <stdarg.h>
+ /* On some systems stdio.h includes stdarg.h;
+ we must bring in varargs.h first. */
+ #include <stdio.h>
+--
+2.38.4
+
diff --git a/pkgs/simple-scalar/default.nix b/pkgs/simple-scalar/default.nix
new file mode 100644
index 0000000..01e8ee4
--- /dev/null
+++ b/pkgs/simple-scalar/default.nix
@@ -0,0 +1,5 @@
+{callPackage}: {
+ gcc-sslittle-na-sstrix = callPackage ./gcc-sslittle-na-sstrix.nix {};
+ simplesim = callPackage ./simplesim.nix {};
+ wattchg7 = callPackage ./simplesim.nix {isWattch = true;};
+}
diff --git a/pkgs/simple-scalar/gcc-sslittle-na-sstrix.nix b/pkgs/simple-scalar/gcc-sslittle-na-sstrix.nix
new file mode 100644
index 0000000..9cb6d30
--- /dev/null
+++ b/pkgs/simple-scalar/gcc-sslittle-na-sstrix.nix
@@ -0,0 +1,109 @@
+# https://www.cse.iitd.ac.in/~cs5070217/csl718/assignment1/ss_install_instructions.html
+{
+ bison,
+ fetchurl,
+ flex,
+ multiStdenv,
+ stdenv_32bit,
+}: let
+ host = "i686-pc-linux";
+ target = "sslittle-na-sstrix";
+
+ gcc-version = "2.7.2.3";
+ makeflags = "LANGUAGES=c CC=\"$CC -m32 $CFLAGS\" prefix=$out";
+in
+ multiStdenv.mkDerivation {
+ pname = "gcc-sslittle-na-sstrix";
+ version = "1998-08-11"; # !!!
+
+ nativeBuildInputs = [flex bison];
+
+ sourceRoot = ".";
+
+ srcs = [
+ (fetchTarball {
+ name = "simpleutils-990811";
+
+ url = "https://www.cse.iitd.ac.in/~cs5070217/csl718/simpleutils-990811.tar.gz";
+ sha256 = "sha256:0w952z382s7ghrxwrad7fd058b1kj5ad1abh8idxwwk47va72cdf";
+ })
+ ];
+
+ # El código es muy viejo y Nix usa opciones muy estrictas por defecto
+ CFLAGS = "-O3 -Wno-error=format-security";
+
+ # Algunas tarballs vienen sin directorio de primer nivel y además requieren arreglos
+ postUnpack = let
+ simpletools = fetchurl {
+ url = "https://www.cse.iitd.ac.in/~cs5070217/csl718/simpletools-2v0.tgz";
+ sha256 = "sha256-FTDTqyQWZCnuNPmTcu3Hcjgp4pHNoUcC0GOGhSJV9Iw=";
+ };
+
+ gcc-ss = fetchurl {
+ url = "https://www.cse.iitd.ac.in/~cs5070217/csl718/gcc-${gcc-version}.ss.tar.gz";
+ sha256 = "sha256-3R3wsLmxoN3MkEW4gaxnhIyTBs0CUiSiH7C1/hF2atM=";
+ };
+
+ ar-and-ranlib = fetchurl {
+ url = "https://www.cse.iitd.ac.in/~cs5070217/csl718/ar_and_ranlib.tar.gz";
+ sha256 = "sha256-MRTO6cAg3WeXlk3jDy2lVuiSXDRz1+LLa2XDkBDygMU=";
+ };
+ in ''
+ tar xf ${simpletools}
+ rm -r gcc-2.6.3
+
+ tar xf ${gcc-ss}
+
+ mkdir ar-and-ranlib
+ tar xf ${ar-and-ranlib} -C ar-and-ranlib
+
+ chmod -R +w gcc-${gcc-version} ar-and-ranlib
+ '';
+
+ patches = [
+ ./0001-fix-case-of-YY_CURRENT_BUFFER.patch
+ ./0002-define-sys_nerr.patch
+ ./0003-fix-obstack.h-post-increment.patch
+ ./0004-stdarg.h-instead-of-varargs.h.patch
+ ];
+
+ postPatch = ''
+ patchelf \
+ --set-interpreter "$(<${stdenv_32bit.cc}/nix-support/dynamic-linker-m32)" \
+ ar-and-ranlib/{ar,ranlib}
+ '';
+
+ configurePhase = ''
+ BUILD=$PWD
+
+ cd $BUILD/simpleutils-990811
+ ./configure --host=${host} --target=${target} --with-gnu-as --with-gnu-ld --prefix=$out
+
+ cd $BUILD/gcc-${gcc-version}
+ ./configure --host=${host} --target=${target} --with-gnu-as --with-gnu-ld --prefix=$out
+ '';
+
+ buildPhase = ''
+ make -C $BUILD/simpleutils-990811
+
+ # GCC necesita binutils para compilar
+ make -C $BUILD/simpleutils-990811 install
+ cp $BUILD/ar-and-ranlib/{ar,ranlib} $out/${target}/bin/
+
+ cd $BUILD/gcc-${gcc-version}
+
+ mkdir -p $out/lib
+ cp patched/sys/cdefs.h $BUILD/${target}/include/sys/cdefs.h
+ cp -r $BUILD/${target} $out/
+ cp $BUILD/${target}/lib/{libc.a,crt0.o} $out/lib/
+ sed -i '130s@-I/usr/include@-I./include@' Makefile
+
+ ! make ${makeflags}
+ sed -i 's/\(return "FIXME\\n\)/\1\\/g' insn-output.c
+ PATH="$out/${target}/bin:$PATH" make ${makeflags}
+ '';
+
+ installPhase = ''
+ PATH="$out/${target}/bin:$PATH" make -C $BUILD/gcc-${gcc-version} ${makeflags} install
+ '';
+ }
diff --git a/pkgs/simple-scalar/simplesim.nix b/pkgs/simple-scalar/simplesim.nix
new file mode 100644
index 0000000..43bc656
--- /dev/null
+++ b/pkgs/simple-scalar/simplesim.nix
@@ -0,0 +1,52 @@
+{
+ fetchFromGitHub,
+ stdenv,
+ isWattch ? false,
+}:
+stdenv.mkDerivation {
+ pname =
+ if isWattch
+ then "wattchg7"
+ else "SimpleSim";
+ version =
+ if isWattch
+ then "master-2014-03-20"
+ else "2003-10-08"; # !!!
+
+ src =
+ if isWattch
+ then
+ fetchFromGitHub
+ {
+ repo = "wattchg7";
+ owner = "n-sreek";
+
+ rev = "b1c2c1447584b7e850c6dc0743a2209c9d021a39";
+ sha256 = "sha256-JMM2+6dgReSP3MKSC0ZOYt0Pcmef8DRzIkC26e4dk+Y=";
+ }
+ else
+ fetchTarball {
+ name = "simplesim-3.0";
+
+ url = "https://www.cse.iitd.ac.in/~cs5070217/csl718/simplesim-3v0d.tgz";
+ sha256 = "sha256:022rlniimzl30c1874765hl001dxc716vfwm40ij256h1qk2dwgw";
+ };
+
+ configurePhase = ''
+ make config-pisa
+ '';
+
+ installPhase =
+ ''
+ mkdir -p $out/bin
+ ''
+ + (
+ if isWattch
+ then ''
+ cp sim-outorder $out/bin/wattch-outorder
+ ''
+ else ''
+ cp {sim-{outorder,cache,profile,bpred,eio,safe,fast},sysprobe} $out/bin/
+ ''
+ );
+}
diff --git a/pkgs/smartthinq-sensors.nix b/pkgs/smartthinq-sensors.nix
new file mode 100644
index 0000000..864df52
--- /dev/null
+++ b/pkgs/smartthinq-sensors.nix
@@ -0,0 +1,31 @@
+{
+ buildHomeAssistantComponent,
+ callPackage,
+ fetchFromGitHub,
+ charset-normalizer,
+ pycountry,
+ xmltodict,
+}: let
+ version = "0.39.2";
+in
+ buildHomeAssistantComponent {
+ owner = "ollo69";
+ domain = "smartthinq_sensors";
+ inherit version;
+
+ src = fetchFromGitHub {
+ repo = "ha-smartthinq-sensors";
+ owner = "ollo69";
+
+ rev = "v${version}";
+ hash = "sha256-tLq4sqeKmjEDDaowA8ouH/mI7jQfq49kkt/a8+40rhQ=";
+ };
+
+ dontBuild = true;
+
+ propagatedBuildInputs = [
+ charset-normalizer
+ pycountry
+ xmltodict
+ ];
+ }
diff --git a/pkgs/spliit/default.nix b/pkgs/spliit/default.nix
new file mode 100644
index 0000000..5ac56b1
--- /dev/null
+++ b/pkgs/spliit/default.nix
@@ -0,0 +1,64 @@
+{
+ buildNpmPackage,
+ fetchFromGitHub,
+ nodePackages,
+ lib,
+ writeShellScriptBin,
+}:
+buildNpmPackage {
+ pname = "spliit2";
+ version = "master-20250420";
+
+ src = fetchFromGitHub {
+ repo = "spliit";
+ owner = "spliit-app";
+
+ rev = "a11efc79c13298c0d282e47496d132538752405f";
+ hash = "sha256-v4gaPzLzBbbqw/LDYxe1fiyficcrqcGOop23YPiTrdc=";
+ };
+
+ npmDepsHash = "sha256-sd0/7ruNUFxUKTeTwx/v8Vc/G3llkXP6RSDE78h3qVU=";
+ npmRebuildFlags = ["--ignore-scripts"];
+
+ doCheck = false;
+
+ postPatch = ''
+ cp -v .env.example .env
+ '';
+
+ # nixpkgs/pkgs/applications/office/documenso/default.nix (git)-[master] 05:36:05
+ preBuild = ''
+ # somehow for linux, npm is not finding the prisma package with the
+ # packages installed with the lockfile.
+ # This generates a prisma version incompatibility warning and is a kludge
+ # until the upstream package-lock is modified.
+ ${lib.getExe nodePackages.prisma} generate
+ '';
+
+ postInstall = ''
+ install -Dvm755 -t $out/bin ${lib.getExe (writeShellScriptBin "spliit2" ''
+ set -euxo pipefail
+
+ cd @out@/lib/node_modules/spliit2
+
+ export PATH="$PWD/node_modules/.bin:$PATH"
+ export NEXT_TELEMETRY_DISABLED=1
+
+ prisma migrate deploy
+ exec next start
+ '')}
+
+ #kk?
+ #${lib.getExe nodePackages.prisma} migrate deploy
+
+ substituteInPlace $out/bin/spliit2 \
+ --replace @out@ $out
+ '';
+
+ meta = {
+ description = "Free and Open Source Alternative to Splitwise. Share expenses with your friends and family.";
+ homepage = "https://spliit.app";
+ license = lib.licenses.mit;
+ maintainers = with lib.maintainers; [];
+ };
+}
diff --git a/pkgs/st.nix b/pkgs/st.nix
new file mode 100644
index 0000000..11ae230
--- /dev/null
+++ b/pkgs/st.nix
@@ -0,0 +1,476 @@
+{}: ''
+ /* See LICENSE file for copyright and license details. */
+
+ /*
+ * appearance
+ *
+ * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
+ */
+ static char *font = "Hack:size=17:antialias=true:autohint=true";
+ static int borderpx = 0;
+
+ /*
+ * What program is execed by st depends of these precedence rules:
+ * 1: program passed with -e
+ * 2: scroll and/or utmp
+ * 3: SHELL environment variable
+ * 4: value of shell in /etc/passwd
+ * 5: value of shell in config.h
+ */
+ static char *shell = "/bin/sh";
+ char *utmp = NULL;
+ /* scroll program: to enable use a string like "scroll" */
+ char *scroll = NULL;
+ char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
+
+ /* identification sequence returned in DA and DECID */
+ char *vtiden = "\033[?6c";
+
+ /* Kerning / character bounding-box multipliers */
+ static float cwscale = 0.9;
+ static float chscale = 1.0;
+
+ /*
+ * word delimiter string
+ *
+ * More advanced example: L" `'\"()[]{}"
+ */
+ wchar_t *worddelimiters = L" ";
+
+ /* selection timeouts (in milliseconds) */
+ static unsigned int doubleclicktimeout = 300;
+ static unsigned int tripleclicktimeout = 600;
+
+ /* alt screens */
+ int allowaltscreen = 1;
+
+ /* allow certain non-interactive (insecure) window operations such as:
+ setting the clipboard text */
+ int allowwindowops = 0;
+
+ /*
+ * draw latency range in ms - from new content/keypress/etc until drawing.
+ * within this range, st draws when content stops arriving (idle). mostly it's
+ * near minlatency, but it waits longer for slow updates to avoid partial draw.
+ * low minlatency will tear/flicker more, as it can "detect" idle too early.
+ */
+ static double minlatency = 8;
+ static double maxlatency = 33;
+
+ /*
+ * blinking timeout (set to 0 to disable blinking) for the terminal blinking
+ * attribute.
+ */
+ static unsigned int blinktimeout = 800;
+
+ /*
+ * thickness of underline and bar cursors
+ */
+ static unsigned int cursorthickness = 2;
+
+ /*
+ * bell volume. It must be a value between -100 and 100. Use 0 for disabling
+ * it
+ */
+ static int bellvolume = 0;
+
+ /* default TERM value */
+ char *termname = "st-256color";
+
+ /*
+ * spaces per tab
+ *
+ * When you are changing this value, don't forget to adapt the »it« value in
+ * the st.info and appropriately install the st.info in the environment where
+ * you use this st version.
+ *
+ * it#$tabspaces,
+ *
+ * Secondly make sure your kernel is not expanding tabs. When running `stty
+ * -a` »tab0« should appear. You can tell the terminal to not expand tabs by
+ * running following command:
+ *
+ * stty tabs
+ */
+ unsigned int tabspaces = 8;
+
+ /* Terminal colors (16 first used in escape sequence) */
+ static const char *colorname[] = {
+ /* 8 normal colors */
+ "#000000",
+ "#cc6666",
+ "#b5bd68",
+ "#f0c674",
+ "#81a2be",
+ "#b294bb",
+ "#8abeb7",
+ "#ffffff",
+
+ /* 8 bright colors */
+ "gray50",
+ "#d54e53",
+ "#b9ca4a",
+ "#e7c547",
+ "#7aa6da",
+ "#c397d8",
+ "#70c0b1",
+ "#ffffff",
+
+ [255] = 0,
+
+ /* more colors can be added after 255 to use with DefaultXX */
+ "#cccccc",
+ "#555555",
+ "#ffffff", /* default foreground colour */
+ "#000000", /* default background colour */
+ };
+
+
+ /*
+ * Default colors (colorname index)
+ * foreground, background, cursor, reverse cursor
+ */
+ unsigned int defaultfg = 258;
+ unsigned int defaultbg = 259;
+ unsigned int defaultcs = 256;
+ static unsigned int defaultrcs = 257;
+
+ /*
+ * Default shape of cursor
+ * 2: Block ("█")
+ * 4: Underline ("_")
+ * 6: Bar ("|")
+ * 7: Snowman ("☃")
+ */
+ static unsigned int cursorshape = 2;
+
+ /*
+ * Default columns and rows numbers
+ */
+
+ static unsigned int cols = 80;
+ static unsigned int rows = 24;
+
+ /*
+ * Default colour and shape of the mouse cursor
+ */
+ static unsigned int mouseshape = XC_xterm;
+ static unsigned int mousefg = 7;
+ static unsigned int mousebg = 0;
+
+ /*
+ * Color used to display font attributes when fontconfig selected a font which
+ * doesn't match the ones requested.
+ */
+ static unsigned int defaultattr = 11;
+
+ /*
+ * Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
+ * Note that if you want to use ShiftMask with selmasks, set this to an other
+ * modifier, set to 0 to not use it.
+ */
+ static uint forcemousemod = ShiftMask;
+
+ /*
+ * Internal mouse shortcuts.
+ * Beware that overloading Button1 will disable the selection.
+ */
+ static MouseShortcut mshortcuts[] = {
+ /* mask button function argument release */
+ { XK_ANY_MOD, Button2, clippaste, {.i = 0}, 1 },
+ { ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
+ { XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
+ { ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
+ { XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
+ };
+
+ /* Internal keyboard shortcuts. */
+ #define MODKEY Mod1Mask
+ #define TERMMOD (ControlMask|ShiftMask)
+
+ static Shortcut shortcuts[] = {
+ /* mask keysym function argument */
+ { XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
+ { ControlMask, XK_Print, toggleprinter, {.i = 0} },
+ { ShiftMask, XK_Print, printscreen, {.i = 0} },
+ { XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
+ { TERMMOD, XK_Prior, zoom, {.f = +1} },
+ { TERMMOD, XK_Next, zoom, {.f = -1} },
+ { TERMMOD, XK_Home, zoomreset, {.f = 0} },
+ { TERMMOD, XK_C, clipcopy, {.i = 0} },
+ { TERMMOD, XK_V, clippaste, {.i = 0} },
+ { TERMMOD, XK_Y, clippaste, {.i = 0} },
+ { ShiftMask, XK_Insert, clippaste, {.i = 0} },
+ { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
+ };
+
+ /*
+ * Special keys (change & recompile st.info accordingly)
+ *
+ * Mask value:
+ * * Use XK_ANY_MOD to match the key no matter modifiers state
+ * * Use XK_NO_MOD to match the key alone (no modifiers)
+ * appkey value:
+ * * 0: no value
+ * * > 0: keypad application mode enabled
+ * * = 2: term.numlock = 1
+ * * < 0: keypad application mode disabled
+ * appcursor value:
+ * * 0: no value
+ * * > 0: cursor application mode enabled
+ * * < 0: cursor application mode disabled
+ *
+ * Be careful with the order of the definitions because st searches in
+ * this table sequentially, so any XK_ANY_MOD must be in the last
+ * position for a key.
+ */
+
+ /*
+ * If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
+ * to be mapped below, add them to this array.
+ */
+ static KeySym mappedkeys[] = { -1 };
+
+ /*
+ * State bits to ignore when matching key or button events. By default,
+ * numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
+ */
+ static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
+
+ /*
+ * This is the huge key array which defines all compatibility to the Linux
+ * world. Please decide about changes wisely.
+ */
+ static Key key[] = {
+ /* keysym mask string appkey appcursor */
+ { XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
+ { XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
+ { XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
+ { XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
+ { XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
+ { XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
+ { XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
+ { XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
+ { XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
+ { XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
+ { XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
+ { XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
+ { XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
+ { XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
+ { XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
+ { XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
+ { XK_KP_End, ControlMask, "\033[J", -1, 0},
+ { XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_KP_End, ShiftMask, "\033[K", -1, 0},
+ { XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
+ { XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
+ { XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
+ { XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
+ { XK_KP_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ { XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+ { XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
+ { XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
+ { XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
+ { XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
+ { XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
+ { XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
+ { XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
+ { XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
+ { XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
+ { XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
+ { XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
+ { XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
+ { XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
+ { XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
+ { XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
+ { XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
+ { XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
+ { XK_Up, ShiftMask, "\033[1;2A", 0, 0},
+ { XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
+ { XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
+ { XK_Up, ControlMask, "\033[1;5A", 0, 0},
+ { XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
+ { XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
+ { XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
+ { XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
+ { XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
+ { XK_Down, ShiftMask, "\033[1;2B", 0, 0},
+ { XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
+ { XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
+ { XK_Down, ControlMask, "\033[1;5B", 0, 0},
+ { XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
+ { XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
+ { XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
+ { XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
+ { XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
+ { XK_Left, ShiftMask, "\033[1;2D", 0, 0},
+ { XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
+ { XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
+ { XK_Left, ControlMask, "\033[1;5D", 0, 0},
+ { XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
+ { XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
+ { XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
+ { XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
+ { XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
+ { XK_Right, ShiftMask, "\033[1;2C", 0, 0},
+ { XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
+ { XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
+ { XK_Right, ControlMask, "\033[1;5C", 0, 0},
+ { XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
+ { XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
+ { XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
+ { XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
+ { XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
+ { XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
+ { XK_Return, Mod1Mask, "\033\r", 0, 0},
+ { XK_Return, XK_ANY_MOD, "\r", 0, 0},
+ { XK_Insert, ShiftMask, "\033[4l", -1, 0},
+ { XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
+ { XK_Insert, ControlMask, "\033[L", -1, 0},
+ { XK_Insert, ControlMask, "\033[2;5~", +1, 0},
+ { XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
+ { XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
+ { XK_Delete, ControlMask, "\033[M", -1, 0},
+ { XK_Delete, ControlMask, "\033[3;5~", +1, 0},
+ { XK_Delete, ShiftMask, "\033[2K", -1, 0},
+ { XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
+ { XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
+ { XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
+ { XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
+ { XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
+ { XK_Home, ShiftMask, "\033[2J", 0, -1},
+ { XK_Home, ShiftMask, "\033[1;2H", 0, +1},
+ { XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
+ { XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
+ { XK_End, ControlMask, "\033[J", -1, 0},
+ { XK_End, ControlMask, "\033[1;5F", +1, 0},
+ { XK_End, ShiftMask, "\033[K", -1, 0},
+ { XK_End, ShiftMask, "\033[1;2F", +1, 0},
+ { XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
+ { XK_Prior, ControlMask, "\033[5;5~", 0, 0},
+ { XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
+ { XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
+ { XK_Next, ControlMask, "\033[6;5~", 0, 0},
+ { XK_Next, ShiftMask, "\033[6;2~", 0, 0},
+ { XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
+ { XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
+ { XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
+ { XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
+ { XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
+ { XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
+ { XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
+ { XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
+ { XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
+ { XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
+ { XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
+ { XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
+ { XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
+ { XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
+ { XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
+ { XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
+ { XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
+ { XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
+ { XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
+ { XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
+ { XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
+ { XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
+ { XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
+ { XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
+ { XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
+ { XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
+ { XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
+ { XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
+ { XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
+ { XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
+ { XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
+ { XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
+ { XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
+ { XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
+ { XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
+ { XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
+ { XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
+ { XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
+ { XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
+ { XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
+ { XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
+ { XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
+ { XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
+ { XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
+ { XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
+ { XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
+ { XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
+ { XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
+ { XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
+ { XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
+ { XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
+ { XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
+ { XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
+ { XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
+ { XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
+ { XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
+ { XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
+ { XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
+ { XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
+ { XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
+ { XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
+ { XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
+ { XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
+ { XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
+ { XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
+ { XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
+ { XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
+ { XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
+ { XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
+ { XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
+ { XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
+ { XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
+ { XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
+ { XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
+ { XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
+ { XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
+ { XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
+ { XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
+ { XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
+ { XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
+ { XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
+ { XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
+ { XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
+ { XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
+ { XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
+ { XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
+ { XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
+ };
+
+ /*
+ * Selection types' masks.
+ * Use the same masks as usual.
+ * Button1Mask is always unset, to make masks match between ButtonPress.
+ * ButtonRelease and MotionNotify.
+ * If no match is found, regular selection is used.
+ */
+ static uint selmasks[] = {
+ [SEL_RECTANGULAR] = Mod1Mask,
+ };
+
+ /*
+ * Printable characters in ASCII, used to estimate the advance width
+ * of single wide characters.
+ */
+ static char ascii_printable[] =
+ " !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~";
+''
diff --git a/pkgs/tmux-lift/Makefile b/pkgs/tmux-lift/Makefile
new file mode 100644
index 0000000..eee4dde
--- /dev/null
+++ b/pkgs/tmux-lift/Makefile
@@ -0,0 +1,6 @@
+CFLAGS+=-O3 -s
+
+all: lift unlift
+
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $<
diff --git a/pkgs/tmux-lift/default.nix b/pkgs/tmux-lift/default.nix
new file mode 100644
index 0000000..3a00f97
--- /dev/null
+++ b/pkgs/tmux-lift/default.nix
@@ -0,0 +1,14 @@
+{stdenv, ...}:
+stdenv.mkDerivation {
+ name = "tmux-lift";
+ version = "1.0.0";
+
+ src = ./.;
+
+ installPhase = ''
+ mkdir -p $out/bin
+ cp lift unlift $out/bin
+ '';
+
+ meta.mainProgram = "lift";
+}
diff --git a/pkgs/tmux-lift/lift.c b/pkgs/tmux-lift/lift.c
new file mode 100644
index 0000000..71d959b
--- /dev/null
+++ b/pkgs/tmux-lift/lift.c
@@ -0,0 +1,139 @@
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+#include "lift.h"
+
+
+#define STAGES 2
+
+
+#define FAIL_PAUSE 0x01
+#define FAIL_EXIT 0x02
+
+
+unsigned failures = 0;
+const char* program_name;
+
+
+void fail
+(
+ const char* source,
+ int mode,
+ const char* format,
+ ...
+)
+{
+ va_list args;
+ va_start( args, format );
+
+ perror( source );
+ if( format != NULL )
+ {
+ fputs( program_name, stderr );
+ fputs( ": ", stderr );
+ vfprintf( stderr, format, args );
+ fputc( '\n', stderr );
+ }
+
+ va_end( args );
+
+ ++failures;
+ if( failures == STAGES || ( mode & FAIL_PAUSE ) )
+ {
+ pause();
+ }
+
+ if( failures == STAGES || ( mode & FAIL_EXIT ) )
+ {
+ exit( EXIT_FAILURE );
+ }
+}
+
+
+void checked_take_foreground()
+{
+ signal( SIGTTOU, SIG_IGN );
+ if( tcsetpgrp( 0, getpgrp() ) < 0 )
+ {
+ fail( "tcsetpgrp()", FAIL_EXIT, NULL );
+ }
+
+ signal( SIGTTOU, SIG_DFL );
+}
+
+
+void checked_exec
+(
+ char *const* command_line
+)
+{
+ execvp( command_line[ 0 ], command_line );
+ fail( "execvp()", FAIL_EXIT, "unable to execute %s", command_line[ 0 ] );
+}
+
+
+int main
+(
+ int argc,
+ char *const argv[]
+)
+{
+ program_name = argv[ 0 ];
+
+ struct passwd* passwd = getpwuid( getuid() );
+ if( passwd == NULL )
+ {
+ fail( "getpwuid()", FAIL_PAUSE | FAIL_EXIT, NULL );
+ }
+
+ pid_t pid = fork();
+ if( pid < 0 )
+ {
+ fail( "fork()", 0, NULL );
+ } else if( pid == 0 )
+ {
+ if( setpgid( 0, 0 ) < 0 )
+ {
+ fail( "setpgid()", FAIL_EXIT, NULL );
+ }
+
+ checked_take_foreground();
+
+ char formatted_pid[ 16 ];
+ snprintf( formatted_pid, sizeof formatted_pid, "%d", getpid() );
+
+ setenv( LIFT_PID_ENV, formatted_pid, 1 );
+ checked_exec( argc > 1 ? &argv[ 1 ] : (char *const[]){ DEFAULT_PATH, NULL } );
+ } else
+ {
+ int status;
+ pid_t res = wait( &status );
+
+ checked_take_foreground();
+ if( res < 0 )
+ {
+ fail( "wait()", FAIL_PAUSE | FAIL_EXIT, NULL );
+ }
+
+ if( WIFEXITED( status ) )
+ {
+ if( status == 0 )
+ {
+ return 0;
+ }
+
+ fprintf( stderr, "Session unlifted by exit code %d\n", WEXITSTATUS( status ) );
+ } else if( WIFSIGNALED( status ) )
+ {
+ fprintf( stderr, "Session unlifted by %s\n", strsignal( WTERMSIG( status ) ) );
+ }
+ }
+
+ checked_exec( (char *const[]){ passwd->pw_shell, NULL } );
+}
diff --git a/pkgs/tmux-lift/lift.h b/pkgs/tmux-lift/lift.h
new file mode 100644
index 0000000..e09d869
--- /dev/null
+++ b/pkgs/tmux-lift/lift.h
@@ -0,0 +1,9 @@
+#ifndef LIFT_H
+#define LIFT_H
+
+
+#define DEFAULT_PATH "tmux"
+#define LIFT_PID_ENV "LIFT_PID"
+
+
+#endif
diff --git a/pkgs/tmux-lift/unlift.c b/pkgs/tmux-lift/unlift.c
new file mode 100644
index 0000000..d8d3a72
--- /dev/null
+++ b/pkgs/tmux-lift/unlift.c
@@ -0,0 +1,41 @@
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+
+#include "lift.h"
+
+
+int main
+(
+ int argc,
+ const char* argv[]
+)
+{
+ char* formatted_pid = getenv( LIFT_PID_ENV );
+ if( formatted_pid == NULL )
+ {
+ fprintf( stderr, "%s: variable " LIFT_PID_ENV " is not set\n", argv[ 0 ] );
+ return EXIT_FAILURE;
+ }
+
+ char* formatted_end;
+ long pid = strtol( formatted_pid, &formatted_end, 10 );
+ if( *formatted_pid == '\0' || *formatted_end != '\0' )
+ {
+ fprintf( stderr, "%s: invalid value for " LIFT_PID_ENV ": %s\n", argv[ 0 ], formatted_pid );
+ return EXIT_FAILURE;
+ }
+
+ if( kill( (pid_t)pid, SIGTERM ) < 0 )
+ {
+ fprintf( stderr, "kill(%ld): %s\n", pid, strerror( errno ) );
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/pkgs/tmux-open/default.nix b/pkgs/tmux-open/default.nix
new file mode 100644
index 0000000..1f882b4
--- /dev/null
+++ b/pkgs/tmux-open/default.nix
@@ -0,0 +1,12 @@
+{
+ jq,
+ substituteAll,
+ sway,
+ tmux,
+ writeShellScriptBin,
+ ...
+}:
+writeShellScriptBin "tmux-open" (builtins.readFile (substituteAll {
+ src = ./tmux-open.sh;
+ env = {inherit jq sway tmux;};
+}))
diff --git a/pkgs/tmux-open/tmux-open.sh b/pkgs/tmux-open/tmux-open.sh
new file mode 100644
index 0000000..c6537b7
--- /dev/null
+++ b/pkgs/tmux-open/tmux-open.sh
@@ -0,0 +1,15 @@
+set -o errexit
+set -o nounset
+set -o pipefail
+
+workspace="$( \
+ @sway@/bin/swaymsg -t get_workspaces \
+ | @jq@/bin/jq '.[] | select(.focused==true).name' \
+ | cut -d"\"" -f2)"
+
+session="ws$workspace"
+if @tmux@/bin/tmux has-session -t "$session" 2>/dev/null && [ -n "$(@tmux@/bin/tmux list-clients -t "$session")" ]; then
+ session="$session-$$"
+fi
+
+exec @tmux@/bin/tmux new-session -A -s "$session" -e "SWAYSOCK=$SWAYSOCK" -e "DISPLAY=$DISPLAY"
diff --git a/pkgs/tmux-pass.nix b/pkgs/tmux-pass.nix
new file mode 100644
index 0000000..0c079c2
--- /dev/null
+++ b/pkgs/tmux-pass.nix
@@ -0,0 +1,26 @@
+{
+ fetchFromGitHub,
+ fzf,
+ pass,
+ tmuxPlugins,
+}:
+tmuxPlugins.mkTmuxPlugin {
+ pluginName = "tmux-pass";
+ version = "master";
+
+ src = fetchFromGitHub {
+ repo = "tmux-pass";
+ owner = "rafi";
+
+ rev = "76b1c98911d56928063a41bc93a2d9e81818ef4c";
+ sha256 = "102n4f5zcqijf5ywdahgmj0yhaibv0zgpvdq8wwkm8vbhvhb7abd";
+ };
+
+ rtpFilePath = "plugin.tmux";
+
+ postInstall = ''
+ substituteInPlace $target/scripts/main.sh \
+ --replace 'fzf \' '${fzf}/bin/fzf \' \
+ --replace 'pass ' '${pass}/bin/pass '
+ '';
+}
diff --git a/pkgs/xandikos/default.nix b/pkgs/xandikos/default.nix
new file mode 100644
index 0000000..4c5d7d8
--- /dev/null
+++ b/pkgs/xandikos/default.nix
@@ -0,0 +1,7 @@
+{
+ xandikos,
+ systemd,
+}:
+xandikos.overridePythonAttrs (super: {
+ dependencies = super.dependencies ++ [systemd];
+})
diff --git a/pki/by-path.nix b/pki/by-path.nix
new file mode 100644
index 0000000..ebc46ef
--- /dev/null
+++ b/pki/by-path.nix
@@ -0,0 +1,18 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; {
+ options.local.pki.byPath = mkOption {
+ type = with lib.types; attrsOf unspecified;
+ readOnly = true;
+ };
+
+ config.local.pki.byPath = let
+ caWithLeaves = ca:
+ singleton {"${ca.path}" = ca;}
+ ++ map (leaf: {"${leaf.path}" = leaf;}) (attrValues ca.leaves);
+ in
+ mergeAttrsList (flatten (map caWithLeaves (attrValues config.local.pki.ca)));
+}
diff --git a/pki/ca.nix b/pki/ca.nix
new file mode 100644
index 0000000..f8e5847
--- /dev/null
+++ b/pki/ca.nix
@@ -0,0 +1,129 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.pki.ca;
+
+ openssl = getExe pkgs.buildPackages.openssl;
+
+ certsType = leafOf:
+ with lib.types;
+ attrsOf (submodule ({
+ config,
+ name,
+ ...
+ }: {
+ options =
+ {
+ cert = mkOption {
+ type = path;
+ readOnly = true;
+ };
+
+ fingerprint = {
+ sha1-lower = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ sha256-bytes-upper = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ };
+
+ fullchain = mkOption {
+ type = path;
+ readOnly = true;
+ };
+
+ issuer = mkOption {
+ type = nullOr str;
+ readOnly = true;
+ };
+
+ path = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ }
+ // optionalAttrs (leafOf != null) {
+ commonName = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ }
+ // optionalAttrs (leafOf == null) {
+ crl = mkOption {
+ type = path;
+ readOnly = true;
+ };
+
+ certWithCrl = mkOption {
+ type = path;
+ readOnly = true;
+ };
+
+ leaves = mkOption {
+ type = certsType name;
+ readOnly = true;
+ };
+ };
+
+ config =
+ {
+ fingerprint = {
+ sha1-lower = readFile (pkgs.runCommandNoCCLocal "cert-${config.path}-fprint-sha1-lower" {} ''
+ ${openssl} x509 -in ${config.cert} -noout -sha1 -fingerprint \
+ | sed 's/^.*=//' \
+ | tr -d $':\n' \
+ | tr '[A-Z]' '[a-z]' \
+ >>$out
+ '');
+
+ sha256-bytes-upper = readFile (pkgs.runCommandNoCCLocal "cert-${config.path}-fprint-sha256-bytes-upper" {} ''
+ ${openssl} x509 -in ${config.cert} -noout -sha256 -fingerprint \
+ | sed 's/^.*=//' \
+ | tr -d $'\n' \
+ >>$out
+ '');
+ };
+
+ fullchain =
+ pkgs.writeText "${name}-fullchain-crl.pem"
+ (concatStrings (map readFile
+ (singleton (
+ if leafOf != null
+ then config.cert
+ else config.certWithCrl
+ )
+ ++ optional (config.issuer != null) cfg.${config.issuer}.fullchain)));
+
+ path = optionalString (config.issuer != null) (cfg.${config.issuer}.path + ".") + name;
+ }
+ // optionalAttrs (leafOf != null) {
+ commonName = readFile (pkgs.runCommandNoCCLocal "cert-${config.path}-common-name" {} ''
+ ${openssl} x509 -in ${config.cert} -noout -subject -nameopt multiline \
+ | grep commonName \
+ | sed 's/^.*=\s*//' \
+ | tr -d $'\n' \
+ >$out
+ '');
+
+ issuer = leafOf;
+ }
+ // optionalAttrs (leafOf == null) {
+ certWithCrl =
+ pkgs.writeText "${name}-cert-crl.pem"
+ (concatStrings (map readFile [config.cert config.crl]));
+ };
+ }));
+in {
+ options.local.pki.ca = mkOption {
+ type = certsType null;
+ readOnly = true;
+ };
+}
diff --git a/pki/certs.nix b/pki/certs.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/pki/certs.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/pki/default.nix b/pki/default.nix
new file mode 100644
index 0000000..30519af
--- /dev/null
+++ b/pki/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./ca.nix
+ ./certs.nix
+ ./by-path.nix
+ ];
+}
diff --git a/pki/public/README.md b/pki/public/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/pki/public/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/auth/default.nix b/sys/auth/default.nix
new file mode 100644
index 0000000..ca2778a
--- /dev/null
+++ b/sys/auth/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./login.nix
+ ./oath.nix
+ ./openssh.nix
+ ];
+}
diff --git a/sys/auth/login.nix b/sys/auth/login.nix
new file mode 100644
index 0000000..f252c1c
--- /dev/null
+++ b/sys/auth/login.nix
@@ -0,0 +1,22 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; {
+ # TODO
+ config = mkIf true {
+ security.pam = {
+ # TODO: altamente inseguro, ver problema con ~/.ssh/authorized_keys
+ # si es editado por un proceso malicioso
+ rssh = {
+ enable = true;
+
+ settings = {
+ cue = true;
+ };
+ };
+ };
+ };
+}
diff --git a/sys/auth/oath.nix b/sys/auth/oath.nix
new file mode 100644
index 0000000..6b00680
--- /dev/null
+++ b/sys/auth/oath.nix
@@ -0,0 +1,38 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.auth.oath;
+in {
+ options.local.auth.oath = {
+ enable = lib.mkEnableOption "pam-oath";
+ };
+
+ config = lib.mkIf cfg.enable {
+ security.pam = {
+ oath = {
+ digits = 6;
+ window = 30;
+
+ usersFile = "/var/trust/auth/users.oath";
+ };
+
+ services.sshd.oathAuth = true;
+ };
+
+ users.users.tunnel = {
+ uid = 1100;
+ group = "nogroup";
+ isSystemUser = true;
+
+ # Requiere oath
+ password = "tunnel";
+
+ home = "/var/empty";
+ shell = "${pkgs.coreutils}/bin/true";
+ };
+ };
+}
diff --git a/sys/auth/openssh.nix b/sys/auth/openssh.nix
new file mode 100644
index 0000000..44fb49a
--- /dev/null
+++ b/sys/auth/openssh.nix
@@ -0,0 +1,193 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.auth.openssh;
+ withOath = config.local.auth.oath.enable;
+ withPassword = config.local.auth.openssh.passwordAuthentication;
+
+ port =
+ if cfg.shiftPortNumber
+ then 2234
+ else 22;
+ restrict = cfg.restrictListen;
+
+ exemptList = optionals config.local.net.fail2ban.enable config.services.fail2ban.ignoreIP;
+in {
+ options.local.auth.openssh = {
+ enable = mkEnableOption "openssh";
+ tunnel.enable = mkEnableOption "ssh tunnel user";
+
+ #TODO: Desfasar ecdsa, inseguro
+ hostKeys = listToAttrs (map
+ (name: {
+ inherit name;
+
+ value = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ }) ["ecdsa" "ed25519" "rsa"]);
+
+ restrictListen = mkOption {
+ default = null;
+
+ type = with types;
+ nullOr (submodule {
+ options = {
+ addresses = mkOption {
+ type = listOf str;
+ };
+
+ interface = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ vsockCid = mkOption {
+ type = nullOr ints.u32;
+ default = null;
+ };
+ };
+ });
+ };
+
+ passwordAuthentication = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ shiftPortNumber = mkOption {
+ type = types.bool;
+ default = true;
+ };
+
+ withDeployKeys = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = cfg.tunnel.enable -> withOath;
+ message = "SSH tunnel requires oath";
+ }
+ {
+ assertion = restrict != null -> (restrict.vsockCid != null -> (restrict.interface == null && restrict.addresses == []));
+ message = "SSH vsock restrict requires disabling inet";
+ }
+ {
+ assertion = restrict != null -> (restrict.vsockCid != null -> config.services.openssh.startWhenNeeded);
+ message = "SSH vsock restrict requires socket activation";
+ }
+ {
+ assertion = restrict != null -> (restrict.vsockCid != null -> config.local.virt.enable);
+ message = "SSH vsock restrict requires nixvirt";
+ }
+ {
+ assertion = any (key: key) (attrValues cfg.hostKeys);
+ message = "No OpenSSH host keys were enabled";
+ }
+ ];
+
+ local.boot.impermanence.files =
+ flatten (map (key: [key.path "${key.path}.pub"]) config.services.openssh.hostKeys);
+
+ networking.firewall = {
+ interfaces = optionalAttrs (restrict != null && restrict.interface != null) {
+ ${restrict.interface}.allowedTCPPorts = [port];
+ };
+
+ allowedTCPPorts = optional (restrict == null || restrict.interface == null) port;
+ };
+
+ services.openssh = {
+ enable = true;
+
+ ports = optional (restrict != null -> restrict.addresses != []) port;
+ startWhenNeeded = mkDefault (!config.services.fail2ban.enable);
+
+ extraConfig =
+ optionalString (exemptList != []) ''
+ PerSourcePenaltyExemptList ${concatStringsSep "," exemptList}
+ ''
+ + optionalString cfg.tunnel.enable ''
+ # User 'tunnel' has no password. Use PAM OATH
+ # and connect with -N, forward with -R.
+ Match User tunnel
+ AllowTcpForwarding remote
+ AllowStreamLocalForwarding no
+ X11Forwarding no
+ PermitTunnel no
+ GatewayPorts no
+ AllowAgentForwarding no
+ PermitOpen none
+ PermitListen 60220 60221 60222 60223 60224 60225 60226 60227 60228 60229
+
+ Banner ${pkgs.writeText "tunnel-banner" ''
+ This is a reverse tunnel
+ ''}
+ '';
+
+ hostKeys =
+ map
+ (name:
+ {
+ path = "/etc/ssh/ssh_host_${name}_key";
+ type = name;
+ }
+ // optionalAttrs (name == "rsa") {
+ bits = 4096;
+ })
+ (attrNames (filterAttrs (name: enable: enable) cfg.hostKeys));
+
+ settings = {
+ X11Forwarding = config.local.seat.enable && config.local.seat.graphical;
+ PermitRootLogin = "prohibit-password";
+ PasswordAuthentication = withOath || withPassword; # Necesario para oath, no reemplaza a oath
+ };
+
+ listenAddresses =
+ mkIf (restrict != null)
+ (map (addr: {inherit addr;}) restrict.addresses);
+ };
+
+ systemd.sockets = mkIf (restrict != null && restrict.vsockCid != null) {
+ sshd = let
+ kernelMod = "modprobe@${
+ if restrict.vsockCid == 2
+ then "vhost_"
+ else ""
+ }vsock.service";
+ in {
+ after = [kernelMod];
+ wants = [kernelMod];
+
+ socketConfig.ListenStream = mkForce ["vsock:${toString restrict.vsockCid}:${toString port}"];
+ };
+ };
+
+ users.users = {
+ root = mkIf cfg.withDeployKeys {
+ openssh.authorizedKeys.keyFiles = [./ssh-key.pub];
+ };
+
+ tunnel = mkIf cfg.tunnel.enable {
+ uid = 1100;
+ group = "nogroup";
+ isSystemUser = true;
+
+ # Requiere oath
+ password = "tunnel";
+
+ home = "/var/empty";
+ shell = "${pkgs.coreutils}/bin/true";
+ };
+ };
+ };
+}
diff --git a/sys/auth/ssh-key.pub b/sys/auth/ssh-key.pub
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/auth/ssh-key.pub
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/baseline/default.nix b/sys/baseline/default.nix
new file mode 100644
index 0000000..96654d8
--- /dev/null
+++ b/sys/baseline/default.nix
@@ -0,0 +1,95 @@
+{
+ config,
+ flakes,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; {
+ config = {
+ # This value determines the NixOS release from which the default
+ # settings for stateful data, like file locations and database versions
+ # on your system were taken. It‘s perfectly fine and recommended to leave
+ # this value at the release version of the first install of this system.
+ # Before changing this value read the documentation for this option
+ # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
+ system.stateVersion = "21.11"; # Did you read the comment?
+
+ environment = {
+ pathsToLink = ["/share/zsh"];
+
+ systemPackages = with pkgs;
+ [
+ git
+ ]
+ ++ optionals (!config.boot.isContainer) [
+ lm_sensors
+ lshw
+ parted
+ pciutils
+ smartmontools
+ usbutils
+ ];
+ };
+
+ home-manager = {
+ useGlobalPkgs = true;
+ useUserPackages = true;
+
+ extraSpecialArgs = {inherit flakes;};
+ };
+
+ lib.local = pkgs.local.lib;
+
+ local.boot.impermanence.directories = ["/var/lib/dhparams"];
+
+ nix = {
+ package = pkgs.nix;
+
+ channel.enable = false;
+
+ extraOptions = ''
+ experimental-features = nix-command flakes
+ '';
+
+ gc = {
+ dates = "Sat *-*-* 00:00:00";
+ automatic = true;
+ };
+
+ # No me interesa el global registry
+ settings.flake-registry = "";
+ };
+
+ programs = {
+ fuse.userAllowOther = true;
+ zsh.enable = true;
+ };
+
+ security.dhparams = {
+ enable = true;
+ defaultBitSize = 4096;
+ };
+
+ services = {
+ earlyoom = {
+ enable = mkDefault true;
+ enableNotifications = true;
+ };
+
+ journald.extraConfig = ''
+ ForwardToKMsg=no
+ ForwardToWall=no
+ ForwardToConsole=no
+ '';
+ };
+
+ # Coredumps son un riesgo de seguridad y puden usar mucho disco
+ systemd.coredump.extraConfig = ''
+ Storage=none
+ ProcessSizeMax=0
+ '';
+
+ time.timeZone = mkDefault "America/Costa_Rica";
+ };
+}
diff --git a/sys/boot/chain.nix b/sys/boot/chain.nix
new file mode 100644
index 0000000..43edcb4
--- /dev/null
+++ b/sys/boot/chain.nix
@@ -0,0 +1,41 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot;
+in {
+ options.local.boot = {
+ loader = mkOption {
+ type = types.enum ["none" "grub" "systemd-boot"];
+ };
+
+ kernel = mkOption {
+ type = types.raw;
+ };
+ };
+
+ config = mkIf (cfg.loader != "none") {
+ boot = {
+ kernelPackages = cfg.kernel;
+
+ loader =
+ if cfg.loader == "grub"
+ then {
+ grub = {
+ enable = true;
+ device = "nodev";
+ efiSupport = true;
+ };
+ }
+ else {
+ systemd-boot = {
+ enable = true;
+ editor = true;
+ };
+ };
+ };
+ };
+}
diff --git a/sys/boot/default.nix b/sys/boot/default.nix
new file mode 100644
index 0000000..4580cba
--- /dev/null
+++ b/sys/boot/default.nix
@@ -0,0 +1,14 @@
+{
+ imports = [
+ ./chain.nix
+ ./detached-luks.nix
+ ./efi.nix
+ ./firmware.nix
+ ./fscrypt.nix
+ ./impermanence.nix
+ ./namespaced.nix
+ ./secure-boot.nix
+ ./stack
+ ./tpm.nix
+ ];
+}
diff --git a/sys/boot/detached-luks.nix b/sys/boot/detached-luks.nix
new file mode 100644
index 0000000..78ae35c
--- /dev/null
+++ b/sys/boot/detached-luks.nix
@@ -0,0 +1,117 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.detachedLuks;
+
+ bootFs = config.fileSystems."/boot";
+ tpmInitrd = config.local.boot.tpm.initrd.enable;
+
+ pcrList = concatStringsSep "," (map toString config.local.boot.tpm.initrd.pcrs);
+in {
+ options.local.boot.detachedLuks = {
+ enable = mkEnableOption "detached LUKS header in initrd";
+
+ headerFromBoot = mkOption {
+ type = types.str;
+ };
+
+ tpmStorageFromBoot = mkOption {
+ type = types.str;
+ default = "tpm-boot";
+ };
+
+ crypt = mkOption {
+ type = types.str;
+ };
+
+ target = mkOption {
+ type = types.str;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ boot.initrd = let
+ headerPath = "/initrd-boot/${cfg.headerFromBoot}";
+ headerPathEscaped = escapeShellArg headerPath;
+
+ tpmPath = escapeShellArg "/initrd-boot/${cfg.tpmStorageFromBoot}";
+ hardwareKeyPath = "/tpm/unsealed.luks-key";
+ in {
+ preDeviceCommands = ''
+ mkdir -p `dirname ${headerPathEscaped}`
+ touch ${headerPathEscaped}
+ '';
+
+ postDeviceCommands = mkIf (!config.boot.initrd.systemd.enable) ''
+ # Set the system time from the hardware clock to work around a
+ # bug in qemu-kvm > 1.5.2 (where the VM clock is initialised
+ # to the *boot time* of the host).
+ hwclock -s
+ '';
+
+ #FIXME: Demasiado vulgar
+ preLVMCommands = optionalString (config.local.boot.efi.enable && config.local.boot.efi.removable) ''
+ sleep 2
+ '';
+
+ luks.devices.${cfg.target} = {
+ device = cfg.crypt;
+ header = headerPath;
+ preLVM = false;
+
+ keyFile = mkIf tpmInitrd hardwareKeyPath;
+ fallbackToPassword = tpmInitrd;
+
+ preOpenCommands =
+ ''
+ mount -o ro -t ${bootFs.fsType} ${bootFs.device} /initrd-boot
+ ''
+ + optionalString tpmInitrd ''
+ mkdir /tpm
+ touch ${escapeShellArg hardwareKeyPath}
+
+ unseal_tpm_key() {
+ tpm2 createprimary -Q -C owner -g sha256 -G ecc -c /tpm/prim.ctx || return
+
+ tpm2 loadexternal -Q -C owner -G rsa -u ${tpmPath}/signing-key.pub -c /tpm/signing-key.ctx -n /tpm/signing-key.name || return
+ tpm2 verifysignature -Q -c /tpm/signing-key.ctx -g sha256 -m ${tpmPath}/auth.policy -s ${tpmPath}/auth.sig -t /tpm/verified.ticket -f rsassa || return
+
+ tpm2 startauthsession -Q -S /tpm/session.ctx --policy-session || return
+
+ tpm_resets=`tpm2 readclock | grep reset_count | sed 's/.*: //g'`
+ tpm2 policycountertimer -Q -S /tpm/session.ctx resets="$tpm_resets" || return
+ tpm2 policypcr -Q -S /tpm/session.ctx -l sha256:${pcrList} || return
+ tpm2 policyauthorize -Q -S /tpm/session.ctx -i ${tpmPath}/auth.policy -n /tpm/signing-key.name -t /tpm/verified.ticket || return
+
+ tpm2 load -Q -C /tpm/prim.ctx -u ${tpmPath}/key.pub -r ${tpmPath}/key.priv -c /tpm/key.ctx || return
+ tpm2 unseal -Q -c /tpm/key.ctx -p session:/tpm/session.ctx -o ${escapeShellArg hardwareKeyPath} || return
+
+ tpm2 flushcontext /tpm/session.ctx
+ }
+
+ unseal_tpm_key
+ '';
+
+ postOpenCommands = mkBefore (''
+ umount /initrd-boot
+ ''
+ + optionalString tpmInitrd ''
+ rm -r /tpm
+ '');
+ };
+ };
+
+ local.boot = {
+ stack = {
+ btrfsToplevelMultidrive.toplevel.device = "/dev/mapper/${cfg.target}";
+ luksExt4FscryptImpermanence = {inherit (cfg) target;};
+ };
+
+ tpm.initrd.enable = mkDefault config.local.boot.tpm.enable;
+ };
+ };
+}
diff --git a/sys/boot/efi.nix b/sys/boot/efi.nix
new file mode 100644
index 0000000..71c42c8
--- /dev/null
+++ b/sys/boot/efi.nix
@@ -0,0 +1,49 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.efi;
+in {
+ options.local.boot.efi = {
+ enable = mkEnableOption "EFI with FAT32 system partition";
+
+ esp = {
+ mountpoint = mkOption {
+ type = types.enum ["/boot" "/boot/efi"];
+ default = "/boot";
+ };
+
+ uuid = mkOption {
+ type = types.strMatching "[0-9A-F]{4}-[0-9A-F]{4}";
+ };
+ };
+
+ removable = mkOption {
+ type = types.bool;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ boot = {
+ initrd.supportedFilesystems = ["vfat"];
+
+ loader = {
+ efi = {
+ efiSysMountPoint = cfg.esp.mountpoint;
+ canTouchEfiVariables = !cfg.removable;
+ };
+
+ grub.efiInstallAsRemovable = cfg.removable;
+ };
+ };
+
+ fileSystems.${cfg.esp.mountpoint} = {
+ device = "/dev/disk/by-uuid/${cfg.esp.uuid}";
+ fsType = "vfat";
+ options = ["noatime" "umask=027" "sync"];
+ neededForBoot = true;
+ };
+ };
+}
diff --git a/sys/boot/firmware.nix b/sys/boot/firmware.nix
new file mode 100644
index 0000000..b3598a7
--- /dev/null
+++ b/sys/boot/firmware.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.firmware;
+in {
+ options.local.boot.firmware = {
+ mode = mkOption {
+ type = types.enum ["none" "redistributable" "all"];
+ };
+
+ cpuVendor = mkOption {
+ type = types.enum ["amd" "intel"];
+ };
+ };
+
+ config = mkIf (cfg.mode != "none") {
+ hardware = {
+ cpu = {
+ amd.updateMicrocode = cfg.cpuVendor == "amd";
+ intel.updateMicrocode = cfg.cpuVendor == "intel";
+ };
+
+ enableAllFirmware = cfg.mode == "all";
+ enableRedistributableFirmware = true;
+ };
+
+ services.fwupd.enable = true;
+ };
+}
diff --git a/sys/boot/fscrypt.nix b/sys/boot/fscrypt.nix
new file mode 100644
index 0000000..459e02b
--- /dev/null
+++ b/sys/boot/fscrypt.nix
@@ -0,0 +1,30 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.fscrypt;
+in {
+ options.local.boot.fscrypt = {
+ enable = mkEnableOption "fscrypt support";
+ };
+
+ config = mkIf cfg.enable {
+ environment.systemPackages = [pkgs.fscrypt-experimental];
+
+ local.boot.impermanence = {
+ directories = [
+ {
+ directory = "/.fscrypt";
+ mode = "u=rwx,g=rx,o=rx";
+ }
+ ];
+
+ files = [
+ "/etc/fscrypt.conf"
+ ];
+ };
+ };
+}
diff --git a/sys/boot/impermanence.nix b/sys/boot/impermanence.nix
new file mode 100644
index 0000000..632094b
--- /dev/null
+++ b/sys/boot/impermanence.nix
@@ -0,0 +1,56 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.impermanence;
+in {
+ options.local.boot.impermanence = {
+ enable = mkEnableOption "root fs impermanence";
+
+ #TODO: type correcto de files, directories?
+
+ directories = mkOption {
+ type = with lib.types; listOf (either str attrs);
+ default = [];
+ };
+
+ files = mkOption {
+ type = with lib.types; listOf (either str attrs);
+ default = [];
+ };
+ };
+
+ config = mkMerge [
+ {
+ local.boot.impermanence = {
+ directories = [
+ "/etc/lvm"
+ "/var/lib/nixos"
+ "/var/log"
+ ];
+
+ files = [
+ "/etc/machine-id"
+ "/var/lib/logrotate.status"
+ ];
+ };
+ }
+ (mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = (config.fileSystems ? "/persist") && config.fileSystems."/persist".neededForBoot;
+ message = "Impermanence requires /persist to be a neededForBoot mountpoint";
+ }
+ ];
+
+ environment.persistence."/persist" = {
+ hideMounts = true;
+
+ files = cfg.files;
+ directories = cfg.directories;
+ };
+ })
+ ];
+}
diff --git a/sys/boot/namespaced.nix b/sys/boot/namespaced.nix
new file mode 100644
index 0000000..3f95960
--- /dev/null
+++ b/sys/boot/namespaced.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ options,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.namespaced;
+in {
+ options.local.boot.namespaced = {
+ enable = mkEnableOption "system containerization";
+ };
+
+ config = mkIf cfg.enable {
+ boot.isContainer = true;
+
+ local.boot = mkMerge ([
+ {
+ loader = mkForce "none";
+
+ efi.enable = mkForce false;
+ firmware.mode = mkForce "none";
+ secureBoot.enable = mkForce false;
+ impermanence.enable = mkForce false;
+ }
+ ]
+ ++ map
+ (name: {
+ stack.${name}.enable = mkForce false;
+ })
+ (attrNames options.local.boot.stack));
+ };
+}
diff --git a/sys/boot/secure-boot.nix b/sys/boot/secure-boot.nix
new file mode 100644
index 0000000..b13ab7c
--- /dev/null
+++ b/sys/boot/secure-boot.nix
@@ -0,0 +1,51 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.secureBoot;
+
+ pkiBundle =
+ if cfg.legacyPath
+ then "/etc/secureboot"
+ else "/var/lib/sbctl";
+in {
+ options.local.boot.secureBoot = {
+ enable = mkEnableOption "secure boot";
+
+ legacyPath = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.boot.efi.enable;
+ message = "secure boot requires EFI";
+ }
+ {
+ assertion = config.local.boot.loader == "systemd-boot";
+ message = "lanzaboote requires systemd-boot";
+ }
+ ];
+
+ boot = {
+ loader.systemd-boot.enable = mkForce false;
+
+ lanzaboote = {
+ enable = true;
+ inherit pkiBundle;
+ };
+ };
+
+ environment.systemPackages = [
+ pkgs.sbctl
+ ];
+
+ local.boot.impermanence.directories = [pkiBundle];
+ };
+}
diff --git a/sys/boot/stack/btrfs-toplevel-multidrive.nix b/sys/boot/stack/btrfs-toplevel-multidrive.nix
new file mode 100644
index 0000000..52db865
--- /dev/null
+++ b/sys/boot/stack/btrfs-toplevel-multidrive.nix
@@ -0,0 +1,99 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.stack.btrfsToplevelMultidrive;
+in {
+ options.local.boot.stack.btrfsToplevelMultidrive = {
+ enable = mkEnableOption "filesystem stack: persistent btrfs toplevel with optional hdd drive";
+
+ toplevel = {
+ device = mkOption {
+ type = types.str;
+ };
+
+ ssd = mkOption {
+ type = types.bool;
+ };
+
+ snapshot = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ root = mkOption {
+ type = types.str;
+ };
+
+ pivot = mkOption {
+ type = types.str;
+ default = "/";
+ };
+ };
+
+ secondary = {
+ device = mkOption {
+ type = types.str;
+ };
+
+ ssd = mkOption {
+ type = types.bool;
+ };
+
+ snapshot = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ home = mkOption {
+ type = types.str;
+ };
+
+ pivot = mkOption {
+ type = types.str;
+ default = "/";
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ local.btrfs = {
+ mounts = {
+ "/" = {
+ inherit (cfg.toplevel) device ssd;
+ subvol = cfg.toplevel.root;
+ };
+
+ "/toplevel" = {
+ inherit (cfg.toplevel) device ssd;
+ subvol = cfg.toplevel.pivot;
+ };
+
+ #FIXME: Este nombre es legacy
+ "/hdd" = {
+ inherit (cfg.secondary) device ssd;
+ subvol = cfg.secondary.pivot;
+ };
+
+ "/home" = {
+ inherit (cfg.secondary) device ssd;
+ subvol = cfg.secondary.home;
+ };
+ };
+
+ snapper =
+ optionalAttrs cfg.toplevel.snapshot
+ {
+ root = "/";
+ }
+ // optionalAttrs cfg.secondary.snapshot {
+ home = "/home";
+ };
+ };
+
+ # Asegura que /hdd sea descifrado antes de intentar montar /home
+ fileSystems."/home".depends = ["/hdd"];
+ };
+}
diff --git a/sys/boot/stack/default.nix b/sys/boot/stack/default.nix
new file mode 100644
index 0000000..ff211e6
--- /dev/null
+++ b/sys/boot/stack/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./btrfs-toplevel-multidrive.nix
+ ./luks-ext4-fscrypt-impermanence.nix
+ ];
+}
diff --git a/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix b/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
new file mode 100644
index 0000000..81feb60
--- /dev/null
+++ b/sys/boot/stack/luks-ext4-fscrypt-impermanence.nix
@@ -0,0 +1,98 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.stack.luksExt4FscryptImpermanence;
+in {
+ options.local.boot.stack.luksExt4FscryptImpermanence = {
+ enable = mkEnableOption "filesystem stack: whatever LUKS approach+ext4+impermanence with per-boot keys";
+
+ target = mkOption {
+ type = types.str;
+ };
+ };
+
+ # - boot device
+ # - some unknown fs, probably vfat
+ # - detached luks header file
+ #
+ # - toplevel device
+ # - headerless luks
+ # - /toplevel (ext4)
+ # - /toplevel/nix
+ # - /toplevel/persist
+ # - /toplevel/boot-archive.pub
+ # - /toplevel/boot-keys
+ # - /toplevel/boot-keys/2000-01-01T00:00:00-06:00.key.crypt (encrypted for /toplevel/boot-archive.pub)
+ # - /toplevel/boot-keys/...
+ # - /toplevel/boot-keys/last.key.crypt -> 2000-01-01T00:00:00-06:00.key.crypt
+ # - /toplevel/boots
+ # - /toplevel/boots/2000-01-01T00:00:00-06:00 (raw protector in last.key.crypt)
+ # - /toplevel/boots/...
+ # - /toplevel/boots/last -> 2000-01-01T00:00:00-06:00 (mounted as /)
+ config = mkIf cfg.enable {
+ boot.initrd.luks.devices.${cfg.target}.postOpenCommands = let
+ fscryptctl = "${pkgs.fscryptctl}/bin/fscryptctl";
+ in ''
+ # FIXME: posiblemente algunos --make-* son innecesarios a partir de aquí
+ mkdir -p /mnt-root /mnt-toplevel
+ mount -o noatime /dev/mapper/${cfg.target} /mnt-toplevel
+ mount --make-private /mnt-toplevel
+
+ boot_stamp="$(date -Is)"
+ root_from_toplevel="/mnt-toplevel/boots/$boot_stamp"
+
+ mkdir -p "$root_from_toplevel" /mnt-toplevel/boot-keys
+ chmod 700 /mnt-toplevel/boot-keys
+
+ head -c64 /dev/urandom >/boot-key
+ key_id=$(${fscryptctl} add_key /mnt-toplevel </boot-key)
+ ${fscryptctl} set_policy "$key_id" "$root_from_toplevel"
+ (umask 077; test -f /mnt-toplevel/boot-archive.pub && \
+ ${pkgs.openssl}/bin/openssl pkeyutl -encrypt \
+ -in /boot-key -pubin -inkey /mnt-toplevel/boot-archive.pub \
+ -out "/mnt-toplevel/boot-keys/$boot_stamp.key.crypt")
+ rm -f /boot-key
+
+ ln -Tsf "$boot_stamp" /mnt-toplevel/boots/last
+ ln -Tsf "$boot_stamp.key.crypt" /mnt-toplevel/boot-keys/last.key.crypt
+
+ mount --bind "$root_from_toplevel" /mnt-root
+ mount --make-shared /mnt-root
+
+ # mount --move es mala idea, ya que "moving a mount residing under a
+ # shared mount is unsupported"
+ mkdir -p /mnt-root/toplevel
+ mount --bind /mnt-toplevel /mnt-root/toplevel
+ mount --make-private /mnt-root/toplevel
+ umount /mnt-toplevel
+ '';
+
+ fileSystems = {
+ "/" = {
+ device = "none";
+ fsType = "ext4";
+ options = ["remount"];
+ };
+
+ "/nix" = {
+ device = "/persist/nix";
+ options = ["bind"];
+ };
+
+ "/persist" = {
+ device = "/toplevel/persist";
+ options = ["bind"];
+ neededForBoot = true;
+ };
+ };
+
+ local.boot = {
+ fscrypt.enable = true;
+ impermanence.enable = true;
+ };
+ };
+}
diff --git a/sys/boot/tpm.nix b/sys/boot/tpm.nix
new file mode 100644
index 0000000..ecc115b
--- /dev/null
+++ b/sys/boot/tpm.nix
@@ -0,0 +1,128 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.boot.tpm;
+
+ pcrList = concatStringsSep "," (map toString cfg.initrd.pcrs);
+
+ # Crear signing-key con:
+ # $ openssl genrsa -out ~/vtmp/signing-key.priv 2048
+ # $ openssl rsa -in ~/vtmp/signing-key.priv -out ~/vtmp/signing-key.pub -pubout
+ # Y copiar signing-key.pub a /boot/tpm-boot. Guardar signing-key.priv en lugar seguro.
+ #
+ # Crear llave con:
+ # $ tpm2_loadexternal -G rsa -C owner -u signing-key.pub -c signing-key.ctx -n signing-key.name
+ # $ tpm2_startauthsession -S session.ctx
+ # $ tpm2_policyauthorize -S session.ctx -L require-signed.policy -n signing-key.name
+ # $ tpm2_flushcontext session.ctx
+ # $ tpm2_createprimary -C owner -g sha256 -G ecc -c prim.ctx
+ # $ head -c128 /dev/urandom | tpm2_create -C prim.ctx -u key.pub -r key.priv -c key.ctx -L require-signed.policy -i-
+ # Y mover key.priv/key.pub a /boot/tpm-boot
+ #
+ # Usage: tpm2-grant-next-boot < signing-key.priv
+ # Genera auth.policy y auth.sig
+ tpm2-grant-next-boot = pkgs.writeShellApplication {
+ name = "tpm2-grant-next-boot";
+
+ runtimeInputs = [
+ pkgs.jq
+ pkgs.openssl
+ pkgs.sbctl
+ pkgs.tpm2-tools
+ ];
+
+ text = ''
+ if [ -z "''${YES_I_DO_WANT_TO_SIGN_WITH_SECURE_BOOT_DISABLED:=}" ] && [ "$(sbctl status --json | jq .secure_boot)" != "truee" ]; then
+ echo "$0: bad Secure Boot state, check the output of \`sbctl status\`" >&2
+ echo "$0: signing a TPM PCR policy with Secure Boot disabled is dangerous" >&2
+ echo "$0: set 'YES_I_DO_WANT_TO_SIGN_WITH_SECURE_BOOT_DISABLED' to skip this check" >&2
+ exit 1
+ fi
+
+ ctx_dir="$(mktemp -d)"
+ trap 'rm -rf -- "$ctx_dir"' EXIT
+
+ tpm2_createprimary -Q -C owner -g sha256 -G ecc -c "$ctx_dir/prim.ctx"
+
+ tpm2_startauthsession -Q -S "$ctx_dir/session.ctx"
+ tpm_resets=$(tpm2_readclock | grep reset_count | sed 's/.*: //')
+ tpm2_policycountertimer -Q -S "$ctx_dir/session.ctx" resets="$((tpm_resets+1))"
+ tpm2_policypcr -Q -S "$ctx_dir/session.ctx" -L auth.policy -l sha256:${pcrList}
+ tpm2_flushcontext -Q "$ctx_dir/session.ctx"
+
+ openssl dgst -sha256 -sign /dev/stdin -out auth.sig auth.policy
+ '';
+ };
+in {
+ options.local.boot.tpm = {
+ enable = mkEnableOption "Trusted Platform Module 2.0";
+
+ driver = mkOption {
+ type = types.enum ["tis" "crb"];
+ };
+
+ initrd = {
+ enable = mkEnableOption "TPM2 in initrd";
+
+ pcrs = mkOption {
+ type = with types; listOf (ints.between 0 23);
+
+ # From 'systemd-analyze pcrs'
+ default = [
+ 0 # platform-code
+ 1 # platform-config
+ 2 # external-code
+ 3 # external-config
+ 4 # boot-loader-code
+ 5 # boot-loader-config
+ 7 # secure-boot-policy
+ 9 # kernel-initrd
+ 11 # kernel-boot
+ 12 # kernel-config
+ 13 # sysexts
+ 14 # shim-policy
+ ];
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.boot.efi.enable;
+ message = "TPM2 requires EFI";
+ }
+ {
+ assertion = cfg.initrd.enable -> cfg.enable;
+ message = "TPM2 in initrd requires TPM2";
+ }
+ ];
+
+ boot.initrd = mkIf cfg.initrd.enable {
+ extraUtilsCommands = ''
+ copy_bin_and_libs ${pkgs.tpm2-tools}/bin/.tpm2-wrapped
+ mv $out/bin/{.tpm2-wrapped,tpm2}
+ cp {${pkgs.tpm2-tss},$out}/lib/libtss2-tcti-device.so.0
+ '';
+
+ kernelModules = [
+ "tpm_${cfg.driver}"
+ ];
+ };
+
+ environment.systemPackages = optionals cfg.initrd.enable [
+ tpm2-grant-next-boot
+ ];
+
+ security.tpm2 = {
+ enable = true;
+
+ pkcs11.enable = true;
+ tctiEnvironment.enable = true;
+ };
+ };
+}
diff --git a/sys/btrfs/default.nix b/sys/btrfs/default.nix
new file mode 100644
index 0000000..ee76537
--- /dev/null
+++ b/sys/btrfs/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./mounts.nix
+ ./snapper.nix
+ ];
+}
diff --git a/sys/btrfs/mounts.nix b/sys/btrfs/mounts.nix
new file mode 100644
index 0000000..3863356
--- /dev/null
+++ b/sys/btrfs/mounts.nix
@@ -0,0 +1,47 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.btrfs;
+in {
+ options.local.btrfs = {
+ mounts = mkOption {
+ default = {};
+
+ type = with lib.types;
+ attrsOf (submodule {
+ options = {
+ ssd = mkOption {
+ type = bool;
+ };
+
+ device = mkOption {
+ type = str;
+ };
+
+ subvol = mkOption {
+ type = str;
+ };
+ };
+ });
+ };
+ };
+
+ config = mkIf (cfg.mounts != {}) {
+ fileSystems = let
+ btrfsMount = {
+ device,
+ subvol,
+ ssd,
+ }: {
+ inherit device;
+ fsType = "btrfs";
+ options = ["noatime" "compress=zstd" "subvol=${subvol}"] ++ optional ssd "ssd";
+ };
+ in
+ mapAttrs (_: btrfsMount) cfg.mounts;
+ };
+}
diff --git a/sys/btrfs/snapper.nix b/sys/btrfs/snapper.nix
new file mode 100644
index 0000000..2d29aa4
--- /dev/null
+++ b/sys/btrfs/snapper.nix
@@ -0,0 +1,76 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.btrfs;
+in {
+ options.local.btrfs = {
+ snapper = mkOption {
+ type = with lib.types; attrsOf str;
+ default = {};
+ };
+ };
+
+ config = mkIf (cfg.snapper != {}) {
+ environment.systemPackages = [pkgs.local.btclone];
+
+ services.snapper.configs = let
+ snapperConfig = _: subvolume: {
+ SUBVOLUME = subvolume;
+
+ # btrfs qgroup for space aware cleanup algorithms
+ QGROUP = "";
+
+ # fraction of the filesystems space the snapshots may use
+ SPACE_LIMIT = "0.5";
+
+ # fraction of the filesystems space that should be free
+ FREE_LIMIT = "0.2";
+
+ # users and groups allowed to work with config
+ ALLOW_USERS = [];
+ ALLOW_GROUPS = [];
+
+ # sync users and groups from ALLOW_USERS and ALLOW_GROUPS to .snapshots
+ # directory
+ SYNC_ACL = "no";
+
+ # start comparing pre- and post-snapshot in background after creating
+ # post-snapshot
+ BACKGROUND_COMPARISON = "yes";
+
+ # run daily number cleanup
+ NUMBER_CLEANUP = "yes";
+
+ # limit for number cleanup
+ NUMBER_MIN_AGE = "1800";
+ NUMBER_LIMIT = "100";
+ NUMBER_LIMIT_IMPORTANT = "10";
+
+ # create hourly snapshots
+ TIMELINE_CREATE = true;
+
+ # cleanup hourly snapshots after some time
+ TIMELINE_CLEANUP = true;
+
+ # limits for timeline cleanup
+ TIMELINE_MIN_AGE = "1800";
+ TIMELINE_LIMIT_HOURLY = "24";
+ TIMELINE_LIMIT_DAILY = "7";
+ TIMELINE_LIMIT_WEEKLY = "4";
+ TIMELINE_LIMIT_MONTHLY = "12";
+ TIMELINE_LIMIT_YEARLY = "10";
+
+ # cleanup empty pre-post-pairs
+ EMPTY_PRE_POST_CLEANUP = "yes";
+
+ # limits for empty pre-post-pair cleanup
+ EMPTY_PRE_POST_MIN_AGE = "1800";
+ };
+ in
+ mapAttrs snapperConfig cfg.snapper;
+ };
+}
diff --git a/sys/default.nix b/sys/default.nix
new file mode 100644
index 0000000..131ddeb
--- /dev/null
+++ b/sys/default.nix
@@ -0,0 +1,38 @@
+{
+ lib,
+ config,
+ flakes,
+ pkgs,
+ ...
+}:
+with lib; {
+ imports = [
+ flakes.nixpkgs.nixosModules.notDetected
+ flakes.nixvirt.nixosModules.default
+ flakes.lanzaboote.nixosModules.lanzaboote
+ flakes.impermanence.nixosModule
+ flakes.home-manager.nixosModules.home-manager
+ flakes.trivionomicon.nixosModules.default
+ ../pki
+ ./auth
+ ./baseline
+ ./boot
+ ./btrfs
+ ./env
+ ./gitea
+ ./hardware
+ ./home-assistant
+ ./jobs
+ ./kiosk
+ ./mail
+ ./mta
+ ./net
+ ./ns
+ ./nspawn
+ ./preset
+ ./seat
+ ./syncthing
+ ./virt
+ ./web
+ ];
+}
diff --git a/sys/env/default.nix b/sys/env/default.nix
new file mode 100644
index 0000000..5e3cb98
--- /dev/null
+++ b/sys/env/default.nix
@@ -0,0 +1,8 @@
+{
+ imports = [
+ ./maps.nix
+ ./domains.nix
+ ./users.nix
+ ./virtual.nix
+ ];
+}
diff --git a/sys/env/domains.nix b/sys/env/domains.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/domains.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/env/maps.nix b/sys/env/maps.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/maps.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/env/users.nix b/sys/env/users.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/users.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/env/virtual.nix b/sys/env/virtual.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/env/virtual.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/gitea/default.nix b/sys/gitea/default.nix
new file mode 100644
index 0000000..212b9f1
--- /dev/null
+++ b/sys/gitea/default.nix
@@ -0,0 +1,41 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.gitea;
+in {
+ options.local.gitea = {
+ enable = mkEnableOption "gitea";
+ };
+
+ config = mkIf cfg.enable {
+ environment.etc."fail2ban/filter.d/gitea.local".text = ''
+ [Definition]
+ failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
+ ignoreregex =
+ '';
+
+ services = {
+ fail2ban.jails.gitea.settings = {
+ filter = "gitea";
+ logpath = "${config.services.gitea.stateDir}/log/gitea.log";
+ maxretry = "10";
+ findtime = "3600";
+ bantime = "900";
+ action = "iptables-allports";
+ };
+
+ gitea = {
+ enable = true;
+ useWizard = true;
+ };
+ };
+
+ users = {
+ users.gitea.uid = 962;
+ groups.gitea.gid = 962;
+ };
+ };
+}
diff --git a/sys/hardware/altera.nix b/sys/hardware/altera.nix
new file mode 100644
index 0000000..fddd722
--- /dev/null
+++ b/sys/hardware/altera.nix
@@ -0,0 +1,25 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.altera;
+in {
+ options.local.hardware.altera = {
+ enable = mkEnableOption "Altera USB Blaster";
+ };
+
+ config = mkIf cfg.enable {
+ services.udev.extraRules = ''
+ # USB-Blaster
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="660", GROUP="users", TAG+="uaccess"
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6002", MODE="660", GROUP="users", TAG+="uaccess"
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6003", MODE="660", GROUP="users", TAG+="uaccess"
+
+ # USB-Blaster II
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6010", MODE="660", GROUP="users", TAG+="uaccess"
+ ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6810", MODE="660", GROUP="users", TAG+="uaccess"
+ '';
+ };
+}
diff --git a/sys/hardware/apc.nix b/sys/hardware/apc.nix
new file mode 100644
index 0000000..97a5bb0
--- /dev/null
+++ b/sys/hardware/apc.nix
@@ -0,0 +1,33 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.apc;
+in {
+ options.local.hardware.apc = {
+ enable = mkEnableOption "APC UPS support";
+ };
+
+ config = mkIf cfg.enable {
+ services.apcupsd = {
+ enable = true;
+
+ configText = concatStrings (mapAttrsToList (k: v: "${k} ${v}\n") {
+ UPSMODE = "disable";
+ UPSTYPE = "usb";
+ UPSCABLE = "usb";
+ UPSCLASS = "standalone";
+
+ NISIP = "127.0.0.1";
+ NETSERVER = "on";
+
+ MINUTES = "5";
+ BATTERYLEVEL = "10";
+
+ NOLOGON = "disable";
+ });
+ };
+ };
+}
diff --git a/sys/hardware/athena.nix b/sys/hardware/athena.nix
new file mode 100644
index 0000000..755c184
--- /dev/null
+++ b/sys/hardware/athena.nix
@@ -0,0 +1,48 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.athena;
+
+ athena = pkgs.local.athena-bccr.${cfg.release};
+in {
+ options.local.hardware.athena = {
+ enable = mkEnableOption "Athena ASEDrive III smartcard reader";
+
+ release = mkOption {
+ type = types.str;
+ default = "latest";
+ description = "athena-bccr release tag";
+ };
+ };
+
+ config = mkIf cfg.enable {
+ environment = {
+ etc = {
+ "Athena".source = "${athena.ase-pkcs11}/etc/Athena";
+
+ "pkcs11/modules/asep11".text = ''
+ module: ${athena.libasep11}
+ '';
+ };
+
+ systemPackages = [athena.ase-pkcs11];
+ };
+
+ #FIXME: Extremadamente peligroso si BCCR o MICITT caen, investigar política nacional de root CA
+ security.pki.certificateFiles = ["${athena.bccr-cacerts}/root-ca.pem"];
+
+ services = {
+ pcscd.enable = true;
+
+ #TODO: Sería mejor agregar un grupo separado
+ udev.extraRules = ''
+ # Athena Smartcard Solutions, Inc. ASEDrive V3CR
+ ATTRS{idVendor}=="0dc3", ATTRS{idProduct}=="1004", MODE="660", GROUP="users", TAG+="uaccess"
+ '';
+ };
+ };
+}
diff --git a/sys/hardware/bluetooth.nix b/sys/hardware/bluetooth.nix
new file mode 100644
index 0000000..63e3f0c
--- /dev/null
+++ b/sys/hardware/bluetooth.nix
@@ -0,0 +1,19 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.bluetooth;
+in {
+ options.local.hardware.bluetooth = {
+ enable = mkEnableOption "bluetooth services";
+ };
+
+ config = mkIf cfg.enable {
+ hardware.bluetooth = {
+ enable = true;
+ powerOnBoot = mkDefault false;
+ };
+ };
+}
diff --git a/sys/hardware/default.nix b/sys/hardware/default.nix
new file mode 100644
index 0000000..2ded912
--- /dev/null
+++ b/sys/hardware/default.nix
@@ -0,0 +1,13 @@
+{
+ imports = [
+ ./altera.nix
+ ./athena.nix
+ ./apc.nix
+ ./bluetooth.nix
+ ./epson.nix
+ ./laptop.nix
+ ./printing.nix
+ ./thinkpad.nix
+ ./yubico.nix
+ ];
+}
diff --git a/sys/hardware/epson.nix b/sys/hardware/epson.nix
new file mode 100644
index 0000000..30b1303
--- /dev/null
+++ b/sys/hardware/epson.nix
@@ -0,0 +1,38 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.epson;
+in {
+ options.local.hardware.epson = {
+ enable = mkEnableOption "Epson printers and scanners";
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.hardware.printing.enable;
+ message = "epson requires printing";
+ }
+ ];
+
+ hardware.sane = {
+ enable = true;
+
+ extraBackends = [
+ pkgs.epkowa
+ ];
+ };
+
+ services.printing = {
+ enable = true;
+
+ drivers = [
+ pkgs.epson_201207w
+ ];
+ };
+ };
+}
diff --git a/sys/hardware/laptop.nix b/sys/hardware/laptop.nix
new file mode 100644
index 0000000..3b5b772
--- /dev/null
+++ b/sys/hardware/laptop.nix
@@ -0,0 +1,19 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.laptop;
+in {
+ options.local.hardware.laptop = {
+ enable = mkEnableOption "laptop stuff";
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ tlp.enable = true;
+ upower.enable = true;
+ };
+ };
+}
diff --git a/sys/hardware/printing.nix b/sys/hardware/printing.nix
new file mode 100644
index 0000000..e11a016
--- /dev/null
+++ b/sys/hardware/printing.nix
@@ -0,0 +1,50 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.printing;
+ inherit (config.local.net) dhcpInterface;
+in {
+ options.local.hardware.printing = {
+ enable = mkEnableOption "print and scan services";
+
+ users = mkOption {
+ type = with types; listOf str;
+ default = [];
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = config.local.net.enable;
+ message = "Printing requires net";
+ }
+ ];
+
+ services.avahi = {
+ enable = true;
+ nssmdns4 = true;
+
+ # Abre 5353 en todas las interfaces (!!!)
+ openFirewall = false;
+ };
+
+ hardware.sane.enable = true;
+
+ networking.firewall.interfaces = mkIf (dhcpInterface != null) {
+ ${dhcpInterface}.allowedUDPPorts = [5353];
+ };
+
+ services.printing.enable = true;
+
+ users.users = listToAttrs (map
+ (user: {
+ name = user;
+ value.extraGroups = ["scanner" "lp"];
+ })
+ cfg.users);
+ };
+}
diff --git a/sys/hardware/thinkpad.nix b/sys/hardware/thinkpad.nix
new file mode 100644
index 0000000..ab18694
--- /dev/null
+++ b/sys/hardware/thinkpad.nix
@@ -0,0 +1,42 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.thinkpad;
+in {
+ options.local.hardware.thinkpad = {
+ enable = mkEnableOption "Thinkpad hardware support";
+ };
+
+ config = mkIf cfg.enable {
+ # For suspending to RAM to work, set Config -> Power -> Sleep State to "Linux" in EFI.
+ # See https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X1_Carbon_(Gen_6)#Suspend_issues
+ # Fingerprint sensor requires a firmware-update to work.
+
+ boot = {
+ extraModulePackages = with config.boot.kernelPackages; [acpi_call];
+ extraModprobeConfig = "options iwlwifi 11n_disable=1 wd_disable=1";
+
+ # acpi_call makes tlp work for newer thinkpads
+ kernelModules = ["acpi_call"];
+
+ # Force use of the thinkpad_acpi driver for backlight control.
+ # This allows the backlight save/load systemd service to work.
+ kernelParams = ["acpi_backlight=native"];
+ };
+
+ hardware.firmware = [pkgs.sof-firmware];
+
+ local.hardware.laptop.enable = true;
+
+ services = {
+ fprintd.enable = true;
+ thinkfan.enable = true;
+ tlp.enable = true;
+ tp-auto-kbbl.enable = true;
+ };
+ };
+}
diff --git a/sys/hardware/yubico.nix b/sys/hardware/yubico.nix
new file mode 100644
index 0000000..0c8478c
--- /dev/null
+++ b/sys/hardware/yubico.nix
@@ -0,0 +1,24 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.hardware.yubico;
+in {
+ options.local.hardware.yubico = {
+ enable = mkEnableOption "Yubico hardware support";
+ };
+
+ config = mkIf cfg.enable {
+ environment.etc."pkcs11/modules/ykcs11".text = ''
+ module: ${pkgs.yubico-piv-tool}/lib/libykcs11.so
+ '';
+
+ services = {
+ pcscd.enable = true;
+ udev.packages = [pkgs.yubikey-personalization];
+ };
+ };
+}
diff --git a/sys/home-assistant/default.nix b/sys/home-assistant/default.nix
new file mode 100644
index 0000000..e997c08
--- /dev/null
+++ b/sys/home-assistant/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./hass.nix
+ ./yaml-extra.nix
+ ];
+}
diff --git a/sys/home-assistant/hass.nix b/sys/home-assistant/hass.nix
new file mode 100644
index 0000000..7fd3251
--- /dev/null
+++ b/sys/home-assistant/hass.nix
@@ -0,0 +1,79 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.home-assistant;
+in {
+ options.local.home-assistant = {
+ enable = mkEnableOption "home-assistant";
+ };
+
+ config = mkIf cfg.enable {
+ # https://nathan.gs/2024/06/22/fail2ban-to-secure-ha-on-nixos/
+ environment.etc."fail2ban/filter.d/home-assistant.local".text = ''
+ [Definition]
+ failregex = ^.* \[homeassistant\.components\.http\.ban\] Login attempt or request with invalid authentication from <HOST>.*$
+
+ ignoreregex =
+
+ journalmatch = _SYSTEMD_UNIT=home-assistant.service + _COMM=home-assistant
+
+ datepattern = {^LN-BEG}
+ '';
+
+ local.boot.impermanence.directories = [
+ {
+ directory = "/var/lib/hass";
+ user = "hass";
+ group = "hass";
+ mode = "u=rwx,g=,o=";
+ }
+ ];
+
+ services = {
+ fail2ban.jails.home-assistant = {};
+
+ home-assistant = {
+ enable = true;
+
+ extraComponents = [
+ "met"
+ "google_translate"
+ "radio_browser"
+ "tuya"
+ "wake_on_lan"
+ "webostv"
+ "xiaomi_miio"
+ ];
+
+ config = {
+ # Includes dependencies for a basic setup
+ # https://www.home-assistant.io/integrations/default_config/
+ default_config = {};
+
+ switch = [
+ # Televisor 192.168.42.205
+ # TODO: No sirve por 192.168.34 vs 192.168.42
+ {
+ platform = "wake_on_lan";
+ mac = "74:40:be:58:5f:da";
+ }
+ ];
+ };
+
+ customComponents = with pkgs.home-assistant-custom-components; [
+ dreame_vacuum
+ smartthinq_sensors
+ xiaomi_miot
+ ];
+
+ customLovelaceModules = with pkgs.home-assistant-custom-lovelace-modules; [
+ xiaomi-vacuum-map-card
+ ];
+ };
+ };
+ };
+}
diff --git a/sys/home-assistant/yaml-extra.nix b/sys/home-assistant/yaml-extra.nix
new file mode 100644
index 0000000..77d1ed2
--- /dev/null
+++ b/sys/home-assistant/yaml-extra.nix
@@ -0,0 +1,23 @@
+{lib, ...}:
+with lib; {
+ options.services.home-assistant = {
+ config = mkOption {
+ type = with lib.types;
+ nullOr (submodule {
+ options = {
+ http = {
+ use_x_forwarded_for = mkOption {
+ type = nullOr bool;
+ default = null;
+ };
+
+ trusted_proxies = mkOption {
+ type = nullOr (either str (listOf str));
+ default = null;
+ };
+ };
+ };
+ });
+ };
+ };
+}
diff --git a/sys/jobs/default.nix b/sys/jobs/default.nix
new file mode 100644
index 0000000..24d6c73
--- /dev/null
+++ b/sys/jobs/default.nix
@@ -0,0 +1,5 @@
+{
+ imports = [
+ ./pki-expiry
+ ];
+}
diff --git a/sys/jobs/pki-expiry/default.nix b/sys/jobs/pki-expiry/default.nix
new file mode 100644
index 0000000..553cdc8
--- /dev/null
+++ b/sys/jobs/pki-expiry/default.nix
@@ -0,0 +1,60 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.jobs.pkiExpiry;
+ inherit (config.local) pki;
+in {
+ options.local.jobs.pkiExpiry = {
+ enable = mkEnableOption "PKI expiration reminder";
+ };
+
+ config = mkIf cfg.enable {
+ systemd = {
+ services.pki-expiry = {
+ after = ["postfix.service"];
+ path = ["/run/wrappers"];
+
+ environment.PKI_PUBLIC = let
+ mkdir = "mkdir -p $out/{ca,cert,crl}";
+
+ cas = mapAttrsToList (_: ca: "ln -s ${ca.cert} $out/ca/${ca.path}") pki.ca;
+ crls = mapAttrsToList (_: ca: "ln -s ${ca.crl} $out/crl/${ca.path}") pki.ca;
+
+ certs =
+ mapAttrsToList
+ (path: leaf: "ln -s ${leaf.cert} $out/cert/${path}")
+ (filterAttrs (_: object: ! object ? leaves) pki.byPath);
+
+ pkiPublic = pkgs.runCommandNoCCLocal "pki-public" {} (concatLines ([mkdir] ++ cas ++ crls ++ certs));
+ in "${pkiPublic}";
+
+ serviceConfig = {
+ Type = "oneshot";
+ StateDirectory = "pki-expiry";
+ WorkingDirectory = "/var/lib/pki-expiry";
+
+ ExecStart = let
+ script = pkgs.writeShellApplication {
+ name = "pki-expiry";
+ text = readFile ./pki-expiry.sh;
+ runtimeInputs = with pkgs; [diffutils openssl];
+ };
+ in "${getExe script}";
+ };
+ };
+
+ timers.pki-expiry = {
+ wantedBy = ["timers.target"];
+
+ timerConfig = {
+ OnStartupSec = "10m";
+ OnUnitInactiveSec = "3d";
+ };
+ };
+ };
+ };
+}
diff --git a/sys/jobs/pki-expiry/pki-expiry.sh b/sys/jobs/pki-expiry/pki-expiry.sh
new file mode 100644
index 0000000..0e95a26
--- /dev/null
+++ b/sys/jobs/pki-expiry/pki-expiry.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+#
+function will_expire() {
+ expiry_status=""
+ expiry_vars="$(openssl "$openssl_cmd" -in "$object_path" -noout "${openssl_var_opts[@]}")"
+
+ expiry_date="$(echo "$expiry_vars" | grep "^$openssl_expiry_var=" | sed 's/^.\+=//g')"
+ if [ -z "$expiry_date" ]; then
+ return 1
+ fi
+
+ expiry_secs="$(date +%s -d "$expiry_date")"
+ diff="$((expiry_secs - now))"
+
+ if [ "$diff" -gt "$1" ]; then
+ return 1
+ elif [ "$diff" -lt 0 ]; then
+ remaining=0
+ else
+ remaining="$((diff / 86400))"
+ fi
+
+ total_matches="$((total_matches + 1))"
+
+ if [ -z "$min_expiry" ]; then
+ min_expiry="$remaining"
+ elif [ "$remaining" -lt "$min_expiry" ]; then
+ min_expiry="$remaining"
+ fi
+}
+
+function has_expired() {
+ if ! will_expire 0; then
+ return 1
+ fi
+
+ expiry_status="has expired"
+}
+
+function will_expire_days() {
+ if ! will_expire "$(($1 * 86400))"; then
+ return 1
+ fi
+
+ expiry_status="will expire in $remaining days"
+}
+
+function check_object() {
+ object_id="$(basename "$1")"
+ object_path="$1"
+
+ if has_expired || will_expire_days 3 || will_expire_days 7 || will_expire_days 15 || will_expire_days 30; then
+ {
+ echo
+ echo "$object_repr '$object_id' $expiry_status"
+ echo "$expiry_vars"
+ } >>"$mail_out"
+ fi
+}
+
+function check_dir() {
+ object_repr="$2"
+
+ for path in "$PKI_PUBLIC/$1"/*; do
+ check_object "$path"
+ done
+}
+
+if [ -z "$PKI_PUBLIC" ]; then
+ echo "$0: \$PKI_PUBLIC not set"
+ exit 1
+elif [ ! -d "$PKI_PUBLIC" ]; then
+ echo "$0: invalid \$PKI_PUBLIC: $PKI_PUBLIC"
+ exit 1
+fi
+
+mail_out="$(mktemp)"
+trap 'rm -f -- "$mail_out"' EXIT
+
+now="$(date +%s)"
+min_expiry=""
+total_matches=0
+
+openssl_cmd=x509
+openssl_var_opts=(-startdate -enddate)
+openssl_expiry_var="notAfter"
+
+check_dir ca "CA"
+check_dir cert "Certificate"
+
+openssl_cmd=crl
+openssl_var_opts=(-lastupdate -nextupdate)
+openssl_expiry_var="nextUpdate"
+
+check_dir crl "CRL for CA"
+
+if [ -s "$mail_out" ] && ! cmp -s last-mail "$mail_out"; then
+ sendmail -t <<- EOF
+ From: PKI expiration reminder <pki-expiry>
+ To: sysadmin
+ Subject: $total_matches PKI objects will expire in $min_expiry days
+
+ The following PKI objects are due for renewal:
+ $(<"$mail_out")
+ EOF
+
+ mv -- "$mail_out" last-mail
+fi
diff --git a/sys/kiosk/default.nix b/sys/kiosk/default.nix
new file mode 100644
index 0000000..be20829
--- /dev/null
+++ b/sys/kiosk/default.nix
@@ -0,0 +1,48 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.kiosk;
+in {
+ options.local.kiosk = {
+ enable = mkEnableOption "kiosk mode";
+
+ program = mkOption {
+ type = types.str;
+ };
+
+ user = mkOption {
+ type = types.str;
+ };
+
+ allowVTSwitch = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ cage = {
+ enable = true;
+ inherit (cfg) program user;
+
+ extraArguments = [
+ (
+ if cfg.allowVTSwitch
+ then "-sd"
+ else "-d"
+ )
+ ];
+ };
+
+ physlock = {
+ enable = true;
+ disableSysRq = true;
+ muteKernelMessages = true;
+ };
+ };
+ };
+}
diff --git a/sys/mail/default.nix b/sys/mail/default.nix
new file mode 100644
index 0000000..f87b6fe
--- /dev/null
+++ b/sys/mail/default.nix
@@ -0,0 +1,246 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.mailHost;
+ imapHostname = config.local.domains.imap.main;
+
+ cert = config.security.acme.certs.${imapHostname}.directory;
+
+ inherit (config.local) users virtual;
+in {
+ options.local.mailHost = {
+ enable = mkEnableOption "mailbox host service";
+
+ mdaListen = mkOption {
+ type = types.str;
+ };
+
+ saslPort = mkOption {
+ type = types.port;
+ };
+
+ lmtpPort = mkOption {
+ type = types.port;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ # 25.05: The option definition `services.dovecot2.modules' in
+ # `/nix/store/d3mfmsa6klf9dizidvs9qgfv4bgxqgvz-source/sys/mail' no longer
+ # has any effect; please remove it. Now need to use
+ # `environment.systemPackages` to load additional Dovecot modules
+ environment.systemPackages = [
+ pkgs.dovecot_pigeonhole
+ ];
+
+ services = {
+ dovecot2 = {
+ enable = true;
+ enablePAM = false;
+ enableLmtp = true;
+
+ sslServerKey = "${cert}/key.pem";
+ sslServerCert = "${cert}/fullchain.pem";
+
+ mailUser = "vmail";
+ mailGroup = "vmail";
+ mailLocation = "maildir:~/mail";
+ mailPlugins.perProtocol.lmtp.enable = ["sieve"];
+
+ # https://github.com/NixOS/nixpkgs/issues/286859
+ sieve.extensions = [
+ "fileinto"
+ "mailbox"
+ ];
+
+ extraConfig = let
+ inherit (config.networking) domain;
+
+ # https://dovecot.org/list/dovecot/2019-March/115250.html
+ # Otra solución posible (https://serverfault.com/a/1062274/980378):
+ # auth_username_format = %{if;%d;eq;${domain};%Ln;%Lu}
+ localEntry = canonical: username: ''
+ ${username}:::::::user=${canonical} nopassword userdb_user=${canonical}
+ '';
+
+ localMailboxes =
+ pkgs.writeText "local-mailboxes"
+ (concatStrings
+ (flatten (mapAttrsToList
+ (canonical: user:
+ map (localEntry canonical) ([canonical] ++ user.hardAliases))
+ users)));
+
+ localCerts = flatten (mapAttrsToList
+ (canonical: user: let
+ certNames = {
+ inherit canonical;
+ logins = [canonical] ++ user.hardAliases;
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ users);
+
+ vmailCerts = flatten (flatten (mapAttrsToList
+ (domain: virtual:
+ mapAttrsToList
+ (username: user: let
+ address = "${username}@${domain}";
+
+ certNames = {
+ canonical = address;
+ logins = [address];
+ };
+ in
+ map (flip nameValuePair certNames) user.mail.certs)
+ virtual.users)
+ virtual));
+
+ certLogins =
+ pkgs.writeText "cert-logins"
+ (concatLines (flatten (mapAttrsToList
+ (certPath: names:
+ map
+ (addr: "${config.local.pki.byPath.${certPath}.commonName}@nodomain,${addr}:::::::user=${names.canonical}")
+ names.logins)
+ (listToAttrs (localCerts ++ vmailCerts)))));
+
+ vmailPath = "/var/lib/vmail/%{if;%d;ne;;%Ld;${domain}}";
+ in ''
+ auth_mechanisms = plain login external
+
+ ssl_ca = <${config.local.pki.ca.mail.fullchain}
+ ssl_require_crl = yes
+ ssl_verify_client_cert = yes
+
+ # Esto descarta @domain.tld de locales explícitos, pero lo exige para los demás.
+ # Implicación: locales implícitos sin dominio fallan en autenticar
+ auth_username_format = %{if;%Ld;eq;${domain};%Ln;%{if;%d;ne;;%Lu;%Ln@nodomain}}
+ auth_ssl_username_from_cert = yes
+
+ # TODO: los defaults de nixpkgs dejan los sockets bajo
+ # /run/dovecot2 con demasiados permisos rwx, arreglar
+
+ service auth {
+ inet_listener mta-sasl {
+ port = ${toString cfg.saslPort}
+ address = ${cfg.mdaListen}
+ }
+ }
+
+ service lmtp {
+ inet_listener mta-lmtp {
+ port = ${toString cfg.lmtpPort}
+ address = ${cfg.mdaListen}
+ }
+ }
+
+ # FIXME: Esta cadena de passdbs hace que 'doveadm user lookup'
+ # falle para usuarios locales, pero todo lo demás sirve. Parece
+ # ser debido a que pam no puede enumerar.
+
+ passdb {
+ driver = static
+ args = nopassword
+
+ master = yes
+ mechanisms = external
+
+ result_success = continue-fail
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN username_format=%{master_user},%Lu ${certLogins}
+
+ mechanisms = external
+ override_fields = nopassword
+
+ result_failure = return-fail
+ result_internalfail = return-fail
+ }
+
+ passdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ }
+
+ passdb {
+ driver = passwd-file
+ args = scheme=PLAIN ${localMailboxes}
+
+ # Esta es una forma de determinar si se encontró el usuario en
+ # el passwd-file por medio de nopassword sin realmente
+ # autenticarlo. Cuidado con result_success, porque si eso se
+ # configura mal se permite inicio de sesión con cualquier
+ # contraseña (!!!).
+ result_success = continue
+ result_failure = return-fail
+ result_internalfail = return-fail
+
+ username_filter = !*@*
+ }
+
+ passdb {
+ driver = pam
+ args = dovecot2
+ username_filter = !*@*
+ #TODO: algo como 'override_fields = allow_nets=...'
+ }
+
+ userdb {
+ driver = passwd-file
+ args = username_format=%Ln ${vmailPath}/passwd
+ override_fields = uid=vmail gid=vmail home=${vmailPath}/home/%Ln
+ }
+
+ userdb {
+ driver = passwd-file
+ args = ${localMailboxes}
+
+ result_success = continue-ok
+ result_internalfail = return-fail
+ skip = found
+ }
+
+ userdb {
+ driver = passwd
+ args = blocking=no
+ skip = notfound
+ }
+ '';
+ };
+
+ fail2ban.jails.dovecot.settings = {
+ filter = "dovecot[mode=aggressive]";
+ maxretry = 3;
+ };
+ };
+
+ security = {
+ # Necesario debido a 'enablePAM = false'
+ pam.services.dovecot2 = {};
+
+ acme.certs.${imapHostname} = {
+ inherit (config.services.dovecot2) group;
+
+ reloadServices = ["dovecot2.service"];
+ };
+ };
+
+ users = {
+ users.${config.services.dovecot2.mailUser}.uid = 995;
+ groups.${config.services.dovecot2.mailGroup}.gid = 993;
+ };
+
+ networking.firewall.allowedTCPPorts = [143 993];
+
+ local.certs.imap.enable = true;
+ };
+}
diff --git a/sys/mta/default.nix b/sys/mta/default.nix
new file mode 100644
index 0000000..57c1c27
--- /dev/null
+++ b/sys/mta/default.nix
@@ -0,0 +1,269 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.mta;
+
+ inherit (config.local) domains virtual users;
+ inherit (config.networking) domain;
+
+ isBackup = cfg.mode == "backup";
+ isPrimary = cfg.mode == "primary";
+
+ allDomains = optional (! virtualDomains ? ${domain}) domain ++ attrNames virtualDomains;
+ virtualDomains = filterAttrs (name: _: name != domain) virtual;
+
+ cert = config.security.acme.certs.${mtaDomain.main}.directory;
+
+ mtaDomain =
+ if isPrimary
+ then domains.smtp
+ else domains.smtp-backup;
+
+ mdaTransport =
+ if isPrimary
+ then "lmtp:inet:${cfg.mdaAddr}:${toString cfg.lmtpPort}"
+ else "error:bad transport";
+in {
+ options.local.mta = {
+ enable = mkEnableOption "mail transfer agent";
+
+ mode = mkOption {
+ type = types.enum ["primary" "backup"];
+ };
+
+ mdaAddr = mkOption {
+ type = types.str;
+ };
+
+ saslPort = mkOption {
+ type = types.port;
+ };
+
+ lmtpPort = mkOption {
+ type = types.port;
+ };
+
+ relayListen = mkOption {
+ type = types.str;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ fail2ban.jails.postfix.settings = {
+ filter = "postfix[mode=aggressive]";
+ };
+
+ opendkim = mkIf isPrimary {
+ enable = true;
+
+ group = "postfix";
+ domains = "csl:" + concatStringsSep "," ([domain] ++ attrNames virtualDomains);
+ selector = "202408";
+
+ configFile = pkgs.writeText "opendkim.conf" ''
+ UMask 007
+ InternalHosts 0.0.0.0/0,::/0
+ '';
+ };
+
+ postfix = {
+ enable = true;
+ enableSmtp = true;
+ enableSubmissions = isPrimary;
+
+ inherit domain;
+ hostname = mtaDomain.main;
+
+ #TODO: check_recipient_access para rechazar localhost desde afuera
+ destination = optionals isPrimary ["localhost" "$mydomain"];
+ origin = "$mydomain";
+
+ networksStyle = "host";
+
+ relayHost = optionalString isBackup domains.smtp.main;
+ lookupMX = false;
+
+ relayDomains =
+ if isBackup
+ then allDomains
+ else null;
+
+ sslKey = "${cert}/key.pem";
+ sslCert = "${cert}/fullchain.pem";
+
+ # También es postmaster
+ rootAlias = config.local.sysadmin;
+
+ extraAliases =
+ optionalString isPrimary
+ (concatLines (flatten (mapAttrsToList
+ (name: user:
+ map
+ (alias: "${alias}: ${name}")
+ user.hardAliases)
+ users)));
+
+ localRecipients =
+ optionals isPrimary
+ (map (user: "${user}@${domain}")
+ (attrNames (users // virtual.${domain}.users)));
+
+ virtual =
+ optionalString isPrimary
+ (concatLines (flatten (mapAttrsToList
+ (name: virtual:
+ mapAttrsToList
+ (alias: targets: "${alias}@${name} ${concatStringsSep ", " targets}")
+ virtual.aliases)
+ virtual)));
+
+ mapFiles = optionalAttrs isPrimary {
+ sender_ccerts =
+ pkgs.writeText "postfix-sender_ccerts"
+ (concatLines (flatten (mapAttrsToList
+ (username: user:
+ map
+ (alias: "${alias}@${domain} CCERTS ${concatStringsSep ","
+ (map (certPath: config.local.pki.byPath.${certPath}.fingerprint.sha256-bytes-upper)
+ user.mail.certs)}")
+ ([username] ++ user.hardAliases))
+ (filterAttrs (_: user: user.mail.certs != []) users))));
+
+ sender_login =
+ pkgs.writeText "postfix-sender_login"
+ (concatLines (flatten (mapAttrsToList
+ (username: user:
+ map
+ (alias: "${alias}@${domain} ${username}")
+ ([username] ++ user.hardAliases))
+ users)));
+
+ virtual_recipients =
+ pkgs.writeText "postfix-virtual_recipients"
+ (concatLines (flatten (mapAttrsToList
+ (virtualDomain: virtual:
+ mapAttrsToList
+ # El lado derecho de esta tabla debe existir pero nunca se usa
+ (username: _: "${username}@${virtualDomain} foo")
+ virtual.users)
+ virtualDomains)));
+
+ virtual_rules =
+ pkgs.writeText "postfix-virtual_rules"
+ (concatLines (flatten (mapAttrsToList
+ (name: virtual:
+ map
+ (rule: "/^${rule.pattern}@${name}$/ ${concatStringsSep ", " rule.targets}")
+ virtual.rules)
+ virtual)));
+ };
+
+ config =
+ {
+ # user+extension@domain.tld
+ recipient_delimiter = optionalString isPrimary "+";
+
+ message_size_limit = toString (50 * 1048576);
+
+ local_transport = mdaTransport;
+ virtual_transport = mdaTransport;
+
+ smtpd_tls_auth_only = true;
+ # Nota: smtpd_tls_dh1024_param_file fue deprecado en 3.9
+
+ tls_append_default_CA = false; # Crítico
+
+ # https://linux-audit.com/postfix-hardening-guide-for-security-and-privacy/
+ smtpd_helo_required = true;
+ disable_vrfy_command = true;
+ }
+ // optionalAttrs isPrimary {
+ virtual_alias_maps = mkAfter ["pcre:/etc/postfix/virtual_rules"];
+ virtual_mailbox_domains = attrNames virtualDomains;
+ virtual_mailbox_maps = ["hash:/etc/postfix/virtual_recipients"];
+
+ smtpd_sasl_type = "dovecot";
+ smtpd_sasl_path = "inet:${cfg.mdaAddr}:${toString cfg.saslPort}";
+ smtpd_sasl_local_domain = "$mydomain";
+ smtpd_sasl_security_options = ["noanonymous"];
+
+ smtpd_tls_CAfile = "${config.local.pki.ca.mail.fullchain}";
+ smtpd_tls_ccert_verifydepth = "1";
+
+ # Inventado, no es parámetro de postfix
+ local_submission_client_restrictions = [
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject"
+ ];
+
+ smtpd_sender_login_maps = ["hash:/etc/postfix/sender_login"];
+
+ smtpd_relay_restrictions = [
+ "permit_mynetworks"
+ "permit_tls_all_clientcerts"
+ "permit_sasl_authenticated"
+ "reject_unauth_destination"
+ ];
+
+ smtpd_sender_restrictions = [
+ "check_sender_access hash:/etc/postfix/sender_ccerts"
+ "reject_sender_login_mismatch"
+ ];
+
+ smtpd_milters = "unix:/run/opendkim/opendkim.sock";
+ non_smtpd_milters = "$smtpd_milters";
+ milter_default_action = "accept";
+ }
+ // optionalAttrs isBackup {
+ inet_interfaces = [cfg.relayListen];
+
+ smtpd_relay_restrictions = [
+ "reject_unauth_destination"
+ ];
+ };
+
+ # Importante: existe submissionOptions por aparte, no son iguales
+ submissionsOptions = optionalAttrs isPrimary {
+ smtpd_client_restrictions = "$local_submission_client_restrictions";
+ smtpd_sasl_auth_enable = "yes";
+ smtpd_tls_ask_ccert = "yes";
+ smtpd_tls_security_level = "encrypt";
+ };
+ };
+ };
+
+ #TODO: solo para las destination addresses necesarias
+ networking.firewall.allowedTCPPorts = optionals isPrimary [25 465];
+
+ local = {
+ boot.impermanence.directories =
+ [
+ {
+ directory = "/var/lib/postfix";
+ user = "root";
+ group = "root";
+ mode = "u=rwx,g=rx,o=rx";
+ }
+ ]
+ ++ optionals isPrimary [
+ {
+ directory = "/var/lib/opendkim";
+ user = "opendkim";
+ group = "postfix";
+ mode = "u=rwx,g=,o=";
+ }
+ ];
+
+ certs.smtp.enable = isPrimary;
+ certs.smtp-backup.enable = isBackup;
+ };
+
+ security.acme.certs.${mtaDomain.main}.reloadServices = ["postfix.service"];
+ };
+}
diff --git a/sys/net/default.nix b/sys/net/default.nix
new file mode 100644
index 0000000..c3c5740
--- /dev/null
+++ b/sys/net/default.nix
@@ -0,0 +1,9 @@
+{
+ imports = [
+ ./fail2ban.nix
+ ./interfaces.nix
+ ./nets.nix
+ ./options.nix
+ ./vsock.nix
+ ];
+}
diff --git a/sys/net/fail2ban.nix b/sys/net/fail2ban.nix
new file mode 100644
index 0000000..32197b6
--- /dev/null
+++ b/sys/net/fail2ban.nix
@@ -0,0 +1,37 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.net.fail2ban;
+ inherit (config.local) nets;
+in {
+ options.local.net.fail2ban = {
+ enable = mkEnableOption "fail2ban";
+ };
+
+ config = mkIf cfg.enable {
+ services.fail2ban = {
+ enable = true;
+
+ bantime = "10m";
+
+ bantime-increment = {
+ enable = true;
+
+ maxtime = "48h";
+ rndtime = "10m";
+ overalljails = true;
+ };
+
+ ignoreIP = [
+ nets.static-vpn.v6.cidr
+ nets.gate-srv.v6.cidr
+ nets.gate-public.hosts.gate.v4.address
+ nets.gate-public.hosts.gate.v6.address
+ ];
+ };
+ };
+}
diff --git a/sys/net/interfaces.nix b/sys/net/interfaces.nix
new file mode 100644
index 0000000..3b0abcd
--- /dev/null
+++ b/sys/net/interfaces.nix
@@ -0,0 +1,119 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.net;
+in {
+ options.local.net = with lib.types; {
+ enable = mkEnableOption "networking stack";
+
+ hostname = mkOption {
+ type = str;
+ };
+
+ dhcpInterface = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ boot.kernel.sysctl = {
+ # rp_filter=1 reemplazado por nixos-fw-rpfilter
+ "net.ipv4.conf.all.rp_filter" = mkForce 2;
+ "net.ipv4.conf.default.rp_filter" = mkForce 2;
+
+ "net.ipv4.conf.all.forwarding" = mkForce true;
+ "net.ipv6.conf.all.forwarding" = mkForce true;
+ "net.ipv4.conf.default.forwarding" = mkForce true;
+ "net.ipv6.conf.default.forwarding" = mkForce true;
+
+ "net.ipv4.conf.all.accept_redirects" = mkForce false;
+ "net.ipv6.conf.all.accept_redirects" = mkForce false;
+ "net.ipv4.conf.default.accept_redirects" = mkForce false;
+ "net.ipv6.conf.default.accept_redirects" = mkForce false;
+ };
+
+ environment.systemPackages = with pkgs; [
+ conntrack-tools
+ dhcpcd
+ dnsutils
+ nmap
+ socat
+ tcpdump
+ ];
+
+ networking = {
+ domain = mkDefault config.local.domains.host.main;
+ hostName = cfg.hostname;
+
+ firewall = {
+ logReversePathDrops = true;
+ checkReversePath = "loose";
+
+ extraCommands = mkBefore ''
+ ip46tables -t filter -P INPUT DROP
+ ip46tables -t filter -P FORWARD ACCEPT #TODO: DROP
+
+ ip46tables -t filter -N local-input
+ ip46tables -t filter -N local-forward
+ ip46tables -t nat -N local-prerouting
+ ip46tables -t nat -N local-postrouting
+
+ ip46tables -t filter -I INPUT -j local-input
+ ip46tables -t filter -I FORWARD -j local-forward
+ ip46tables -t nat -I PREROUTING -j local-prerouting
+ ip46tables -t nat -I POSTROUTING -j local-postrouting
+
+ ip46tables -t filter -A local-forward -m conntrack --ctstate RELATED,ESTABLISHED,SNAT,DNAT -j ACCEPT
+ '';
+
+ extraStopCommands = mkAfter ''
+ ip46tables -t filter -D INPUT -j local-input || true
+ ip46tables -t filter -D FORWARD -j local-forward || true
+ ip46tables -t nat -D PREROUTING -j local-prerouting || true
+ ip46tables -t nat -D POSTROUTING -j local-postrouting || true
+
+ ip46tables -t filter -F local-input || true
+ ip46tables -t filter -X local-input || true
+ ip46tables -t filter -F local-forward || true
+ ip46tables -t filter -X local-forward || true
+ ip46tables -t nat -F local-prerouting || true
+ ip46tables -t nat -X local-prerouting || true
+ ip46tables -t nat -F local-postrouting || true
+ ip46tables -t nat -X local-postrouting || true
+
+ ip46tables -t filter -P INPUT ACCEPT
+ ip46tables -t filter -P FORWARD ACCEPT
+ '';
+
+ logRefusedConnections = false;
+ };
+
+ useDHCP = false;
+ enableIPv6 = mkDefault true;
+ useNetworkd = mkDefault true;
+ useHostResolvConf = false;
+
+ wireguard.enable = true;
+ };
+
+ systemd.network.networks = mkIf (cfg.dhcpInterface != null) {
+ "40-${cfg.dhcpInterface}" = {
+ matchConfig.Name = cfg.dhcpInterface;
+
+ networkConfig = {
+ DHCP = "ipv4";
+ IPv6AcceptRA = true;
+ IPv6PrivacyExtensions = "kernel";
+ };
+
+ # make routing on this interface a dependency for network-online.target
+ linkConfig.RequiredForOnline = "routable";
+ };
+ };
+ };
+}
diff --git a/sys/net/nets.nix b/sys/net/nets.nix
new file mode 100644
index 0000000..1bb3788
--- /dev/null
+++ b/sys/net/nets.nix
@@ -0,0 +1 @@
+# This file has been lustrated.
diff --git a/sys/net/options.nix b/sys/net/options.nix
new file mode 100644
index 0000000..0608fb9
--- /dev/null
+++ b/sys/net/options.nix
@@ -0,0 +1,278 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ v4PtrHierarchy = address: bits: reverseList (sublist 0 (bits / 8) (splitString "." address));
+
+ v6PtrHierarchy = address: bits: let
+ separator = lists.findFirstIndex (hextet: hextet == "") null colonSplit;
+ colonSplit = splitString ":" address;
+
+ zeroFill = replicate (8 - length colonSplit + 1) "0000";
+ leftSplit = sublist 0 separator colonSplit;
+ rightSplit = sublist (separator + 1) (length colonSplit - separator - 1) colonSplit;
+
+ fullSplit =
+ if separator != null
+ then leftSplit ++ zeroFill ++ rightSplit
+ else colonSplit;
+
+ padded = map (hextet: strings.replicate (4 - stringLength hextet) "0" + hextet) fullSplit;
+ in
+ reverseList (sublist 0 (bits / 4) (flatten (map stringToCharacters padded)));
+
+ matchPtrRecordName = {
+ splitter,
+ netAddress,
+ netBits,
+ targetAddress,
+ targetBits,
+ }: let
+ netSplit = splitter netAddress netBits;
+ targetSplit = splitter targetAddress targetBits;
+
+ netLength = length netSplit;
+ lengthDelta = length targetSplit - netLength;
+
+ withinNet = lengthDelta >= 0 && sublist lengthDelta netLength targetSplit == netSplit;
+ throwMessage = "${targetAddress}/${toString targetBits} is not a subset of ${netAddress}/${toString netBits}";
+
+ recordHierarchy = sublist 0 lengthDelta targetSplit;
+
+ recordName =
+ if recordHierarchy != []
+ then concatStringsSep "." recordHierarchy
+ else "@";
+ in
+ throwIfNot withinNet throwMessage recordName;
+in {
+ options.local.nets = with lib.types;
+ mkOption {
+ readOnly = true;
+
+ type = attrsOf (submodule ({config, ...}: {
+ options = let
+ v4config = config.v4;
+ v6config = config.v6;
+ in {
+ hosts = mkOption {
+ default = {};
+
+ type = attrsOf (submodule {
+ options = {
+ v4 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ suffix = mkOption {
+ type = str;
+ };
+
+ address = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ single = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ };
+
+ config = {
+ address =
+ if v4config.bits == 0
+ then config.suffix
+ else if v4config.bits == 32
+ then v4config.subnet
+ else "${v4config.prefix}.${config.suffix}";
+
+ cidr = "${config.address}/${toString v4config.bits}";
+ single = "${config.address}/32";
+ };
+ }));
+ };
+
+ v6 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ suffix = mkOption {
+ type = str;
+ };
+
+ address = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ single = mkOption {
+ type = str;
+ readOnly = true;
+ };
+ };
+
+ config = {
+ address = let
+ hextets = fragment: length (splitString ":" fragment);
+ separator =
+ if doubleColon
+ then "::"
+ else ":";
+ doubleColon = hextets v6config.prefix + hextets config.suffix < 8;
+
+ joined =
+ if v6config.bits == 128
+ then v6config.prefix
+ else if v6config.bits == 0
+ then config.suffix
+ else "${v6config.prefix}${separator}${config.suffix}";
+ in
+ joined;
+
+ cidr = "${config.address}/${toString v6config.bits}";
+ single = "${config.address}/128";
+ };
+ }));
+ };
+ };
+ });
+ };
+
+ v4 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ bits = mkOption {
+ type = enum [0 8 16 24 32];
+ };
+
+ prefix = mkOption {
+ type = str;
+ };
+
+ subnet = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrDomain = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrRecordName = mkOption {
+ type = functionTo (functionTo str);
+ readOnly = true;
+ };
+ };
+
+ config = {
+ cidr = "${config.subnet}/${toString config.bits}";
+
+ subnet =
+ if config.bits != 0
+ then config.prefix + strings.replicate (4 - config.bits / 8) ".0"
+ else "0.0.0.0";
+
+ ptrDomain = concatStrings (map (x: x + ".") (v4PtrHierarchy config.subnet config.bits)) + "in-addr.arpa";
+
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v4PtrHierarchy;
+
+ netBits = config.bits;
+ netAddress = config.subnet;
+
+ targetBits = bits;
+ targetAddress = address;
+ };
+ };
+ }));
+ };
+
+ v6 = mkOption {
+ default = null;
+
+ type = nullOr (submodule ({config, ...}: {
+ options = {
+ bits = mkOption {
+ type =
+ addCheck (ints.between 0 128) (b: mod b 4 == 0)
+ // {
+ description = "IPv6 subnet bits at nibble boundary";
+ };
+ };
+
+ prefix = mkOption {
+ type = str;
+ };
+
+ subnet = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ cidr = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrDomain = mkOption {
+ type = str;
+ readOnly = true;
+ };
+
+ ptrRecordName = mkOption {
+ type = functionTo (functionTo str);
+ readOnly = true;
+ };
+ };
+
+ config = {
+ cidr = "${config.subnet}/${toString config.bits}";
+
+ subnet =
+ if config.bits == 128 || length (splitString "::" config.prefix) > 1
+ then config.prefix
+ else "${config.prefix}::";
+
+ ptrDomain = concatStrings (map (x: x + ".") (v6PtrHierarchy config.subnet config.bits)) + "ip6.arpa";
+
+ ptrRecordName = address: bits:
+ matchPtrRecordName {
+ splitter = v6PtrHierarchy;
+
+ netBits = config.bits;
+ netAddress = config.subnet;
+
+ targetBits = bits;
+ targetAddress = address;
+ };
+ };
+ }));
+ };
+ };
+ }));
+ };
+}
diff --git a/sys/net/vsock.nix b/sys/net/vsock.nix
new file mode 100644
index 0000000..c6b0ad6
--- /dev/null
+++ b/sys/net/vsock.nix
@@ -0,0 +1,63 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.net.vsock;
+in {
+ options.local.net.vsock = {
+ connect = mkOption {
+ default = {};
+ type = with lib.types;
+ attrsOf (submodule ({name, ...}: {
+ options = {
+ enable = mkEnableOption "vsock connect '${name}'";
+
+ cid = mkOption {
+ type = ints.u32;
+ default = 2;
+ };
+
+ localPort = mkOption {
+ type = port;
+ };
+
+ vsockPort = mkOption {
+ type = port;
+ };
+ };
+ }));
+ };
+ };
+
+ config = {
+ systemd = let
+ connects =
+ mapAttrs
+ (_: connect: {
+ service.serviceConfig = {
+ Type = "simple";
+ ExecStart = "${getExe pkgs.socat} - VSOCK:${toString connect.cid}:${toString connect.vsockPort}";
+ StandardInput = "socket";
+ };
+
+ socket = {
+ wantedBy = ["sockets.target"];
+
+ socketConfig = {
+ Accept = true;
+ ListenStream = "[::1]:${toString connect.localPort}";
+ };
+
+ unitConfig.ConditionVirtualization = "kvm";
+ };
+ })
+ cfg.connect;
+ in {
+ sockets = mapAttrs' (name: connect: nameValuePair "vsock-${name}" connect.socket) connects;
+ services = mapAttrs' (name: connect: nameValuePair "vsock-${name}@" connect.service) connects;
+ };
+ };
+}
diff --git a/sys/ns/default.nix b/sys/ns/default.nix
new file mode 100644
index 0000000..b1a4da3
--- /dev/null
+++ b/sys/ns/default.nix
@@ -0,0 +1,10 @@
+{
+ imports = [
+ ./mx.nix
+ ./ns.nix
+ ./nsd.nix
+ ./ptr
+ ./rr.nix
+ ./zones
+ ];
+}
diff --git a/sys/ns/dkim/README.md b/sys/ns/dkim/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/ns/dkim/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/ns/mx.nix b/sys/ns/mx.nix
new file mode 100644
index 0000000..892b684
--- /dev/null
+++ b/sys/ns/mx.nix
@@ -0,0 +1,60 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ inherit (config.local) domains;
+in {
+ options.local.ns.zones = mkOption {
+ type = with lib.types;
+ attrsOf (submodule ({
+ config,
+ name,
+ ...
+ }: {
+ options.localMX = {
+ enable = mkEnableOption "local MX settings";
+ };
+
+ config = mkIf config.localMX.enable {
+ mx = [
+ {
+ name = "@";
+ priority = 10;
+ host = "${domains.smtp.gated}.";
+ }
+ {
+ name = "@";
+ priority = 20;
+ host = "${domains.smtp-backup.main}.";
+ }
+ # Many thanks to junkemailfilter.com for all their years of service. RIP.
+ #{ name = "@"; priority = 30; host = "mxbackup1.junkemailfilter.com."; }
+ #{ name = "@"; priority = 40; host = "mxbackup2.junkemailfilter.com."; }
+ ];
+
+ txt =
+ [
+ {
+ name = "@";
+ text = "v=spf1 mx a -all";
+ }
+ {
+ name = "_dmarc";
+ text = "v=DMARC1;p=reject;sp=reject;adkim=r;aspf=r;fo=1;rf=afrf;rua=mailto:postmaster@${name}";
+ }
+ {
+ name = "_adsp._domainkey";
+ text = "dkim=all";
+ }
+ ]
+ ++ map
+ (selector: {
+ name = "${toString selector}._domainkey";
+ text = readFile (./dkim + "/${toString selector}.txt");
+ }) [202001 202102 202402 202408];
+ };
+ }));
+ };
+}
diff --git a/sys/ns/ns.nix b/sys/ns/ns.nix
new file mode 100644
index 0000000..e5b30e8
--- /dev/null
+++ b/sys/ns/ns.nix
@@ -0,0 +1,153 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ inherit (config.networking) domain;
+ inherit (config.local.nets) gate-public;
+ inherit (config.local.ns.server) tsigName;
+
+ ptrNets = config.local.ns.ptr;
+in {
+ options.local.ns.zones = mkOption {
+ type = with lib.types;
+ attrsOf
+ (submodule
+ ({
+ config,
+ name,
+ ...
+ }: let
+ inherit (config.soa) primary;
+
+ cfg = config.localNS;
+ ptrDomain = cfg.ptrNet.v4 != null || cfg.ptrNet.v6 != null;
+ in {
+ options.localNS = {
+ enable = mkEnableOption "local NS settings";
+
+ acme = mkOption {
+ default = {};
+ type = attrsOf str;
+ };
+
+ ptrNet = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ v6 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+ };
+ };
+
+ config =
+ mkIf cfg.enable
+ {
+ ptrName = let
+ name =
+ if cfg.ptrNet.v6 != null
+ then "${cfg.ptrNet.v6}-v6"
+ else "${cfg.ptrNet.v4}-v4";
+ in
+ mkIf ptrDomain name;
+
+ # https://docs.gandi.net/en/domain_names/advanced_users/secondary_nameserver.html
+ nsdConfig = let
+ providerSecondary = [
+ "37.205.15.45 ${tsigName}" # ns3.vpsfree.cz
+ "37.205.11.85 ${tsigName}" # ns4.vpsfree.cz
+ "2a03:3b40:fe:2be::1 ${tsigName}" # ns3.vpsfree.cz
+ "2a03:3b40:101:4::1 ${tsigName}" # ns4.vpsfree.cz
+ ];
+ in {
+ notify = providerSecondary;
+ provideXFR = providerSecondary;
+ };
+
+ ns = [
+ {
+ name = "@";
+ host = primary;
+ }
+ {
+ name = "@";
+ host = "ns3.vpsfree.cz.";
+ }
+ {
+ name = "@";
+ host = "ns4.vpsfree.cz.";
+ }
+ ];
+
+ a =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv4 = gate-public.hosts.gate.v4.address;
+ ptr = null;
+ };
+
+ aaaa =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv6 = gate-public.hosts.gate.v6.address;
+ ptr = null;
+ };
+
+ ptr = let
+ ptrsToRecords = mapAttrsToList (suffix: target: {
+ name = suffix;
+ inherit target;
+ });
+
+ v4Net = cfg.ptrNet.v4;
+ v6Net = cfg.ptrNet.v6;
+
+ v4Records = optionals (v4Net != null) (ptrsToRecords ptrNets.${v4Net}.v4.targets);
+ v6Records = optionals (v6Net != null) (ptrsToRecords ptrNets.${v6Net}.v6.targets);
+ in
+ v4Records ++ v6Records;
+
+ soa = mkIf ptrDomain {
+ authorityZone = mkDefault "${domain}.";
+ };
+
+ cname =
+ mapAttrsToList
+ (name: id: {
+ name = "_acme-challenge" + optionalString (name != "@") ".${name}";
+ target = "${id}.acme-challenge.${domain}.";
+ })
+ cfg.acme;
+ };
+ }));
+ };
+
+ config = {
+ assertions =
+ mapAttrsToList
+ (name: zone: {
+ assertion = zone.localNS.ptrNet.v4 != null -> zone.localNS.ptrNet.v6 == null;
+ message = "zone '${name}' defined as both a v4 and v6 PTR zone";
+ })
+ config.local.ns.zones;
+
+ local.ns.ptr = let
+ zonePtrNets = name: zone:
+ optionalAttrs (zone.localNS.ptrNet.v4 != null)
+ {
+ ${zone.localNS.ptrNet.v4}.v4.zone = name;
+ }
+ // optionalAttrs (zone.localNS.ptrNet.v6 != null) {
+ ${zone.localNS.ptrNet.v6}.v6.zone = name;
+ };
+ in
+ mkMerge (flatten (mapAttrsToList zonePtrNets (filterAttrs (_: zone: zone.localNS.enable) config.local.ns.zones)));
+ };
+}
diff --git a/sys/ns/nsd.nix b/sys/ns/nsd.nix
new file mode 100644
index 0000000..d49e464
--- /dev/null
+++ b/sys/ns/nsd.nix
@@ -0,0 +1,87 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ inherit (config.networking) domain;
+
+ cfg = config.local.ns.server;
+
+ acmeChallengeDomain = "acme-challenge.${domain}";
+in {
+ options. local. ns. server = {
+ enable = mkEnableOption "nsd authoritative server";
+
+ tsigName = mkOption {
+ type = types.str;
+ default = "NOKEY";
+ };
+
+ acme = {
+ apiListen.v6 = mkOption {
+ type = types.str;
+ };
+
+ dnsListen.v6 = mkOption {
+ type = types.str;
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = cfg.tsigName == "NOKEY" || config.services.nsd.keys ? "${cfg.tsigName}";
+ message = "TSIG key '${cfg.tsigName}' not defined";
+ }
+ ];
+
+ networking.firewall = let
+ inherit (config.services.nsd) port;
+ in {
+ allowedTCPPorts = [port];
+ allowedUDPPorts = [port];
+ };
+
+ services = {
+ acme-dns = {
+ enable = true;
+ settings = {
+ api = {
+ ip = "[${cfg.acme.apiListen.v6}]";
+ port = 80;
+ };
+
+ general = {
+ domain = acmeChallengeDomain;
+ nsname = acmeChallengeDomain;
+ nsadmin = "hostmaster.${domain}";
+
+ listen = "[${cfg.acme.dnsListen.v6}]:53";
+
+ records = [
+ "${acmeChallengeDomain}. NS ${acmeChallengeDomain}."
+ "${acmeChallengeDomain}. AAAA ${cfg.acme.dnsListen.v6}"
+ ];
+ };
+ };
+ };
+
+ nsd = {
+ enable = true;
+
+ ipFreebind = true;
+
+ bind8Stats = true;
+ statistics = 3600;
+
+ tcpCount = 128;
+ tcpTimeout = 30;
+ tcpQueryCount = 128;
+
+ zones = mapAttrs' (name: zone: nameValuePair "${name}." zone.nsdConfig) config.local.ns.zones;
+ };
+ };
+ };
+}
diff --git a/sys/ns/ptr/default.nix b/sys/ns/ptr/default.nix
new file mode 100644
index 0000000..b4fba7e
--- /dev/null
+++ b/sys/ns/ptr/default.nix
@@ -0,0 +1,9 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ config.local.ns.zones = {
+ ${nets.gate-public.v4.ptrDomain} = import ./gate-public-v4;
+ ${nets.gate-public.v6.ptrDomain} = import ./gate-public-v6;
+ ${nets.static-prefix.v6.ptrDomain} = import ./static-prefix-v6;
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v4/default.nix b/sys/ns/ptr/gate-public-v4/default.nix
new file mode 100644
index 0000000..44c7f2e
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v4/default.nix
@@ -0,0 +1,14 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ imports = [
+ ./serial.nix
+ ];
+
+ config = {
+ localNS = {
+ enable = true;
+ ptrNet.v4 = "gate-public";
+ };
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v4/serial.nix b/sys/ns/ptr/gate-public-v4/serial.nix
new file mode 100644
index 0000000..008e5d8
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v4/serial.nix
@@ -0,0 +1,6 @@
+{
+ config = {
+ soa.serial = 2025042402;
+ nullSerialHash = "sha256-afaedee02017aabd45b944a657ce91515866982c7cb900927edcee6d2b39c731";
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v6/default.nix b/sys/ns/ptr/gate-public-v6/default.nix
new file mode 100644
index 0000000..674421f
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v6/default.nix
@@ -0,0 +1,14 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ imports = [
+ ./serial.nix
+ ];
+
+ config = {
+ localNS = {
+ enable = true;
+ ptrNet.v6 = "gate-public";
+ };
+ };
+}
diff --git a/sys/ns/ptr/gate-public-v6/serial.nix b/sys/ns/ptr/gate-public-v6/serial.nix
new file mode 100644
index 0000000..126a17e
--- /dev/null
+++ b/sys/ns/ptr/gate-public-v6/serial.nix
@@ -0,0 +1,6 @@
+{
+ config = {
+ soa.serial = 2025042402;
+ nullSerialHash = "sha256-9a8ac8849ea6c8993e44feefe439b96c643e2ccf3a03d0d700558e9a188f57d7";
+ };
+}
diff --git a/sys/ns/ptr/static-prefix-v6/default.nix b/sys/ns/ptr/static-prefix-v6/default.nix
new file mode 100644
index 0000000..7688b97
--- /dev/null
+++ b/sys/ns/ptr/static-prefix-v6/default.nix
@@ -0,0 +1,14 @@
+{config, ...}: let
+ inherit (config.local) nets;
+in {
+ imports = [
+ ./serial.nix
+ ];
+
+ config = {
+ localNS = {
+ enable = true;
+ ptrNet.v6 = "static-prefix";
+ };
+ };
+}
diff --git a/sys/ns/ptr/static-prefix-v6/serial.nix b/sys/ns/ptr/static-prefix-v6/serial.nix
new file mode 100644
index 0000000..a7c214a
--- /dev/null
+++ b/sys/ns/ptr/static-prefix-v6/serial.nix
@@ -0,0 +1,6 @@
+{
+ config = {
+ soa.serial = 2025042600;
+ nullSerialHash = "sha256-a5ce7781b014aa816998410db440dd40278d8b566d1de76e06776a83c9839b35";
+ };
+}
diff --git a/sys/ns/rr.nix b/sys/ns/rr.nix
new file mode 100644
index 0000000..7f089d1
--- /dev/null
+++ b/sys/ns/rr.nix
@@ -0,0 +1,520 @@
+{
+ config,
+ lib,
+ options,
+ pkgs,
+ ...
+}:
+with lib; let
+ inherit (config.local) nets;
+
+ cfg = config.local.ns;
+ globalConfig = config;
+
+ segmentRegex = "[a-z0-9_-]+(\\.[a-z0-9_-]+)*";
+
+ emailType = lib.types.strMatching "[a-z0-9._-]+(@${segmentRegex})?";
+ domainRefType = lib.types.strMatching "@|${segmentRegex}\\.?";
+ domainNameType = lib.types.strMatching "${segmentRegex}\\.";
+
+ zoneHashCheck = name: zone: let
+ zoneHash = algorithm: "${algorithm}-${builtins.hashString algorithm cfg.nullSerialZones.${name}.content}";
+ expected = zoneHash "sha256";
+ in {
+ inherit expected zone;
+ needsUpdate = zone.soa.serial == null || zone.nullSerialHash != expected;
+ };
+
+ rrTypes = [
+ "A"
+ "AAAA"
+ "CNAME"
+ "MX"
+ "NS"
+ "PTR"
+ "SOA"
+ "SRV"
+ "TXT"
+ ];
+in {
+ options.local.ns = {
+ nullSerialZones = mkOption {
+ type = options.local.ns.zones.type;
+ readOnly = true;
+ };
+
+ ptr = mkOption {
+ default = {};
+
+ type = with lib.types;
+ attrsOf (submodule {
+ options = {
+ v4 = {
+ zone = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ targets = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
+ };
+
+ v6 = {
+ zone = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ targets = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
+ };
+ };
+ });
+ };
+
+ zones = mkOption {
+ default = {};
+
+ type = with lib.types;
+ attrsOf (submodule ({
+ config,
+ name,
+ ...
+ }: let
+ nameOption = args @ {
+ defaultZone ? "${name}.",
+ permitRelative ? true,
+ ...
+ }:
+ mkOption (removeAttrs args ["defaultZone" "permitRelative"]
+ // {
+ type = domainRefType;
+
+ apply = value: let
+ zone =
+ throwIfNot
+ (hasSuffix "." defaultZone)
+ "zone expression '${defaultZone}' must be absolute, not relative"
+ defaultZone;
+ in
+ if value == "@"
+ then zone
+ else if hasSuffix "." value
+ then value
+ else if permitRelative
+ then "${value}.${zone}"
+ else throw "zone expression '${value}' in zone '${zone}' must be absolute, not relative";
+ });
+
+ rrType = options:
+ mkOption {
+ default = [];
+ type = listOf (submodule {
+ options =
+ options
+ // {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
+ };
+ };
+ });
+ };
+
+ rrConfig = {
+ rrs,
+ type,
+ format,
+ applyName ? (rr: rr.name),
+ }: (map
+ (rr: {
+ inherit type;
+ inherit (rr) ttl;
+
+ data = format rr;
+ name = applyName rr;
+ })
+ rrs);
+ in {
+ options = {
+ local = mkOption {
+ type = unspecified;
+ default = globalConfig.local;
+ readOnly = true;
+ };
+
+ defaultTTL = mkOption {
+ type = int;
+ default = 3600;
+ };
+
+ ptrName = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ defaultPtr = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ v6 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+ };
+
+ nsdConfig = mkOption {
+ type = attrsOf unspecified;
+ default = {};
+ };
+
+ content = mkOption {
+ type = lines;
+ readOnly = true;
+ };
+
+ nullSerialHash = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ rr = mkOption {
+ default = [];
+ type =
+ listOf
+ (submodule {
+ options = {
+ name = nameOption {};
+
+ ttl = mkOption {
+ type = int;
+ };
+
+ class = mkOption {
+ type = enum ["IN"];
+ default = "IN";
+ };
+
+ type = mkOption {
+ type = enum rrTypes;
+ };
+
+ data = mkOption {
+ type = listOf (either int str);
+ default = [];
+ };
+ };
+ });
+ };
+
+ soa = {
+ authorityZone = nameOption {
+ default = "@";
+ permitRelative = false;
+ };
+
+ ttl = mkOption {
+ type = int;
+ default = config.defaultTTL;
+ };
+
+ primary = nameOption {
+ default = "ns1";
+ defaultZone = config.soa.authorityZone;
+ };
+
+ hostmaster = mkOption {
+ type = emailType;
+ default = "hostmaster";
+
+ apply = address: let
+ split = splitString "@" address;
+
+ user = head split;
+ domain =
+ if length split == 2
+ then head (tail split)
+ else removeSuffix "." config.soa.authorityZone;
+ in
+ if hasSuffix "." address
+ then address
+ else "${replaceStrings ["."] ["\\."] user}.${domain}.";
+ };
+
+ serial = mkOption {
+ type = nullOr int;
+ default = null;
+ };
+
+ refresh = mkOption {
+ type = int;
+ default = 3 * 3600;
+ };
+
+ retry = mkOption {
+ type = int;
+ default = 3600;
+ };
+
+ expire = mkOption {
+ type = int;
+ default = 7 * 24 * 3600;
+ };
+
+ negativeTTL = mkOption {
+ type = int;
+ default = 3600;
+ };
+ };
+
+ a = rrType {
+ ipv4 = mkOption {
+ type = str;
+ };
+
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v4;
+ };
+ };
+
+ aaaa = rrType {
+ ipv6 = mkOption {
+ type = str;
+ };
+
+ ptr = mkOption {
+ type = nullOr str;
+ default = config.defaultPtr.v6;
+ };
+ };
+
+ cname = rrType {
+ target = nameOption {};
+ };
+
+ mx = rrType {
+ host = nameOption {};
+
+ priority = mkOption {
+ type = int;
+ };
+ };
+
+ ns = rrType {
+ host = nameOption {};
+ };
+
+ ptr = rrType {
+ target = nameOption {};
+ };
+
+ srv = rrType {
+ host = nameOption {};
+
+ port = mkOption {
+ type = port;
+ };
+
+ priority = mkOption {
+ type = int;
+ };
+
+ proto = mkOption {
+ type = enum ["tcp" "udp"];
+ };
+
+ service = mkOption {
+ type = str;
+ };
+
+ weight = mkOption {
+ type = int;
+ };
+ };
+
+ txt = rrType {
+ text = mkOption {
+ type = strMatching "[^\"\n\\]*\n?";
+ apply = removeSuffix "\n";
+ };
+ };
+ };
+
+ config = {
+ nsdConfig.data = config.content;
+
+ content = let
+ rrLine = rr: concatMapStringsSep " " toString ([rr.name rr.ttl rr.class rr.type] ++ rr.data);
+ in
+ ''
+ $ORIGIN ${name}.
+ $TTL ${toString config.defaultTTL}
+ ''
+ + concatLines (map rrLine config.rr);
+
+ rr = mkMerge [
+ (mkOrder 0 (singleton {
+ inherit (config.soa) ttl;
+
+ name = "${name}.";
+ type = "SOA";
+
+ data = with config.soa; [
+ primary
+ hostmaster
+ (throwIf (serial == null) "No serial defined for zone ${name}" serial)
+ refresh
+ retry
+ expire
+ negativeTTL
+ ];
+ }))
+
+ (mkOrder 1 (rrConfig {
+ rrs = config.ns;
+ type = "NS";
+ format = rr: [rr.host];
+ }))
+
+ (rrConfig {
+ rrs = config.a;
+ type = "A";
+ format = rr: [rr.ipv4];
+ })
+
+ (rrConfig {
+ rrs = config.aaaa;
+ type = "AAAA";
+ format = rr: [rr.ipv6];
+ })
+
+ (rrConfig {
+ rrs = config.cname;
+ type = "CNAME";
+ format = rr: [rr.target];
+ })
+
+ (rrConfig {
+ rrs = config.mx;
+ type = "MX";
+ format = rr: [rr.priority rr.host];
+ })
+
+ (rrConfig {
+ rrs = config.ptr;
+ type = "PTR";
+ format = rr: [rr.target];
+ })
+
+ (rrConfig {
+ rrs = config.srv;
+ type = "SRV";
+
+ format = rr: [rr.priority rr.weight rr.port rr.host];
+ applyName = rr: "_${rr.service}._${rr.proto}.${rr.name}";
+ })
+
+ (rrConfig {
+ rrs = config.txt;
+ type = "TXT";
+
+ format = rr: let
+ # nsd-zonecheck: text string is longer than 255 characters, try splitting it into multiple parts
+ txtFragments = text: let
+ max = 255;
+ length = stringLength text;
+ in
+ singleton (substring 0 max text) ++ optionals (length > max) (txtFragments (substring max length text));
+ in
+ map (fragment: "\"${fragment}\"") (txtFragments rr.text);
+ })
+ ];
+ };
+ }));
+ };
+ };
+
+ config = {
+ assertions =
+ [
+ (
+ let
+ badZones = attrNames (filterAttrs (name: zone: (zoneHashCheck name zone).needsUpdate) cfg.zones);
+ in {
+ assertion = badZones == [];
+ message = "Update serials for these zones (null-serial hash mismatch): ${concatStringsSep ", " badZones}";
+ }
+ )
+ ]
+ ++ flatten (mapAttrsToList
+ (name: ptr: [
+ {
+ assertion = ptr.v4.targets != {} -> ptr.v4.zone != null;
+ message = "undefined v4 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v4.targets)}";
+ }
+ {
+ assertion = ptr.v6.targets != {} -> ptr.v6.zone != null;
+ message = "undefined v6 PTR net '${name}': ${concatStringsSep ", " (attrValues ptr.v6.targets)}";
+ }
+ ])
+ cfg.ptr);
+
+ lib.local.zoneSerialUpdates = let
+ ptrChecks = filterAttrs (_: check: check.zone.ptrName != null) allZoneChecks;
+ zoneChecks = filterAttrs (_: check: check.zone.ptrName == null) allZoneChecks;
+ allZoneChecks = filterAttrs (_: check: check.needsUpdate) (mapAttrs zoneHashCheck cfg.zones);
+
+ updateInfo = name: check: {
+ inherit name;
+ inherit (check) expected;
+ inherit (check.zone.soa) serial;
+ };
+ in {
+ ptr = mapAttrs (_: check: updateInfo check.zone.ptrName check) ptrChecks;
+ zones = mapAttrs updateInfo zoneChecks;
+ };
+
+ local.ns = {
+ nullSerialZones = let
+ defaultAttrs = ["defaultTTL" "defaultPtr" "ptrName"];
+ filteredAttrs = defaultAttrs ++ map toLower rrTypes;
+ in
+ mapAttrs
+ (_: zone:
+ mkMerge [
+ (filterAttrs (name: _: elem name filteredAttrs) zone)
+ {soa.serial = mkOverride 0 0;}
+ ])
+ cfg.zones;
+
+ ptr = let
+ zonePtrs = zone: let
+ v4Ptrs =
+ map
+ (a: {
+ ${a.ptr}.v4.targets.${nets.${a.ptr}.v4.ptrRecordName a.ipv4 32} = a.name;
+ })
+ (filter (a: a.ptr != null) zone.a);
+
+ v6Ptrs =
+ map
+ (aaaa: {
+ ${aaaa.ptr}.v6.targets.${nets.${aaaa.ptr}.v6.ptrRecordName aaaa.ipv6 128} = aaaa.name;
+ })
+ (filter (aaaa: aaaa.ptr != null) zone.aaaa);
+ in
+ v4Ptrs ++ v6Ptrs;
+ in
+ mkMerge (flatten (mapAttrsToList (_: zonePtrs) cfg.zones));
+ };
+ };
+}
diff --git a/sys/ns/zones/README.md b/sys/ns/zones/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/ns/zones/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/nspawn/default.nix b/sys/nspawn/default.nix
new file mode 100644
index 0000000..15e60de
--- /dev/null
+++ b/sys/nspawn/default.nix
@@ -0,0 +1,5 @@
+{
+ imports = [
+ ./dmz.nix
+ ];
+}
diff --git a/sys/nspawn/dmz.nix b/sys/nspawn/dmz.nix
new file mode 100644
index 0000000..3263730
--- /dev/null
+++ b/sys/nspawn/dmz.nix
@@ -0,0 +1,229 @@
+{
+ config,
+ lib,
+ pkgs,
+ flakes,
+ doctrine,
+ ...
+}:
+with lib; let
+ cfg = config.local.nspawn.dmz;
+ inherit (config.local) mailHost;
+
+ dmzNet = config.local.nets.${cfg.netName};
+
+ hassPort = config.services.home-assistant.config.http.server_port;
+ hassEnable = config.local.home-assistant.enable;
+in {
+ options.local.nspawn.dmz = {
+ enable = mkEnableOption "DMZ services in a container";
+
+ dns64 = mkOption {
+ type = types.str;
+ };
+
+ netName = mkOption {
+ type = types.str;
+ };
+
+ net6 = mkOption {
+ type = types.str;
+ readOnly = true;
+ };
+
+ hostAddr6 = mkOption {
+ type = types.str;
+ readOnly = true;
+ };
+
+ system = mkOption {
+ type = types.raw;
+ };
+ };
+
+ # Situación con os-release
+ #
+ # La idea aquí es poder hacer 'btrfs subvol create /var/lib/machines/foo' y
+ # dejar que systemd-nspawn y el activation script creen todo lo demás. Esto
+ # no sirve bien debido a la prueba barata que hace systemd para revisar si el
+ # árbol parece contener una imagen de sistema operativo. Esta prueba falla en
+ # dos momentos distintos:
+ #
+ # 1. Inmediatamente tras crear un árbol vacío, puesto que os-release no existe.
+ # La solución naive es 'mkdir rootfs/etc && touch rootfs/etc/os-release'.
+ #
+ # 2. Luego de reiniciar el contenedor una vez que NixOS ha preparado /etc, ya que
+ # systemd espera un archivo regular y no telera el symlink a la store.
+ #
+ # Resulta ser que systemd revisa tanto /etc/os-release como /usr/lib/os-release.
+ # NixOS evidentemente no usa la segunda ruta por ser FHS, así que la duct tape
+ # final es 'mkdir rootfs/usr/lib && touch rootfs/usr/lib/os-release'.
+
+ config = mkIf cfg.enable {
+ local = {
+ mailHost.mdaListen = cfg.hostAddr6;
+
+ nspawn.dmz = {
+ hostAddr6 = dmzNet.hosts.gateway.v6.address;
+
+ system = let
+ containerModule = {...}: {
+ #TODO: urgente: bloquear puertos de dovecot a non-postfix con iptables
+ config = {
+ local = {
+ preset.dmz = {
+ enable = true;
+ container = true;
+ };
+
+ mta = {
+ mdaAddr = "[${mailHost.mdaListen}]";
+ inherit (mailHost) saslPort lmtpPort;
+ };
+
+ web.sites = {
+ home = {
+ enable = hassEnable;
+ proxyUrl = "http://[${cfg.hostAddr6}]:${toString hassPort}";
+ };
+ };
+ };
+
+ nixpkgs = {
+ pkgs = mkDefault pkgs;
+ localSystem = mkDefault pkgs.stdenv.hostPlatform;
+ };
+
+ services.nginx.virtualHosts = {
+ "${config.local.domains.imap.main}".locations."^~ /.well-known/acme-challenge/" = {
+ root = "/var/lib/acme/acme-challenge";
+
+ extraConfig = ''
+ auth_basic off;
+ auth_request off;
+ '';
+ };
+ };
+
+ systemd.network.networks."40-host0" = {
+ name = "host0";
+
+ networkConfig = {
+ DNS = [cfg.dns64];
+
+ DHCP = "no";
+ IPv6AcceptRA = "yes";
+ LinkLocalAddressing = "ipv6";
+ };
+
+ ipv6AcceptRAConfig = {
+ Token = [
+ "static:::${dmzNet.hosts.dmz.v6.suffix}"
+ "eui64"
+ "static:::${dmzNet.hosts.mta.v6.suffix}"
+ "static:::${dmzNet.hosts.web.v6.suffix}"
+ ];
+
+ UseDNS = false;
+ };
+ };
+ };
+ };
+ in
+ flakes.trivionomicon.lib.mkSystem {
+ inherit doctrine flakes pkgs;
+
+ modules = [
+ ../.
+ containerModule
+ ];
+ };
+ };
+ };
+
+ services = {
+ home-assistant.config.http = mkIf hassEnable {
+ server_host = [cfg.hostAddr6];
+ trusted_proxies = [dmzNet.hosts.web.v6.address];
+ use_x_forwarded_for = true;
+ };
+ };
+
+ systemd = {
+ nspawn.dmz = {
+ execConfig.PrivateUsers = "pick";
+
+ filesConfig.BindReadOnly = [
+ # idmap porque algunos hacks en nixpkgs (postfix-setup.service)
+ # asumen que la store es de root
+ "/nix/store:/nix/store:idmap"
+ "${cfg.system.config.system.build.toplevel}/init:/sbin/init"
+ ];
+ };
+
+ network.networks."40-ve-dmz" = {
+ matchConfig = {
+ Name = "ve-dmz";
+ Driver = "veth";
+ };
+
+ addresses = [
+ {
+ Address = dmzNet.hosts.gateway.v6.cidr;
+ AddPrefixRoute = "no";
+ PreferredLifetime = 0;
+ }
+ ];
+
+ networkConfig = {
+ LinkLocalAddressing = "ipv6";
+ DHCPServer = "no";
+ IPMasquerade = "no";
+ LLDP = "no";
+ EmitLLDP = "no";
+ IPv6SendRA = "yes";
+ IPv6AcceptRA = "no";
+ };
+
+ ipv6Prefixes = [
+ {
+ Assign = "no";
+ Prefix = dmzNet.v6.cidr;
+ }
+ ];
+
+ routes = [
+ {
+ Destination = dmzNet.v6.cidr;
+ # Sin esto, siempre se escogerá una ULA como source address debido a "PreferredLifetime = 0" en la GUA
+ PreferredSource = dmzNet.hosts.gateway.v6.address;
+ }
+ ];
+ };
+
+ services = {
+ dovecot2.after = ["systemd-nspawn@dmz.service"];
+
+ "systemd-nspawn@dmz" = {
+ overrideStrategy = "asDropin";
+
+ after = ["network-online.target"];
+ wants = ["network-online.target"];
+ wantedBy = ["machines.target"];
+ };
+ };
+ };
+
+ networking.firewall = {
+ allowedTCPPorts = [25 80 443];
+
+ interfaces.ve-dmz = {
+ allowedTCPPorts =
+ [mailHost.saslPort mailHost.lmtpPort]
+ ++ optional hassEnable hassPort;
+
+ allowedUDPPorts = [67]; # DHCP
+ };
+ };
+ };
+}
diff --git a/sys/platform/README.md b/sys/platform/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/platform/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/preset/default.nix b/sys/preset/default.nix
new file mode 100644
index 0000000..45ae529
--- /dev/null
+++ b/sys/preset/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./dmz.nix
+ ./user.nix
+ ];
+}
diff --git a/sys/preset/dmz.nix b/sys/preset/dmz.nix
new file mode 100644
index 0000000..5a04c1e
--- /dev/null
+++ b/sys/preset/dmz.nix
@@ -0,0 +1,64 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.preset.dmz;
+in {
+ options.local.preset.dmz = {
+ enable = mkEnableOption "dmz preset";
+
+ container = mkOption {
+ type = types.bool;
+ default = false;
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+ local = {
+ boot = {
+ kernel = mkDefault pkgs.linuxPackages_hardened;
+ loader = mkDefault "grub";
+
+ efi.enable = mkDefault (!cfg.container);
+ firmware.mode = mkDefault "none";
+ namespaced.enable = cfg.container;
+
+ stack.luksExt4FscryptImpermanence = {
+ enable = mkDefault (!cfg.container);
+ };
+ };
+
+ jobs.pkiExpiry.enable = mkDefault config.local.mta.enable;
+
+ mta = {
+ enable = mkDefault true;
+
+ mode = "primary";
+ };
+
+ net = {
+ enable = true;
+ hostname = "dmz";
+
+ fail2ban.enable = true;
+ };
+
+ web.sites.portal.enable = true;
+ };
+
+ services = {
+ resolved = {
+ llmnr = "false";
+ fallbackDns = []; # Disable the default systemd-resolved server list
+ };
+ };
+
+ users = {
+ allowNoPasswordLogin = cfg.container;
+ mutableUsers = false;
+ };
+ };
+}
diff --git a/sys/preset/user.nix b/sys/preset/user.nix
new file mode 100644
index 0000000..fd9c5ff
--- /dev/null
+++ b/sys/preset/user.nix
@@ -0,0 +1,73 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: let
+ inherit (lib) mkDefault;
+ cfg = config.local.preset.user;
+in {
+ options.local.preset.user = {
+ enable = lib.mkEnableOption "user-like preset";
+ };
+
+ config = lib.mkIf cfg.enable {
+ local = {
+ installUsers = mkDefault "single";
+
+ auth = {
+ oath.enable = mkDefault true;
+
+ openssh = {
+ enable = mkDefault true;
+
+ hostKeys = {
+ rsa = mkDefault true;
+ ecdsa = mkDefault true;
+ ed25519 = mkDefault true;
+ };
+ };
+ };
+
+ boot = {
+ kernel = mkDefault pkgs.linuxPackages_latest;
+ loader = mkDefault "grub";
+
+ efi = {
+ enable = mkDefault true;
+ removable = mkDefault false;
+ };
+
+ firmware.mode = mkDefault "redistributable";
+ detachedLuks.enable = mkDefault true;
+
+ stack.btrfsToplevelMultidrive = {
+ enable = mkDefault true;
+
+ toplevel.root = mkDefault "/root";
+ secondary.home = mkDefault "/home";
+ };
+ };
+
+ hardware = {
+ yubico.enable = mkDefault true;
+ bluetooth.enable = mkDefault true;
+ };
+
+ net.enable = true;
+
+ seat = {
+ enable = true;
+ graphical = mkDefault true;
+ };
+ };
+
+ services.nullmailer = {
+ enable = mkDefault true;
+
+ config = {
+ me = "${config.networking.hostName}@${config.networking.domain}";
+ };
+ };
+ };
+}
diff --git a/sys/seat/default.nix b/sys/seat/default.nix
new file mode 100644
index 0000000..402047f
--- /dev/null
+++ b/sys/seat/default.nix
@@ -0,0 +1,142 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.seat;
+
+ users = filterAttrs (_: user: user.install) config.local.users;
+in {
+ options.local.seat = {
+ enable = mkEnableOption "user seat";
+
+ graphical = mkOption {
+ type = types.bool;
+ default = false;
+ };
+
+ wayland = mkOption {
+ type = types.bool;
+ default = true;
+ };
+
+ videoDrivers = mkOption {
+ type = with types; listOf str;
+ };
+ };
+
+ config =
+ mkIf cfg.enable
+ (mkMerge [
+ {
+ hardware = {
+ acpilight.enable = true;
+ };
+
+ security.rtkit.enable = true;
+
+ services = {
+ pipewire = {
+ enable = true;
+
+ alsa = {
+ enable = true;
+ support32Bit = true;
+ };
+
+ jack.enable = true;
+ pulse.enable = true;
+ wireplumber.enable = true;
+ };
+
+ pulseaudio.enable = false;
+ };
+
+ users = {
+ groups =
+ mapAttrs (_: user: {inherit (user) gid;}) users
+ // {
+ adbusers.gid = 1008;
+ };
+
+ users =
+ mapAttrs
+ (username: user: {
+ isNormalUser = true;
+
+ inherit (user) uid;
+ description = user.gecos;
+
+ group = username;
+ extraGroups = ["users"] ++ user.groups;
+
+ shell =
+ if user.allowLogin
+ then pkgs.zsh
+ else null;
+ })
+ users;
+ };
+ }
+ (mkIf cfg.graphical {
+ environment = {
+ sessionVariables.NIXOS_OZONE_WL = "1";
+
+ systemPackages = with pkgs; [
+ qt5.qtwayland
+ qt6.qtwayland
+ ];
+ };
+
+ hardware.graphics.enable = true;
+
+ programs = {
+ dconf.enable = true;
+
+ gtklock = {
+ enable = true;
+
+ config = {};
+ modules = [];
+ };
+ };
+
+ services = {
+ libinput.enable = true;
+
+ udev.packages = with pkgs; [
+ pkgs.android-udev-rules
+ ];
+
+ xserver = mkIf (!cfg.wayland) {
+ enable = true;
+ videoDrivers = cfg.videoDrivers ++ ["modesetting" "fbdev"];
+ displayManager.startx.enable = mkDefault true;
+ };
+ };
+
+ xdg.portal = {
+ enable = true;
+ wlr.enable = true;
+ extraPortals = [pkgs.xdg-desktop-portal-gtk];
+ xdgOpenUsePortal = true;
+
+ # warning: xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
+ # should either set `xdg.portal.config` or `xdg.portal.configPackages`
+ # to specify which portal backend to use for the requested interface.
+ #
+ # https://github.com/flatpak/xdg-desktop-portal/blob/1.18.1/doc/portals.conf.rst.in
+ #
+ # If you simply want to keep the behaviour in < 1.17, which uses the first
+ # portal implementation found in lexicographical order, use the following:
+ #
+ # xdg.portal.config.common.default = "*";
+ config.common.default = "*";
+ };
+
+ users.groups.adbusers.gid = 1008;
+ })
+ ]);
+}
diff --git a/sys/syncthing/default.nix b/sys/syncthing/default.nix
new file mode 100644
index 0000000..951ad30
--- /dev/null
+++ b/sys/syncthing/default.nix
@@ -0,0 +1,45 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.syncthing;
+in {
+ options.local.syncthing = {
+ enable = mkEnableOption "syncthing server";
+ openFirewall = mkEnableOption "syncthing firewall rules";
+ };
+
+ config = mkMerge [
+ {
+ networking.firewall = {
+ allowedTCPPorts = optional cfg.openFirewall 22000;
+ allowedUDPPorts = optional cfg.openFirewall 22000;
+ };
+ }
+ (mkIf cfg.enable {
+ local.syncthing.openFirewall = true;
+
+ services.syncthing = {
+ enable = true;
+
+ systemService = true;
+ overrideFolders = false;
+ overrideDevices = false;
+ openDefaultPorts = true;
+
+ guiAddress = "127.0.0.1:8384";
+
+ settings.options.urAccepted = -1;
+
+ relay = {
+ enable = true;
+
+ pools = [];
+ providedBy = "${config.networking.hostName}.${config.networking.domain}";
+ };
+ };
+ })
+ ];
+}
diff --git a/sys/virt/default.nix b/sys/virt/default.nix
new file mode 100644
index 0000000..1434bad
--- /dev/null
+++ b/sys/virt/default.nix
@@ -0,0 +1,5 @@
+{
+ imports = [
+ ./libvirt.nix
+ ];
+}
diff --git a/sys/virt/dom/README.md b/sys/virt/dom/README.md
new file mode 100644
index 0000000..37073ba
--- /dev/null
+++ b/sys/virt/dom/README.md
@@ -0,0 +1 @@
+# This directory has been lustrated.
diff --git a/sys/virt/libvirt.nix b/sys/virt/libvirt.nix
new file mode 100644
index 0000000..ebbfbcd
--- /dev/null
+++ b/sys/virt/libvirt.nix
@@ -0,0 +1,64 @@
+{
+ config,
+ flakes,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.local.virt;
+
+ inherit (config.lib.local) importAll;
+
+ doms = mapAttrs (_: dom: dom {inherit config lib pkgs;}) (importAll {root = ./dom;});
+in {
+ options.local.virt = {
+ enable = mkEnableOption "hypervisor support";
+
+ dom =
+ mapAttrs
+ (name: _: {
+ enable = mkEnableOption "domain ${name}";
+ })
+ doms;
+ };
+
+ config = mkIf cfg.enable {
+ local.boot.impermanence.directories = [
+ {
+ directory = "/var/dom";
+ user = "root";
+ group = "qemu-libvirtd";
+ mode = "u=rwx,g=rx,o=";
+ }
+ ];
+
+ virtualisation = {
+ libvirt = {
+ enable = any (dom: dom.enable) (attrValues cfg.dom);
+
+ connections."qemu:///system".domains = let
+ makeDomain = def: {
+ active = true;
+ restart = false;
+ definition = flakes.nixvirt.lib.domain.writeXML def;
+ };
+ in
+ map makeDomain (attrValues (filterAttrs (name: _: cfg.dom.${name}.enable) doms));
+
+ swtpm.enable = true;
+ };
+
+ libvirtd = {
+ enable = true;
+
+ qemu = {
+ runAsRoot = false;
+
+ ovmf.enable = true;
+ swtpm.enable = true;
+ };
+ };
+ };
+ };
+}
diff --git a/sys/web/default.nix b/sys/web/default.nix
new file mode 100644
index 0000000..2fc769f
--- /dev/null
+++ b/sys/web/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./nginx.nix
+ ./php-fpm.nix
+ ./sites
+ ];
+}
diff --git a/sys/web/nginx.nix b/sys/web/nginx.nix
new file mode 100644
index 0000000..a054289
--- /dev/null
+++ b/sys/web/nginx.nix
@@ -0,0 +1,94 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.web;
+ inherit (config.local) domains;
+in {
+ options.local.web = {
+ enable = mkEnableOption "web server";
+
+ defaultACMEHost = mkOption {
+ type = types.str;
+ };
+
+ ownedCerts = mkOption {
+ type = with lib.types; listOf str;
+ default = [];
+ };
+ };
+
+ config = mkIf cfg.enable {
+ services = {
+ fail2ban.jails = {
+ # https://discourse.nixos.org/t/fail2ban-with-nginx-and-authelia/31419
+ nginx-botsearch.settings = {
+ # Usar log en vez de journalctl
+ # TODO: Pasar todo a systemd?
+ backend = "pyinotify";
+ logpath = "/var/log/nginx/*.log";
+ journalmatch = "";
+ };
+
+ nginx-bad-request.settings = {
+ backend = "pyinotify";
+ logpath = "/var/log/nginx/*.log";
+ journalmatch = "";
+
+ maxretry = 10;
+ };
+ };
+
+ nginx = {
+ enable = true;
+
+ recommendedGzipSettings = true;
+ recommendedOptimisation = true;
+ recommendedProxySettings = true;
+ recommendedTlsSettings = true;
+
+ logError = "/var/log/nginx/error.log";
+ sslDhparam = config.security.dhparams.params.nginx.path;
+ clientMaxBodySize = "42M";
+
+ mapHashBucketSize = 128;
+
+ virtualHosts.default = {
+ default = true;
+
+ addSSL = true;
+ useACMEHost = cfg.defaultACMEHost;
+
+ locations."/".extraConfig = ''
+ return 403;
+ '';
+ };
+ };
+ };
+
+ local.certs = listToAttrs (map
+ (name: {
+ inherit name;
+ value.enable = true;
+ })
+ cfg.ownedCerts);
+
+ networking.firewall.allowedTCPPorts = [80 443];
+
+ security = {
+ acme.certs = listToAttrs (map
+ (name: {
+ name = domains.${name}.main;
+ value = {
+ group = mkDefault config.services.nginx.group;
+ reloadServices = ["nginx.service"];
+ };
+ })
+ cfg.ownedCerts);
+
+ dhparams.params.nginx = {};
+ };
+ };
+}
diff --git a/sys/web/php-fpm.nix b/sys/web/php-fpm.nix
new file mode 100644
index 0000000..33efe1a
--- /dev/null
+++ b/sys/web/php-fpm.nix
@@ -0,0 +1,154 @@
+# Based on <https://gist.github.com/aanderse/3344baef2c3b86c8a1e98e63bd9256ea>
+# See also:
+# - <https://albert.cx/20181125-use-separate-systemd-units-for-php-fpm-pools>
+# - <https://freedesktop.org/wiki/Software/systemd/DaemonSocketActivation/>
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}:
+with lib; let
+ cfg = config.services.php-fpm-isolated;
+
+ configFile = {
+ pool,
+ poolOpts,
+ runtimeDir,
+ sockFile,
+ pidFile,
+ }: let
+ config = {
+ global = {
+ daemonize = false;
+ error_log = "syslog";
+ pid = pidFile;
+ };
+
+ "${pool}" = let
+ enforced = {
+ inherit (poolOpts) user group;
+ listen = sockFile;
+ };
+
+ defaults = {
+ "pm" = "dynamic";
+ "pm.max_children" = 16;
+ "pm.min_spare_servers" = 1;
+ "pm.max_spare_servers" = 4;
+ "pm.start_servers" = 1;
+ "catch_workers_output" = true;
+ "php_admin_flag[log_errors]" = true;
+ "env[PATH]" = makeBinPath [pkgs.php];
+ };
+
+ env =
+ mapAttrs'
+ (name: value: {
+ name = "env[${name}]";
+ value = "\"${escape ["\""] value}\"";
+ })
+ poolOpts.env;
+ in
+ defaults // poolOpts.config // env // enforced;
+ };
+ in
+ (pkgs.formats.ini {}).generate "php-fpm-pool-${pool}.conf" config;
+in {
+ options.services.php-fpm-isolated.pools = mkOption {
+ default = {};
+
+ type = with types;
+ attrsOf (submodule {
+ options = {
+ enable = mkEnableOption "PHP-FPM pool";
+
+ user = mkOption {
+ type = str;
+ };
+
+ group = mkOption {
+ type = str;
+ };
+
+ unveil = mkOption {
+ type = listOf (either package str);
+ };
+
+ env = mkOption {
+ type = attrsOf str;
+ default = {};
+ };
+
+ config = mkOption {
+ type = attrsOf (oneOf [int str bool]);
+ default = {};
+ };
+ };
+ });
+ };
+
+ config.systemd = let
+ php-fpm = "${pkgs.php}/bin/php-fpm";
+
+ unitsFor = pool: poolOpts: let
+ runtimeBase = "php-fpm-isolated/${pool}";
+ runtimeDir = "/run/${runtimeBase}";
+ pidFile = "${runtimeDir}/${pool}.pid";
+ sockFile = "${runtimeDir}/${pool}.sock";
+ in {
+ name = "php-fpm-pool-${pool}";
+
+ value.service = {
+ description = "PHP-FPM process manager for pool '${pool}'";
+ after = ["network.target"];
+
+ confinement.enable = true;
+
+ serviceConfig = {
+ Type = "notify";
+ ExecReload = "${pkgs.coreutils}/bin/kill -USR2 $MAINPID";
+ PIDFile = pidFile;
+
+ Environment = "FPM_SOCKETS=${sockFile}=3";
+
+ ExecStart = let
+ fpmConfig = configFile {
+ inherit pool poolOpts runtimeDir sockFile pidFile;
+ };
+ in "${php-fpm} --nodaemonize --fpm-config ${fpmConfig} --pid ${pidFile}";
+
+ PrivateTmp = true;
+ PrivateNetwork = true;
+ PrivateDevices = true;
+ # XXX: We need AF_NETLINK to make the sendmail SUID binary from postfix work
+ RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
+
+ User = poolOpts.user;
+ Group = poolOpts.group;
+ RuntimeDirectory = runtimeBase;
+
+ BindReadOnlyPaths = let
+ unveiled = map builtins.toString poolOpts.unveil;
+ in
+ ["/run/systemd/journal/socket"] ++ unveiled;
+ };
+ };
+
+ value.socket = {
+ description = "PHP-FPM socket for pool '${pool}'";
+ listenStreams = [sockFile];
+
+ socketConfig = {
+ User = poolOpts.user;
+ Group = poolOpts.group;
+ };
+ };
+ };
+
+ units = mapAttrs' unitsFor (filterAttrs (_: pool: pool.enable) cfg.pools);
+ in {
+ sockets = mapAttrs (_: unit: unit.socket) units;
+ services = mapAttrs (_: unit: unit.service) units;
+ };
+}
diff --git a/sys/web/sites/default.nix b/sys/web/sites/default.nix
new file mode 100644
index 0000000..ba2835c
--- /dev/null
+++ b/sys/web/sites/default.nix
@@ -0,0 +1,7 @@
+{
+ imports = [
+ ./home.nix
+ ./host.nix
+ ./portal.nix
+ ];
+}
diff --git a/sys/web/sites/home.nix b/sys/web/sites/home.nix
new file mode 100644
index 0000000..fed9b84
--- /dev/null
+++ b/sys/web/sites/home.nix
@@ -0,0 +1,38 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.web.sites.home;
+ inherit (config.local) domains;
+in {
+ options.local.web.sites.home = {
+ enable = mkEnableOption "home site";
+
+ proxyUrl = mkOption {
+ type = types.str;
+ };
+ };
+
+ config = mkIf cfg.enable {
+ local.web = {
+ enable = mkDefault true;
+ ownedCerts = ["home"];
+ };
+
+ services.nginx.virtualHosts.${domains.home.main} = {
+ forceSSL = true;
+ useACMEHost = domains.home.main;
+
+ locations."/".extraConfig = ''
+ proxy_pass ${cfg.proxyUrl};
+ proxy_redirect http:// https://;
+
+ # Necesario debido a websockets
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection $connection_upgrade;
+ '';
+ };
+ };
+}
diff --git a/sys/web/sites/host.nix b/sys/web/sites/host.nix
new file mode 100644
index 0000000..ea6cc23
--- /dev/null
+++ b/sys/web/sites/host.nix
@@ -0,0 +1,106 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.web.sites.host;
+
+ inherit (config.local) domains;
+ inherit (config.local.net) hostname;
+
+ users = filterAttrs (_: user: user.install) config.local.users;
+ hostDomain = domains.${hostDomainName};
+ hostDomainName = "host-${hostname}";
+
+ userCerts = flatten (flatten (mapAttrsToList
+ (name: user:
+ map
+ (cert: {
+ fprint = config.local.pki.byPath.${cert}.fingerprint.sha1-lower;
+ inherit name;
+ })
+ user.mail.certs)
+ users));
+in {
+ options.local.web.sites.host = {
+ enable = mkEnableOption "host site, restricted to per-user client certs";
+ };
+
+ config = mkIf cfg.enable {
+ local.web = {
+ enable = mkDefault true;
+ ownedCerts = [hostDomainName];
+ };
+
+ services = {
+ nginx = {
+ appendHttpConfig = ''
+ map $ssl_client_fingerprint $host_user_from_fprint {
+ default "";
+ ${concatMapStringsSep "\n " (pair: "\"${escapeRegex pair.fprint}\" \"${pair.name}\";") userCerts}
+ }
+ '';
+
+ virtualHosts = {
+ ${hostDomain.main} = {
+ forceSSL = true;
+ useACMEHost = hostDomain.main;
+
+ extraConfig = ''
+ ssl_verify_depth 2;
+ ssl_verify_client optional;
+ ssl_client_certificate ${config.local.pki.ca.mail.fullchain};
+
+ #if ($ssl_client_verify != "SUCCESS") {
+ #return 403;
+ #}
+ '';
+
+ locations =
+ {
+ "/".return = 403;
+ }
+ // concatMapAttrs
+ (name: user: let
+ userLocation = config: {
+ extraConfig =
+ ''
+ if ($host_user_from_fprint != "${name}") {
+ return 403;
+ }
+ ''
+ + config;
+ };
+
+ userLocations =
+ {
+ "/${name}" = ''
+ return 404;
+ '';
+ }
+ // optionalAttrs user.mail.dav {
+ "/${name}/dav" = ''
+ proxy_pass http://unix:/run/host-www/${name}/dav.sock;
+ '';
+ };
+ in
+ mapAttrs (_: userLocation) userLocations)
+ (filterAttrs (_: user: user.mail.certs != []) users);
+ };
+ };
+ };
+ };
+
+ systemd.tmpfiles.settings."10-run-host-www" =
+ concatMapAttrs
+ (name: _: {
+ "/run/host-www/${name}".d = {
+ mode = "0750";
+ user = name;
+ group = "nginx";
+ };
+ })
+ users;
+ };
+}
diff --git a/sys/web/sites/portal.nix b/sys/web/sites/portal.nix
new file mode 100644
index 0000000..93b01bd
--- /dev/null
+++ b/sys/web/sites/portal.nix
@@ -0,0 +1,40 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ cfg = config.local.web.sites.portal;
+ inherit (config.local) domains;
+in {
+ options.local.web.sites.portal = {
+ enable = mkEnableOption "public non-fqdn portal";
+ };
+
+ config = mkIf cfg.enable {
+ local.web = {
+ enable = mkDefault true;
+ ownedCerts = ["host" "sysret"];
+ defaultACMEHost = domains.host.main;
+ };
+
+ services.nginx.virtualHosts = {
+ ${domains.host.www} = {
+ forceSSL = true;
+ useACMEHost = domains.host.main;
+ serverAliases = [domains.host.main];
+ };
+
+ ${domains.sysret.main} = {
+ forceSSL = true;
+ useACMEHost = domains.sysret.main;
+ serverAliases = [domains.sysret.www];
+
+ locations = {
+ "/fsociety".return = "301 https://meet.posixlycorrect.com/%C6%92%C6%A8%C5%8F%C4%8B%D3%80%C9%99%CF%AE%D0%A3";
+ "/.well-known/openpgpkey/hu/".alias = "/var/lib/pgp-wkd/";
+ };
+ };
+ };
+ };
+}
diff --git a/sysret.org/.gitignore b/sysret.org/.gitignore
new file mode 100644
index 0000000..46f5006
--- /dev/null
+++ b/sysret.org/.gitignore
@@ -0,0 +1 @@
+public/*
diff --git a/config.toml b/sysret.org/config.toml
index db3554d..db3554d 100644
--- a/config.toml
+++ b/sysret.org/config.toml
diff --git a/trivionomicon/.gitignore b/trivionomicon/.gitignore
new file mode 100644
index 0000000..f094862
--- /dev/null
+++ b/trivionomicon/.gitignore
@@ -0,0 +1,2 @@
+!**/.keep
+result
diff --git a/trivionomicon/COPYING b/trivionomicon/COPYING
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/trivionomicon/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/trivionomicon/README.md b/trivionomicon/README.md
new file mode 100644
index 0000000..aced5a2
--- /dev/null
+++ b/trivionomicon/README.md
@@ -0,0 +1,8 @@
+### Push:
+
+ git subtree push --prefix=trivionomicon forgejo@git.posixlycorrect.com:deepState/trivionomicon.git master
+
+
+### Pull:
+
+ git subtree pull --prefix=trivionomicon forgejo@git.posixlycorrect.com:deepState/trivionomicon.git master
diff --git a/trivionomicon/doctrine/default.nix b/trivionomicon/doctrine/default.nix
new file mode 100644
index 0000000..0d50d49
--- /dev/null
+++ b/trivionomicon/doctrine/default.nix
@@ -0,0 +1,16 @@
+{
+ lib ? pkgs.lib,
+ pkgs,
+ prefix ? "trivium",
+ namespace ? null,
+}: let
+ doctrine =
+ {
+ lib = import ./lib {inherit lib pkgs doctrine;};
+ inherit namespace prefix;
+ }
+ // lib.optionalAttrs (pkgs != null) {
+ inherit pkgs;
+ };
+in
+ doctrine
diff --git a/trivionomicon/doctrine/lib/default.nix b/trivionomicon/doctrine/lib/default.nix
new file mode 100644
index 0000000..e2d84b8
--- /dev/null
+++ b/trivionomicon/doctrine/lib/default.nix
@@ -0,0 +1,23 @@
+{
+ lib,
+ doctrine,
+ pkgs,
+}: let
+ close = vars: f: args:
+ (
+ if builtins.isPath f
+ then import f
+ else f
+ )
+ (args // vars);
+
+ closeLib = close {inherit lib;};
+ closeFull = close {inherit lib pkgs doctrine;};
+in
+ {
+ inherit close;
+ importAll = closeLib ./import-all.nix;
+ }
+ // lib.optionalAttrs (doctrine.namespace != null) {
+ mkModule = closeFull ./mk-module.nix;
+ }
diff --git a/trivionomicon/doctrine/lib/import-all.nix b/trivionomicon/doctrine/lib/import-all.nix
new file mode 100644
index 0000000..423dd9c
--- /dev/null
+++ b/trivionomicon/doctrine/lib/import-all.nix
@@ -0,0 +1,21 @@
+{
+ lib,
+ root,
+ exclude ? ["default"],
+}:
+with builtins;
+with lib;
+# http://chriswarbo.net/projects/nixos/useful_hacks.html
+ let
+ basename = removeSuffix ".nix";
+
+ isMatch = name: type:
+ (hasSuffix ".nix" name || type == "directory")
+ && ! elem (basename name) exclude;
+
+ entry = name: _: {
+ name = basename name;
+ value = import (root + "/${name}");
+ };
+ in
+ mapAttrs' entry (filterAttrs isMatch (readDir root))
diff --git a/trivionomicon/doctrine/lib/mk-module.nix b/trivionomicon/doctrine/lib/mk-module.nix
new file mode 100644
index 0000000..ffbe6bc
--- /dev/null
+++ b/trivionomicon/doctrine/lib/mk-module.nix
@@ -0,0 +1,51 @@
+{
+ # The first few arguments are implicitly passed by the 'close' helper
+ lib,
+ pkgs,
+ doctrine,
+ name,
+ config,
+ hm ? null,
+ sys ? null,
+ options ? null,
+ requires ? [],
+ prefix ? doctrine.prefix,
+ namespace ? doctrine.namespace,
+ passthru ? {},
+}: let
+ optionsSet = import options (passthru
+ // {
+ inherit config lib pkgs cfg name doctrine;
+ });
+
+ configSet = import configFiles.${namespace} (passthru
+ // {
+ inherit config lib pkgs doctrine cfg;
+ });
+
+ configFiles = lib.filterAttrs (k: v: v != null) {
+ inherit sys hm;
+ };
+
+ cfg = config.${prefix}.${name};
+in {
+ config =
+ lib.optionalAttrs (configFiles ? ${namespace})
+ (lib.mkIf cfg.enable (lib.mkMerge [
+ configSet
+ {
+ assertions =
+ map (dependency: {
+ assertion = cfg.enable -> config.${prefix}.${dependency}.enable;
+ message = "${prefix}.${name}.enable requires ${prefix}.${dependency}.enable";
+ })
+ requires;
+ }
+ ]));
+
+ options.${prefix}.${name} =
+ lib.optionalAttrs (options != null && optionsSet ? ${namespace}) optionsSet.${namespace}
+ // {
+ enable = lib.mkEnableOption name;
+ };
+}
diff --git a/trivionomicon/flake.lock b/trivionomicon/flake.lock
new file mode 100644
index 0000000..8730827
--- /dev/null
+++ b/trivionomicon/flake.lock
@@ -0,0 +1,61 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": "systems"
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1754292888,
+ "narHash": "sha256-1ziydHSiDuSnaiPzCQh1mRFBsM2d2yRX9I+5OPGEmIE=",
+ "owner": "nixos",
+ "repo": "nixpkgs",
+ "rev": "ce01daebf8489ba97bd1609d185ea276efdeb121",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nixos",
+ "ref": "nixos-25.05",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/trivionomicon/flake.nix b/trivionomicon/flake.nix
new file mode 100644
index 0000000..2b53ebd
--- /dev/null
+++ b/trivionomicon/flake.nix
@@ -0,0 +1,229 @@
+{
+ inputs = {
+ flake-utils.url = "github:numtide/flake-utils";
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
+ };
+
+ outputs = {
+ self,
+ nixpkgs,
+ flake-utils,
+ }: let
+ mapOverlayOverride = prefix: overlay: final: prev: let
+ overlayPkgs = overlay final prev;
+ in
+ {
+ "${prefix}" = (prev.${prefix} or {}) // builtins.removeAttrs overlayPkgs ["override"];
+ }
+ // (overlayPkgs.override or {});
+
+ doctrineNoPkgs = self.lib.mkDoctrine {
+ lib = nixpkgs.lib;
+ pkgs = null;
+ };
+ in
+ flake-utils.lib.eachDefaultSystem (system: let
+ pkgs = import nixpkgs {inherit system;};
+ in {
+ formatter = pkgs.alejandra;
+
+ packages =
+ (import nixpkgs {
+ inherit system;
+ overlays = [self.overlays.default];
+ }).${
+ doctrineNoPkgs.prefix
+ };
+ })
+ // {
+ templates = let
+ system-flake = {
+ path = ./templates/system-flake;
+ description = "Opinionated flake for a NixOS system with Home Manager";
+ };
+ in {
+ inherit system-flake;
+
+ default = system-flake;
+ };
+
+ overlays = let
+ overlay = mapOverlayOverride doctrineNoPkgs.prefix (import ./pkgs);
+ in {
+ default = overlay;
+ ${doctrineNoPkgs.prefix} = overlay;
+ };
+
+ homeManagerModules.default = ./modules;
+ nixosModules.default = ./modules;
+
+ lib = {
+ mkDoctrine = import ./doctrine;
+
+ mkSystemFlake = {
+ flakes,
+ system,
+ doctrinePrefix ? null,
+ formatter ? "alejandra",
+ paths ? {},
+ }: let
+ mkDoctrine = args:
+ self.lib.mkDoctrine
+ (args
+ // optionalAttrs (doctrinePrefix != null) {
+ prefix = doctrinePrefix;
+ });
+
+ doctrineNoPkgs = mkDoctrine {
+ lib = nixpkgs.lib;
+ pkgs = null;
+ };
+
+ optionalFlake = name:
+ if flakes ? "${name}"
+ then flakes.${name}
+ else null;
+
+ requireFlake = name:
+ if flakes ? "${name}"
+ then flakes.${name}
+ else throw "Required flake input '${name}' is missing";
+
+ nur = optionalFlake "nur";
+ nixpkgs = requireFlake "nixpkgs";
+ unstable = optionalFlake "unstable";
+
+ home-manager =
+ if hmSourcePath != null
+ then requireFlake "home-manager"
+ else null;
+
+ pathFromSelf = path: builtins.toPath "${flakes.self}" + "/${path}";
+
+ localOverlayPath = pathFromSelf paths.localOverlay;
+ nixpkgsConfigPath = pathFromSelf paths.nixpkgsConfig;
+ nixosSourcePath = pathFromSelf paths.nixosSource;
+ nixosPlatformsPath = pathFromSelf paths.nixosPlatforms;
+ hmSourcePath = pathFromSelf paths.hmSource;
+ hmPlatformsPath = pathFromSelf paths.hmPlatforms;
+
+ pkgs = importPkgs nixpkgs;
+
+ importPkgs = flake:
+ import flake ({
+ inherit system;
+
+ overlays = let
+ conditions = [
+ {
+ overlay = nur.overlays.default;
+ condition = nur != null;
+ }
+ # NB: Preserve the relative order
+ {
+ overlay = mapOverlayOverride prefix (import ./pkgs);
+ condition = true;
+ }
+ {
+ overlay = flakes.self.overlays.default;
+ condition = true;
+ }
+ ];
+ in
+ builtins.map (cond: cond.overlay) (builtins.filter (cond: cond.condition) conditions);
+ }
+ // optionalAttrs (paths ? nixpkgsConfig) {
+ config = import nixpkgsConfigPath {inherit (nixpkgs) lib;};
+ });
+
+ inherit (pkgs) lib;
+ inherit (nixpkgs.lib) optionalAttrs; # Prevents infinite recursion
+ inherit (doctrineNoPkgs) prefix;
+ inherit (doctrineNoPkgs.lib) importAll;
+ in
+ {
+ formatter.${system} =
+ if formatter == "alejandra"
+ then pkgs.alejandra
+ else if formatter == "nixpkgs-fmt"
+ then pkgs.nixpkgs-fmt
+ else throw "Unknown formatter: '${formatter}'";
+
+ packages.${system} = pkgs.${prefix};
+
+ overlays.default = final: prev: let
+ overlay = final: prev:
+ if paths ? localOverlay
+ then import localOverlayPath {inherit final prev flakes;}
+ else {};
+ in
+ mapOverlayOverride prefix overlay final prev
+ // optionalAttrs (unstable != null) {
+ unstable = importPkgs unstable;
+ };
+ }
+ // optionalAttrs (paths ? nixosSource) {
+ nixosConfigurations = let
+ hostConfig = platform:
+ self.lib.mkSystem {
+ inherit flakes pkgs;
+ doctrine = doctrineNoPkgs;
+
+ modules = [
+ nixosSourcePath
+ platform
+ ];
+ };
+ in
+ lib.mapAttrs (_: hostConfig) (importAll {root = nixosPlatformsPath;});
+ }
+ // optionalAttrs (paths ? hmSource) {
+ homeConfigurations = let
+ home = name: platform:
+ home-manager.lib.homeManagerConfiguration {
+ inherit pkgs;
+
+ extraSpecialArgs = {
+ inherit flakes;
+
+ doctrine = mkDoctrine {
+ inherit pkgs;
+ namespace = "hm";
+ };
+ };
+
+ modules = [
+ self.homeManagerModules.default
+ hmSourcePath
+ platform
+ ];
+ };
+ in
+ lib.mapAttrs home (importAll {root = hmPlatformsPath;});
+ };
+
+ mkSystem = {
+ pkgs,
+ flakes,
+ doctrine,
+ modules,
+ }:
+ flakes.nixpkgs.lib.makeOverridable flakes.nixpkgs.lib.nixosSystem {
+ inherit pkgs;
+ inherit (pkgs) system;
+
+ modules = [self.nixosModules.default] ++ modules;
+
+ specialArgs = {
+ inherit flakes;
+
+ doctrine = self.lib.mkDoctrine {
+ inherit pkgs;
+ inherit (doctrine) prefix;
+ namespace = "sys";
+ };
+ };
+ };
+ };
+ };
+}
diff --git a/trivionomicon/modules/athena-bccr/default.nix b/trivionomicon/modules/athena-bccr/default.nix
new file mode 100644
index 0000000..93c5660
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/default.nix
@@ -0,0 +1,14 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "athena-bccr";
+ hm = ./hm.nix;
+ sys = ./sys.nix;
+ options = ./options.nix;
+}
diff --git a/trivionomicon/modules/athena-bccr/hm.nix b/trivionomicon/modules/athena-bccr/hm.nix
new file mode 100644
index 0000000..0678e3c
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/hm.nix
@@ -0,0 +1,14 @@
+{
+ pkgs,
+ lib,
+ cfg,
+ doctrine,
+ ...
+}: let
+ athena = pkgs.${doctrine.prefix}.athena-bccr.${cfg.release};
+in {
+ home.packages = [
+ athena.firmador
+ (athena.gaudi.override {inherit (cfg) gaudiHash;})
+ ];
+}
diff --git a/trivionomicon/modules/athena-bccr/options.nix b/trivionomicon/modules/athena-bccr/options.nix
new file mode 100644
index 0000000..eb61cf5
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/options.nix
@@ -0,0 +1,30 @@
+{lib, ...}:
+with lib.types; {
+ hm = {
+ gaudiHash = lib.mkOption {
+ type = nullOr str;
+ default = null;
+ description = "hash of the Gaudi client";
+ };
+
+ release = lib.mkOption {
+ type = str;
+ default = "latest";
+ description = "pinned athena-bccr release tag";
+ };
+ };
+
+ sys = {
+ group = lib.mkOption {
+ type = str;
+ default = "users";
+ description = "user group with full access to the smartcard reader";
+ };
+
+ release = lib.mkOption {
+ type = str;
+ default = "latest";
+ description = "pinned athena-bccr release tag";
+ };
+ };
+}
diff --git a/trivionomicon/modules/athena-bccr/sys.nix b/trivionomicon/modules/athena-bccr/sys.nix
new file mode 100644
index 0000000..631185d
--- /dev/null
+++ b/trivionomicon/modules/athena-bccr/sys.nix
@@ -0,0 +1,35 @@
+{
+ pkgs,
+ lib,
+ cfg,
+ doctrine,
+ ...
+}: let
+ athena = pkgs.${doctrine.prefix}.athena-bccr.${cfg.release};
+in {
+ environment = {
+ etc = {
+ "Athena".source = "${athena.ase-pkcs11}/etc/Athena";
+
+ "pkcs11/modules/asep11".text = ''
+ module: ${athena.libasep11}
+ '';
+ };
+
+ systemPackages = [athena.ase-pkcs11];
+ };
+
+ #FIXME: Extremadamente peligroso si BCCR o MICITT caen, investigar política nacional de root CA
+ security.pki.certificateFiles = ["${athena.bccr-cacerts}/root-ca.pem"];
+
+ services = {
+ pcscd.enable = true;
+
+ udev.extraRules = ''
+ # Athena Smartcard Solutions, Inc. ASEDrive V3CR
+ ATTRS{idVendor}=="0dc3", ATTRS{idProduct}=="1004", MODE="660", GROUP="${cfg.group}", TAG+="uaccess"
+ '';
+ };
+
+ users.groups.${cfg.group} = {};
+}
diff --git a/trivionomicon/modules/default.nix b/trivionomicon/modules/default.nix
new file mode 100644
index 0000000..0c0fd4c
--- /dev/null
+++ b/trivionomicon/modules/default.nix
@@ -0,0 +1,3 @@
+{doctrine, ...}: {
+ imports = builtins.attrValues (doctrine.lib.importAll {root = ./.;});
+}
diff --git a/trivionomicon/modules/laptop/default.nix b/trivionomicon/modules/laptop/default.nix
new file mode 100644
index 0000000..b908d47
--- /dev/null
+++ b/trivionomicon/modules/laptop/default.nix
@@ -0,0 +1,10 @@
+{
+ config,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "laptop";
+ sys = ./sys.nix;
+}
diff --git a/trivionomicon/modules/laptop/sys.nix b/trivionomicon/modules/laptop/sys.nix
new file mode 100644
index 0000000..252f49c
--- /dev/null
+++ b/trivionomicon/modules/laptop/sys.nix
@@ -0,0 +1,11 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: {
+ services = {
+ tlp.enable = lib.mkDefault true;
+ upower.enable = lib.mkDefault true;
+ };
+}
diff --git a/trivionomicon/modules/nix-registry/default.nix b/trivionomicon/modules/nix-registry/default.nix
new file mode 100644
index 0000000..8406d88
--- /dev/null
+++ b/trivionomicon/modules/nix-registry/default.nix
@@ -0,0 +1,16 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ flakes,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "nix-registry";
+ hm = ./hm.nix;
+ options = ./options.nix;
+
+ passthru = {inherit flakes;};
+}
diff --git a/trivionomicon/modules/nix-registry/hm.nix b/trivionomicon/modules/nix-registry/hm.nix
new file mode 100644
index 0000000..1c57e95
--- /dev/null
+++ b/trivionomicon/modules/nix-registry/hm.nix
@@ -0,0 +1,23 @@
+{
+ pkgs,
+ lib,
+ cfg,
+ flakes,
+ ...
+}: let
+ registryName = name:
+ if name == "self"
+ then cfg.renameSelf
+ else name;
+
+ registryFilter = {
+ nixpkgs = true;
+ unstable = true;
+ self = cfg.renameSelf != null;
+ };
+in {
+ nix.registry =
+ lib.mapAttrs'
+ (name: value: lib.nameValuePair (registryName name) {flake = value;})
+ (lib.filterAttrs (name: _: registryFilter.${name} or cfg.allInputs) flakes);
+}
diff --git a/trivionomicon/modules/nix-registry/options.nix b/trivionomicon/modules/nix-registry/options.nix
new file mode 100644
index 0000000..e8898ec
--- /dev/null
+++ b/trivionomicon/modules/nix-registry/options.nix
@@ -0,0 +1,19 @@
+{lib, ...}:
+with lib.types; {
+ hm = {
+ allInputs = mkOption {
+ type = bool;
+ default = default;
+ description = ''
+ Include all flake inputs. If false, only 'nixpkgs' and 'unstable'
+ (if available) will be added to the flake registry by default.
+ '';
+ };
+
+ renameSelf = mkOption {
+ type = nullOr str;
+ default = "self";
+ description = "Registry name to use for the 'self' input";
+ };
+ };
+}
diff --git a/trivionomicon/modules/sway/default.nix b/trivionomicon/modules/sway/default.nix
new file mode 100644
index 0000000..9f49e7c
--- /dev/null
+++ b/trivionomicon/modules/sway/default.nix
@@ -0,0 +1,13 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "sway";
+ sys = ./sys.nix;
+ options = ./options.nix;
+}
diff --git a/trivionomicon/modules/sway/options.nix b/trivionomicon/modules/sway/options.nix
new file mode 100644
index 0000000..e433039
--- /dev/null
+++ b/trivionomicon/modules/sway/options.nix
@@ -0,0 +1,3 @@
+{...}: {
+ sys = {};
+}
diff --git a/trivionomicon/modules/sway/sys.nix b/trivionomicon/modules/sway/sys.nix
new file mode 100644
index 0000000..9c8b664
--- /dev/null
+++ b/trivionomicon/modules/sway/sys.nix
@@ -0,0 +1,45 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ services.libinput.enable = true;
+ hardware.graphics.enable = true;
+
+ xdg.portal = {
+ enable = true;
+ wlr.enable = true;
+ extraPortals = with pkgs; [xdg-desktop-portal-gtk];
+ xdgOpenUsePortal = true;
+
+ # warning: xdg-desktop-portal 1.17 reworked how portal implementations are loaded, you
+ # should either set `xdg.portal.config` or `xdg.portal.configPackages`
+ # to specify which portal backend to use for the requested interface.
+ #
+ # https://github.com/flatpak/xdg-desktop-portal/blob/1.18.1/doc/portals.conf.rst.in
+ #
+ # If you simply want to keep the behaviour in < 1.17, which uses the first
+ # portal implementation found in lexicographical order, use the following:
+ #
+ # xdg.portal.config.common.default = "*";
+ config.common.default = "*";
+ };
+
+ environment = {
+ sessionVariables.NIXOS_OZONE_WL = "1";
+
+ systemPackages = with pkgs; [
+ qt5.qtwayland
+ qt6.qtwayland
+ ];
+ };
+
+ programs = {
+ gtklock = {
+ enable = lib.mkDefault true;
+
+ config = {};
+ modules = [];
+ };
+ };
+}
diff --git a/trivionomicon/modules/thinkpad/default.nix b/trivionomicon/modules/thinkpad/default.nix
new file mode 100644
index 0000000..e210947
--- /dev/null
+++ b/trivionomicon/modules/thinkpad/default.nix
@@ -0,0 +1,11 @@
+{
+ config,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "thinkpad";
+ sys = ./sys.nix;
+ requires = ["laptop"];
+}
diff --git a/trivionomicon/modules/thinkpad/sys.nix b/trivionomicon/modules/thinkpad/sys.nix
new file mode 100644
index 0000000..bc96146
--- /dev/null
+++ b/trivionomicon/modules/thinkpad/sys.nix
@@ -0,0 +1,30 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: {
+ # For suspending to RAM to work, set Config -> Power -> Sleep State to "Linux" in EFI.
+ # See https://wiki.archlinux.org/index.php/Lenovo_ThinkPad_X1_Carbon_(Gen_6)#Suspend_issues
+ # Fingerprint sensor requires a firmware-update to work.
+
+ boot = {
+ extraModulePackages = with config.boot.kernelPackages; [acpi_call];
+ extraModprobeConfig = "options iwlwifi 11n_disable=1 wd_disable=1";
+
+ # acpi_call makes tlp work for newer thinkpads
+ kernelModules = ["acpi_call"];
+
+ # Force use of the thinkpad_acpi driver for backlight control.
+ # This allows the backlight save/load systemd service to work.
+ kernelParams = ["acpi_backlight=native"];
+ };
+
+ hardware.firmware = [pkgs.sof-firmware];
+
+ services = {
+ fprintd.enable = lib.mkDefault true;
+ thinkfan.enable = lib.mkDefault true;
+ tp-auto-kbbl.enable = lib.mkDefault true;
+ };
+}
diff --git a/trivionomicon/modules/trivionomiconMotd/default.nix b/trivionomicon/modules/trivionomiconMotd/default.nix
new file mode 100644
index 0000000..0844b5a
--- /dev/null
+++ b/trivionomicon/modules/trivionomiconMotd/default.nix
@@ -0,0 +1,10 @@
+{
+ config,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "trivionomiconMotd";
+ sys = ./sys.nix;
+}
diff --git a/trivionomicon/modules/trivionomiconMotd/sys.nix b/trivionomicon/modules/trivionomiconMotd/sys.nix
new file mode 100644
index 0000000..5b38e3d
--- /dev/null
+++ b/trivionomicon/modules/trivionomiconMotd/sys.nix
@@ -0,0 +1,22 @@
+{
+ config,
+ lib,
+ pkgs,
+ ...
+}: {
+ users.motd = ''
+ _ _ _ _
+ | | | | | | | |
+ _ __ _____ _____ _ __ ___ __| | | |__ _ _ | |_| |__ ___
+ | '_ \ / _ \ \ /\ / / _ \ '__/ _ \/ _` | | '_ \| | | | | __| '_ \ / _ \
+ | |_) | (_) \ V V / __/ | | __/ (_| | | |_) | |_| | | |_| | | | __/
+ | .__/ \___/ \_/\_/ \___|_| \___|\__,_| |_.__/ \__, | \__|_| |_|\___|
+ | | __/ |
+ |_|_____ _____ _______ _______ ____ _ _|___/_ __ __ _____ _____ ____ _ _
+ |__ __| __ \|_ _\ \ / /_ _/ __ \| \ | |/ __ \| \/ |_ _/ ____/ __ \| \ | |
+ | | | |__) | | | \ \ / / | || | | | \| | | | | \ / | | || | | | | | \| |
+ | | | _ / | | \ \/ / | || | | | . ` | | | | |\/| | | || | | | | | . ` |
+ | | | | \ \ _| |_ \ / _| || |__| | |\ | |__| | | | |_| || |___| |__| | |\ |
+ |_| |_| \_\_____| \/ |_____\____/|_| \_|\____/|_| |_|_____\_____\____/|_| \_|
+ '';
+}
diff --git a/trivionomicon/modules/yubico/default.nix b/trivionomicon/modules/yubico/default.nix
new file mode 100644
index 0000000..71bed70
--- /dev/null
+++ b/trivionomicon/modules/yubico/default.nix
@@ -0,0 +1,13 @@
+{
+ config,
+ lib,
+ pkgs,
+ doctrine,
+ ...
+}:
+doctrine.lib.mkModule {
+ inherit config;
+ name = "yubico";
+ hm = ./hm.nix;
+ sys = ./sys.nix;
+}
diff --git a/trivionomicon/modules/yubico/hm.nix b/trivionomicon/modules/yubico/hm.nix
new file mode 100644
index 0000000..8d06368
--- /dev/null
+++ b/trivionomicon/modules/yubico/hm.nix
@@ -0,0 +1,9 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ home.packages = [
+ pkgs.yubikey-manager
+ ];
+}
diff --git a/trivionomicon/modules/yubico/sys.nix b/trivionomicon/modules/yubico/sys.nix
new file mode 100644
index 0000000..3cd009f
--- /dev/null
+++ b/trivionomicon/modules/yubico/sys.nix
@@ -0,0 +1,14 @@
+{
+ pkgs,
+ lib,
+ ...
+}: {
+ environment.etc."pkcs11/modules/ykcs11".text = ''
+ module: ${pkgs.yubico-piv-tool}/lib/libykcs11.so
+ '';
+
+ services = {
+ pcscd.enable = true;
+ udev.packages = [pkgs.yubikey-personalization];
+ };
+}
diff --git a/trivionomicon/pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch b/trivionomicon/pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch
new file mode 100644
index 0000000..e7fc5d5
--- /dev/null
+++ b/trivionomicon/pkgs/athena-bccr/0001-Remove-CheckUpdatePlugin-from-default-list.patch
@@ -0,0 +1,25 @@
+From 5e7eb46f46af6a29a2aea19db722ebc28baede25 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sat, 21 Jun 2025 22:37:19 -0600
+Subject: [PATCH] Remove CheckUpdatePlugin from default list
+
+---
+ src/main/java/cr/libre/firmador/Settings.java | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/main/java/cr/libre/firmador/Settings.java b/src/main/java/cr/libre/firmador/Settings.java
+index e5ddf01..a028d6e 100644
+--- a/src/main/java/cr/libre/firmador/Settings.java
++++ b/src/main/java/cr/libre/firmador/Settings.java
+@@ -81,7 +81,7 @@ public class Settings {
+
+ public Settings() {
+ activePlugins.add("cr.libre.firmador.plugins.DummyPlugin");
+- activePlugins.add("cr.libre.firmador.plugins.CheckUpdatePlugin");
++ // activePlugins.add("cr.libre.firmador.plugins.CheckUpdatePlugin");
+ availablePlugins.add("cr.libre.firmador.plugins.DummyPlugin");
+ availablePlugins.add("cr.libre.firmador.plugins.CheckUpdatePlugin");
+ }
+--
+2.49.0
+
diff --git a/trivionomicon/pkgs/athena-bccr/LaunchGaudi.java b/trivionomicon/pkgs/athena-bccr/LaunchGaudi.java
new file mode 100644
index 0000000..e4bcdbf
--- /dev/null
+++ b/trivionomicon/pkgs/athena-bccr/LaunchGaudi.java
@@ -0,0 +1,12 @@
+// Los del BCCR no se molestaron en ponerle un main al Agente Gaudi porque el
+// actualizador (que a su vez sí tiene main) carga el jar en memoria y crea una
+// instancia de Inicializador usando reflexión. El actualizador no es relevante
+// en Nix. En todo caso, dicho actualizador es sumamente frágil y me daría
+// demasiada pereza arreglarlo, así que en su lugar usamos este stub para
+// launchear Gaudi.
+
+public class LaunchGaudi {
+ public static void main(String[] args) {
+ new InicializadorCliente.Inicializador("");
+ }
+}
diff --git a/trivionomicon/pkgs/athena-bccr/default.nix b/trivionomicon/pkgs/athena-bccr/default.nix
new file mode 100644
index 0000000..a5f79ca
--- /dev/null
+++ b/trivionomicon/pkgs/athena-bccr/default.nix
@@ -0,0 +1,30 @@
+{
+ callPackage,
+ lib,
+}: let
+ latest = "deb64-rev26";
+
+ releases = lib.mapAttrs (name: release: release // {name = name;}) (import ./releases.nix);
+
+ overrideUnwrapped = default: new: let
+ args = default // new;
+ unwrappedPkgs = lib.filterAttrs (name: _: ! lib.elem name ["override" "overrideDerivation"]) (callPackage ./unwrapped.nix args);
+ in
+ lib.fix (unwrapped: lib.mapAttrs (_: pkg: callPackage pkg unwrapped) unwrappedPkgs)
+ // {
+ override = overrideUnwrapped args;
+ };
+
+ pkgsForRelease = release: let
+ ase-pkcs11 = unwrapped.ase-idprotect.lib;
+ libasep11 = "${ase-pkcs11}/lib/x64-athena/libASEP11.so";
+ unwrapped = overrideUnwrapped {inherit release;} {};
+ in {
+ inherit ase-pkcs11 libasep11;
+ inherit (unwrapped) ase-idprotect bccr-cacerts;
+
+ gaudi = callPackage ./gaudi-env.nix {inherit unwrapped;};
+ firmador = callPackage ./firmador.nix {inherit libasep11;};
+ };
+in
+ lib.mapAttrs (_: pkgsForRelease) (releases // {latest = releases.${latest};})
diff --git a/trivionomicon/pkgs/athena-bccr/firmador.nix b/trivionomicon/pkgs/athena-bccr/firmador.nix
new file mode 100644
index 0000000..d280b56
--- /dev/null
+++ b/trivionomicon/pkgs/athena-bccr/firmador.nix
@@ -0,0 +1,57 @@
+{
+ fetchgit,
+ lib,
+ makeWrapper,
+ maven,
+ openjdk,
+ wrapGAppsHook,
+ libasep11 ? null,
+}: let
+ jdk = openjdk.override {
+ enableJavaFX = true;
+ };
+
+ version = "1.9.8";
+in
+ maven.buildMavenPackage {
+ pname = "firmador";
+ inherit version;
+
+ src = fetchgit {
+ url = "https://codeberg.org/firmador/firmador";
+ rev = version;
+ hash = "sha256-xdiVPjihRADPK4nG+WQHWsDzVYLCeN6ouQ6SDtjf1qQ=";
+ };
+
+ patches = [
+ ./0001-Remove-CheckUpdatePlugin-from-default-list.patch
+ ];
+
+ mvnHash = "sha256-h1zoStTgaE7toWWKq0Y0ahOORyltChwjmaMYjLgs1VE=";
+
+ nativeBuildInputs = [
+ makeWrapper
+ wrapGAppsHook
+ ];
+
+ postPatch = lib.optionalString (libasep11 != null) ''
+ sed -i 's@/usr/lib/x64-athena/libASEP11.so@${libasep11}@g' src/main/java/cr/libre/firmador/CRSigner.java
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ mkdir -p $out/bin $out/share/java
+ install -Dm644 target/firmador.jar $out/share/java
+
+ makeWrapper ${jdk}/bin/java $out/bin/firmador \
+ --add-flags "-jar $out/share/java/firmador.jar"
+
+ runHook postInstall
+ '';
+
+ meta = {
+ homepage = "https://firmador.libre.cr";
+ license = lib.licenses.gpl3Plus;
+ };
+ }
diff --git a/trivionomicon/pkgs/athena-bccr/gaudi-env.nix b/trivionomicon/pkgs/athena-bccr/gaudi-env.nix
new file mode 100644
index 0000000..0ca1b82
--- /dev/null
+++ b/trivionomicon/pkgs/athena-bccr/gaudi-env.nix
@@ -0,0 +1,62 @@
+{
+ buildFHSEnv,
+ curl,
+ lib,
+ writeShellScriptBin,
+ gaudiHash ? null,
+ unwrapped,
+}: let
+ unwrappedWithGaudi = unwrapped.override {inherit gaudiHash;};
+in
+ buildFHSEnv {
+ name = "gaudi";
+
+ targetPkgs = pkgs: [
+ unwrappedWithGaudi.ase-idprotect.lib
+ unwrappedWithGaudi.gaudi
+
+ (writeShellScriptBin "launch-gaudi" ''
+ set -o errexit
+ set -o pipefail
+ set -o nounset
+
+ PATH="${lib.makeBinPath [curl]}:$PATH"
+
+ echo "$0: testing for incompatible releases..." >&2
+
+ jar_name=bccr-firma-fva-clienteMultiplataforma.jar
+ url="https://www.firmadigital.go.cr/Bccr.Firma.Fva.Actualizador.ClienteFirmadorJava//recursosLiberica17/actualizador/$jar_name"
+ ca_file="${unwrappedWithGaudi.bccr-cacerts}/root-ca.pem"
+ url_hash=$(curl -sS --cacert "$ca_file" "$url" | sha256sum | cut -d' ' -f1)
+ jar_path="${unwrappedWithGaudi.gaudi}/share/java/$jar_name"
+ jar_hash=$(sha256sum "$jar_path" | cut -d' ' -f1)
+
+ if [ "$url_hash" != "$jar_hash" ]; then
+ last_modified=$(curl -sS --head --cacert "$ca_file" "$url" | grep -i '^last-modified:' | head -1)
+
+ echo "$0: sha256 mismatch for $jar_path due to server-side update" >&2
+ echo "$0: expected: $url_hash" >&2
+ echo "$0: actual: $jar_hash" >&2
+ echo "$0: $last_modified" >&2
+ echo "$0: run the following to download the new client JAR, then update your derivation:" >&2
+ echo "$0: \$ ${unwrappedWithGaudi.update-gaudi}" >&2
+
+ exit 1
+ fi
+
+ cache_path_1="''${XDG_CACHE_HOME:-$HOME/.cache}/Agente-GAUDI"
+ cache_path_2="''${XDG_CACHE_HOME:-$HOME/.cache}/Firmador-BCCR"
+
+ for cache_path in "$cache_path_1" "$cache_path_2"; do
+ mkdir -p "$cache_path"
+ ln -sf -- ${unwrappedWithGaudi.gaudi}/share/java/bccr-firma-fva-clienteMultiplataforma.jar "$cache_path"
+ done
+
+ cp -f --no-preserve=mode -t "$cache_path_1" -- "${unwrappedWithGaudi.gaudi}/share/java/config.properties"
+
+ exec gaudi
+ '')
+ ];
+
+ runScript = "launch-gaudi";
+ }
diff --git a/trivionomicon/pkgs/athena-bccr/releases.nix b/trivionomicon/pkgs/athena-bccr/releases.nix
new file mode 100644
index 0000000..e965172
--- /dev/null
+++ b/trivionomicon/pkgs/athena-bccr/releases.nix
@@ -0,0 +1,12 @@
+{
+ "deb64-rev26" = {
+ # nix hash convert --hash-algo sha256 --from base16 --to sri $(sha256sum sfd_ClientesLinux_DEB64_Rev26.zip | cut -d' ' -f1)
+ hash = "sha256-ZPWP9TqJQ5coJAPzUSiaXKVItBWlqFM4smCjOf+gqQM=";
+ basename = "sfd_ClientesLinux_DEB64_Rev26";
+
+ srcPaths = {
+ gaudi = "Firma Digital/Agente GAUDI/agente-gaudi_20.0_amd64.deb";
+ idprotect = "Firma Digital/PinTool/IDProtect PINTool 7.24.02/DEB/idprotectclient_7.24.02-0_amd64.deb";
+ };
+ };
+}
diff --git a/trivionomicon/pkgs/athena-bccr/unwrapped.nix b/trivionomicon/pkgs/athena-bccr/unwrapped.nix
new file mode 100644
index 0000000..d6f3f38
--- /dev/null
+++ b/trivionomicon/pkgs/athena-bccr/unwrapped.nix
@@ -0,0 +1,226 @@
+{
+ lib,
+ requireFile,
+ release,
+ gaudiHash ? null,
+ ...
+}: let
+ inherit (release) srcPaths;
+
+ src = requireFile {
+ url = "https://soportefirmadigital.com";
+ name = "${release.basename}.zip";
+
+ inherit (release) hash;
+ };
+
+ gaudiUpdateSrc = {update-gaudi}:
+ requireFile {
+ url = "${update-gaudi}";
+ name = "gaudi-update-${release.name}.zip";
+
+ hash = gaudiHash;
+ };
+
+ moduleFromDeb = name: args @ {
+ stdenv,
+ dpkg,
+ unzip,
+ srcPath,
+ ...
+ }:
+ stdenv.mkDerivation ({
+ pname = "${name}-unwrapped";
+ version = release.name;
+
+ inherit src;
+
+ nativeBuildInputs = [dpkg unzip] ++ (args.nativeBuildInputs or []);
+
+ postUnpack = ''
+ dpkg -x ${lib.escapeShellArg "${release.basename}/${srcPath}"} ${lib.escapeShellArg release.basename}
+ '';
+ }
+ // lib.removeAttrs args ["stdenv" "dpkg" "unzip" "srcPath" "nativeBuildInputs"]);
+in {
+ ase-idprotect = {
+ autoPatchelfHook,
+ dpkg,
+ fontconfig,
+ freetype,
+ pcsclite,
+ stdenv,
+ unzip,
+ xorg,
+ zlib,
+ ...
+ }:
+ moduleFromDeb "ase-idprotect" {
+ inherit dpkg stdenv unzip;
+ srcPath = srcPaths.idprotect;
+
+ buildInputs = [
+ fontconfig
+ freetype
+ pcsclite
+ stdenv.cc.cc.lib
+ xorg.libX11
+ xorg.libXext
+ zlib
+ ];
+
+ nativeBuildInputs = [
+ autoPatchelfHook
+ ];
+
+ outputs = ["out" "lib"];
+
+ installPhase = ''
+ runHook preInstall
+
+ install -m755 -d $out/bin $lib/{etc,lib/x64-athena}
+ install -m755 usr/bin/IDProtect{_Manager,PINTool} $out/bin/
+ install -m755 usr/lib/x64-athena/* $lib/lib/x64-athena
+ cp -r etc/Athena $lib/etc/Athena
+
+ runHook postInstall
+ '';
+
+ preFixup = ''
+ patchelf --set-rpath $lib/lib/x64-athena $out/bin/*
+ '';
+ };
+
+ gaudi = {
+ autoPatchelfHook,
+ dpkg,
+ makeWrapper,
+ openjdk,
+ pkgs,
+ stdenv,
+ unzip,
+ writeShellScriptBin,
+ update-gaudi,
+ ...
+ }: let
+ jdk = openjdk.override {
+ enableJavaFX = true;
+ openjfx_jdk = pkgs."openjfx${lib.head (lib.splitString "." openjdk.version)}".override {withWebKit = true;};
+ };
+
+ fakeSudo = writeShellScriptBin "sudo" "";
+ gaudiUpdate = gaudiUpdateSrc {inherit update-gaudi;};
+ in
+ moduleFromDeb "gaudi" {
+ inherit dpkg stdenv unzip;
+ srcPath = srcPaths.gaudi;
+
+ nativeBuildInputs = [
+ autoPatchelfHook
+ jdk
+ makeWrapper
+ ];
+
+ preBuild = lib.optionalString (gaudiHash != null) ''
+ unzip -o ${gaudiUpdate} -d opt/Agente-GAUDI/lib/app
+ '';
+
+ buildPhase = ''
+ runHook preBuild
+
+ install -m755 -d $out/{bin,opt/Firmador-BCCR/lib}
+ cp -r opt/Agente-GAUDI/lib/app $out/opt/Firmador-BCCR/lib/app
+
+ # Preserves the original filename and avoids <hash>-LaunchGaudi.java
+ ln -s ${./LaunchGaudi.java} LaunchGaudi.java
+
+ javac \
+ -cp opt/Agente-GAUDI/lib/app/bccr-firma-fva-clienteMultiplataforma.jar \
+ -d $out/opt/Firmador-BCCR/lib/app \
+ LaunchGaudi.java
+
+ runHook postBuild
+ '';
+
+ installPhase = ''
+ runHook preInstall
+
+ install -m755 -d $out/{share,opt/Firmador-BCCR/lib/runtime/lib}
+ install -m755 -D opt/Agente-GAUDI/bin/Agente-GAUDI $out/opt/Firmador-BCCR/bin/Agente-GAUDI
+ install -m755 -D opt/Agente-GAUDI/lib/libapplauncher.so $out/opt/Firmador-BCCR/lib/libapplauncher.so
+
+ ln -s ../opt/Firmador-BCCR/lib/app $out/share/java
+ ln -s Firmador-BCCR $out/opt/Agente-GAUDI
+ ln -s ${jdk}/lib/openjdk/lib/libjli.so $out/opt/Firmador-BCCR/lib/runtime/lib/libjli.so
+
+ makeWrapper ${jdk}/bin/java $out/bin/gaudi \
+ --prefix PATH : ${fakeSudo}/bin \
+ --add-flags "-cp $out/share/java:$out/share/java/bccr-firma-fva-clienteMultiplataforma.jar" \
+ --add-flags "-Djavax.net.ssl.trustStore=$out/opt/Firmador-BCCR/lib/app/bccr.cacerts" \
+ --add-flags "LaunchGaudi"
+
+ runHook postInstall
+ '';
+ };
+
+ bccr-cacerts = {
+ openssl,
+ stdenv,
+ unzip,
+ ...
+ }:
+ stdenv.mkDerivation {
+ pname = "bccr-cacerts";
+ version = release.name;
+
+ inherit src;
+
+ nativeBuildInputs = [
+ openssl
+ unzip
+ ];
+
+ installPhase = ''
+ cp -r Firma\ Digital/Certificados $out
+ openssl x509 -in $out/CA\ RAIZ\ NACIONAL\ -\ COSTA\ RICA\ v2.crt -out $out/root-ca.pem -text
+ '';
+ };
+
+ update-gaudi = {
+ wget,
+ writeShellScript,
+ zip,
+ bccr-cacerts,
+ ...
+ }:
+ writeShellScript "update-gaudi" ''
+ set -o errexit
+ set -o pipefail
+ set -o nounset
+
+ temp_dir="$(mktemp -d)"
+ trap 'cd / && rm -rf -- "$temp_dir"' EXIT
+ cd "$temp_dir"
+
+ PATH="${lib.makeBinPath [wget zip]}:$PATH"
+ ca_cert="${bccr-cacerts}/root-ca.pem"
+ base_url="https://www.firmadigital.go.cr/Bccr.Firma.Fva.Actualizador.ClienteFirmadorJava//recursosLiberica17/actualizador"
+
+ wget --ca-certificate="$ca_cert" "$base_url/bccr.cacerts"
+ wget --ca-certificate="$ca_cert" "$base_url/config.properties"
+ wget --ca-certificate="$ca_cert" "$base_url/bccr-firma-fva-clienteMultiplataforma.jar"
+ wget --ca-certificate="$ca_cert" "$base_url/ServicioActualizadorClienteBCCR.jar"
+
+ # https://gist.github.com/stokito/c588b8d6a6a0aee211393d68eea678f2
+ TZ=UTC find . -exec touch --no-dereference -a -m -t 198002010000.00 {} +
+ zip_path="$PWD/gaudi-update-${release.name}.zip"
+ TZ=UTC zip -q --move --recurse-paths --symlinks -X "$zip_path" .
+ TZ=UTC touch -a -m -t 198002010000.00 "$zip_path"
+
+ set -x
+ nix-store --add-fixed sha256 "$zip_path"
+ set +x
+
+ echo -e "\ngaudiHash: $(nix-hash --to-sri --type sha256 $(sha256sum "$zip_path" | cut -d' ' -f1))"
+ '';
+}
diff --git a/trivionomicon/pkgs/default.nix b/trivionomicon/pkgs/default.nix
new file mode 100644
index 0000000..4a275a3
--- /dev/null
+++ b/trivionomicon/pkgs/default.nix
@@ -0,0 +1,10 @@
+final: prev:
+with prev.lib; let
+ inherit (final) callPackage;
+in {
+ override = {};
+
+ athena-bccr = callPackage ./athena-bccr {};
+ snapborg = final.python3Packages.callPackage ./snapborg {};
+ spliit = callPackage ./spliit {};
+}
diff --git a/trivionomicon/pkgs/snapborg/0001-Remove-env-arg-from-subprocess-calls.patch b/trivionomicon/pkgs/snapborg/0001-Remove-env-arg-from-subprocess-calls.patch
new file mode 100644
index 0000000..33f7a0c
--- /dev/null
+++ b/trivionomicon/pkgs/snapborg/0001-Remove-env-arg-from-subprocess-calls.patch
@@ -0,0 +1,29 @@
+From c363931656938f9cc3354b8e2797fe9abac1b0e3 Mon Sep 17 00:00:00 2001
+From: Alejandro Soto <alejandro@34project.org>
+Date: Sun, 31 Aug 2025 13:30:45 -0600
+Subject: [PATCH] Remove "env" arg from subprocess calls
+
+---
+ snapborg/borg.py | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/snapborg/borg.py b/snapborg/borg.py
+index 89a3d84..b74ddf7 100644
+--- a/snapborg/borg.py
++++ b/snapborg/borg.py
+@@ -173,11 +173,10 @@ def launch_borg(args, password=None, print_output=False, dryrun=False, cwd=None)
+ # TODO: parse output from JSON log lines
+ try:
+ if print_output:
+- subprocess.run(cmd, env=env, check=True, cwd=cwd)
++ subprocess.run(cmd, check=True, cwd=cwd)
+ else:
+ subprocess.check_output(cmd,
+ stderr=subprocess.STDOUT,
+- env=env,
+ cwd=cwd)
+ except CalledProcessError as e:
+ if e.returncode == 1:
+--
+2.49.0
+
diff --git a/trivionomicon/pkgs/snapborg/default.nix b/trivionomicon/pkgs/snapborg/default.nix
new file mode 100644
index 0000000..271be5c
--- /dev/null
+++ b/trivionomicon/pkgs/snapborg/default.nix
@@ -0,0 +1,34 @@
+{
+ borgbackup,
+ buildPythonApplication,
+ fetchFromGitHub,
+ lib,
+ packaging,
+ pyyaml,
+}:
+buildPythonApplication {
+ pname = "snapborg";
+ version = "0.1.0-unstable-20250331";
+
+ src = fetchFromGitHub {
+ repo = "snapborg";
+ owner = "enzingerm";
+
+ rev = "7e860395319f995161a6e0c7954ce47635e3cd59";
+ hash = "sha256-RzYL4IHulk1Q/ALWFs6YCTeCO8ohwqXH2NMHRctRVSA=";
+ };
+
+ patches = [
+ ./0001-Remove-env-arg-from-subprocess-calls.patch # Fixes broken $PATH when calling borg
+ ];
+
+ propagatedBuildInputs = [
+ borgbackup
+ packaging
+ pyyaml
+ ];
+
+ preFixup = ''
+ makeWrapperArgs+=(--prefix PATH : ${lib.makeBinPath [borgbackup]})
+ '';
+}
diff --git a/trivionomicon/pkgs/spliit/default.nix b/trivionomicon/pkgs/spliit/default.nix
new file mode 100644
index 0000000..280e820
--- /dev/null
+++ b/trivionomicon/pkgs/spliit/default.nix
@@ -0,0 +1,76 @@
+{
+ buildNpmPackage,
+ fetchFromGitHub,
+ nodePackages,
+ lib,
+ writeShellScriptBin,
+ pkgs,
+}: let
+ schemaEngine = "${pkgs.prisma-engines}/bin/schema-engine";
+ queryEngineBin = "${pkgs.prisma-engines}/bin/query-engine";
+ queryEngineLib = "${pkgs.prisma-engines}/lib/libquery_engine.node";
+ buildFlags = ["--ignore-scripts"];
+in
+ buildNpmPackage {
+ pname = "spliit2";
+ version = "master-20250420";
+
+ src = fetchFromGitHub {
+ repo = "spliit";
+ owner = "spliit-app";
+
+ rev = "a11efc79c13298c0d282e47496d132538752405f";
+ hash = "sha256-v4gaPzLzBbbqw/LDYxe1fiyficcrqcGOop23YPiTrdc=";
+ };
+
+ npmDepsHash = "sha256-sd0/7ruNUFxUKTeTwx/v8Vc/G3llkXP6RSDE78h3qVU=";
+
+ nativeBuildInputs = [pkgs.openssl];
+
+ npmRebuildFlags = buildFlags;
+
+ PRISMA_SCHEMA_ENGINE_BINARY = schemaEngine;
+ PRISMA_QUERY_ENGINE_BINARY = queryEngineBin;
+ PRISMA_QUERY_ENGINE_LIBRARY = queryEngineLib;
+
+ preBuild = ''
+ cp -v scripts/build.env .env
+
+ npx prisma generate
+ '';
+
+ npmBuildFlags = buildFlags;
+
+ postInstall = ''
+ cp -r .next public package.json next.config.mjs $out/lib/node_modules/spliit2
+
+ install -Dvm755 -t $out/bin ${lib.getExe (writeShellScriptBin "spliit2" ''
+ set -euxo pipefail
+
+ cd @out@/lib/node_modules/spliit2
+
+ export PATH="$PWD/node_modules/.bin:$PATH"
+ export NEXT_TELEMETRY_DISABLED=1
+
+ export PRISMA_SCHEMA_ENGINE_BINARY="${schemaEngine}"
+ export PRISMA_QUERY_ENGINE_BINARY="${queryEngineBin}"
+ export PRISMA_QUERY_ENGINE_LIBRARY="${queryEngineLib}"
+
+ prisma migrate deploy
+ next start
+ '')}
+
+ substituteInPlace $out/bin/spliit2 \
+ --replace @out@ $out
+
+ wrapProgram $out/bin/spliit2 \
+ --prefix PATH : ${lib.makeBinPath [pkgs.openssl]}
+ '';
+
+ meta = {
+ description = "Free and Open Source Alternative to Splitwise. Share expenses with your friends and family.";
+ homepage = "https://spliit.app";
+ license = lib.licenses.mit;
+ maintainers = with lib.maintainers; [];
+ };
+ }
diff --git a/trivionomicon/templates/system-flake/.gitignore b/trivionomicon/templates/system-flake/.gitignore
new file mode 100644
index 0000000..21f979d
--- /dev/null
+++ b/trivionomicon/templates/system-flake/.gitignore
@@ -0,0 +1,3 @@
+!**/.keep
+result
+flake.lock
diff --git a/trivionomicon/templates/system-flake/flake.nix b/trivionomicon/templates/system-flake/flake.nix
new file mode 100644
index 0000000..6afe06f
--- /dev/null
+++ b/trivionomicon/templates/system-flake/flake.nix
@@ -0,0 +1,28 @@
+{
+ inputs = {
+ nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
+ unstable.url = "github:nixos/nixpkgs/nixos-unstable";
+
+ home-manager = {
+ url = "github:nix-community/home-manager/release-24.11";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ trivium = {
+ url = "git+https://git.posixlycorrect.com/deepState/trivionomicon.git";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+ };
+
+ outputs = flakes @ {
+ self,
+ nixpkgs,
+ unstable,
+ home-manager,
+ trivium,
+ }:
+ trivium.lib.mkSystemFlake {
+ system = "x86_64-linux";
+ inherit flakes;
+ };
+}
diff --git a/trivionomicon/templates/system-flake/home/default.nix b/trivionomicon/templates/system-flake/home/default.nix
new file mode 100644
index 0000000..49439c7
--- /dev/null
+++ b/trivionomicon/templates/system-flake/home/default.nix
@@ -0,0 +1,73 @@
+{
+ config,
+ pkgs,
+ ...
+}: {
+ # This value determines the Home Manager release that your configuration is
+ # compatible with. This helps avoid breakage when a new Home Manager release
+ # introduces backwards incompatible changes.
+ #
+ # You should not change this value, even if you update Home Manager. If you do
+ # want to update the value, then make sure to first check the Home Manager
+ # release notes.
+ home.stateVersion = "24.11"; # Please read the comment before changing.
+
+ # The home.packages option allows you to install Nix packages into your
+ # environment.
+ home.packages = [
+ # # Adds the 'hello' command to your environment. It prints a friendly
+ # # "Hello, world!" when run.
+ # pkgs.hello
+
+ # # It is sometimes useful to fine-tune packages, for example, by applying
+ # # overrides. You can do that directly here, just don't forget the
+ # # parentheses. Maybe you want to install Nerd Fonts with a limited number of
+ # # fonts?
+ # (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; })
+
+ # # You can also create simple shell scripts directly inside your
+ # # configuration. For example, this adds a command 'my-hello' to your
+ # # environment:
+ # (pkgs.writeShellScriptBin "my-hello" ''
+ # echo "Hello, ${config.home.username}!"
+ # '')
+ ];
+
+ # Home Manager is pretty good at managing dotfiles. The primary way to manage
+ # plain files is through 'home.file'.
+ home.file = {
+ # # Building this configuration will create a copy of 'dotfiles/screenrc' in
+ # # the Nix store. Activating the configuration will then make '~/.screenrc' a
+ # # symlink to the Nix store copy.
+ # ".screenrc".source = dotfiles/screenrc;
+
+ # # You can also set the file content immediately.
+ # ".gradle/gradle.properties".text = ''
+ # org.gradle.console=verbose
+ # org.gradle.daemon.idletimeout=3600000
+ # '';
+ };
+
+ # Home Manager can also manage your environment variables through
+ # 'home.sessionVariables'. These will be explicitly sourced when using a
+ # shell provided by Home Manager. If you don't want to manage your shell
+ # through Home Manager then you have to manually source 'hm-session-vars.sh'
+ # located at either
+ #
+ # ~/.nix-profile/etc/profile.d/hm-session-vars.sh
+ #
+ # or
+ #
+ # ~/.local/state/nix/profiles/profile/etc/profile.d/hm-session-vars.sh
+ #
+ # or
+ #
+ # /etc/profiles/per-user/<user>/etc/profile.d/hm-session-vars.sh
+ #
+ home.sessionVariables = {
+ # EDITOR = "emacs";
+ };
+
+ # Let Home Manager install and manage itself.
+ programs.home-manager.enable = true;
+}
diff --git a/trivionomicon/templates/system-flake/home/platform/me@foo/default.nix b/trivionomicon/templates/system-flake/home/platform/me@foo/default.nix
new file mode 100644
index 0000000..6481e85
--- /dev/null
+++ b/trivionomicon/templates/system-flake/home/platform/me@foo/default.nix
@@ -0,0 +1,10 @@
+{
+ config,
+ pkgs,
+ ...
+}: {
+ # Home Manager needs a bit of information about you and the paths it should
+ # manage.
+ home.username = "ale";
+ home.homeDirectory = "/home/ale";
+}
diff --git a/trivionomicon/templates/system-flake/pkgs/config/default.nix b/trivionomicon/templates/system-flake/pkgs/config/default.nix
new file mode 100644
index 0000000..47abe76
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/config/default.nix
@@ -0,0 +1,5 @@
+{lib}:
+with lib; {
+ android_sdk.accept_license = true;
+ allowUnfreePredicate = pkg: import ./unfree.nix lib (getName pkg);
+}
diff --git a/trivionomicon/templates/system-flake/pkgs/config/unfree.nix b/trivionomicon/templates/system-flake/pkgs/config/unfree.nix
new file mode 100644
index 0000000..deda971
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/config/unfree.nix
@@ -0,0 +1,7 @@
+lib: name:
+with lib;
+ elem name [
+ "libproprietary-v3"
+ "closed-source-pkg"
+ "favorite-abandonware"
+ ]
diff --git a/trivionomicon/templates/system-flake/pkgs/default.nix b/trivionomicon/templates/system-flake/pkgs/default.nix
new file mode 100644
index 0000000..78a86d4
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/default.nix
@@ -0,0 +1,12 @@
+final: prev:
+with prev.lib; let
+ inherit (final) callPackage fetchpatch;
+in {
+ lib = callPackage ./lib {};
+
+ hello-world = callPackage ./hello-world {};
+
+ override = {
+ sl = prev.sl.overrideAttrs {pname = "my-sl";};
+ };
+}
diff --git a/trivionomicon/templates/system-flake/pkgs/hello-world/Makefile b/trivionomicon/templates/system-flake/pkgs/hello-world/Makefile
new file mode 100644
index 0000000..4eef056
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/hello-world/Makefile
@@ -0,0 +1,6 @@
+CFLAGS += -O3 -s
+
+all: hello-world
+
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $<
diff --git a/trivionomicon/templates/system-flake/pkgs/hello-world/default.nix b/trivionomicon/templates/system-flake/pkgs/hello-world/default.nix
new file mode 100644
index 0000000..19047a1
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/hello-world/default.nix
@@ -0,0 +1,14 @@
+{stdenv, ...}:
+stdenv.mkDerivation {
+ name = "hello-world";
+ version = "1.0.0";
+
+ src = ./.;
+
+ installPhase = ''
+ mkdir -p $out/bin
+ cp hello-world $out/bin
+ '';
+
+ meta.mainProgram = "hello-world";
+}
diff --git a/trivionomicon/templates/system-flake/pkgs/hello-world/hello-world.c b/trivionomicon/templates/system-flake/pkgs/hello-world/hello-world.c
new file mode 100644
index 0000000..d6cfa6b
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/hello-world/hello-world.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+int main()
+{
+ printf("Hello, world!\n");
+ return 0;
+}
diff --git a/trivionomicon/templates/system-flake/pkgs/lib/default.nix b/trivionomicon/templates/system-flake/pkgs/lib/default.nix
new file mode 100644
index 0000000..ab54163
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/lib/default.nix
@@ -0,0 +1,3 @@
+{callPackage}: {
+ fibonacci = callPackage ./fibonacci.nix {};
+}
diff --git a/trivionomicon/templates/system-flake/pkgs/lib/fibonacci.nix b/trivionomicon/templates/system-flake/pkgs/lib/fibonacci.nix
new file mode 100644
index 0000000..a12576b
--- /dev/null
+++ b/trivionomicon/templates/system-flake/pkgs/lib/fibonacci.nix
@@ -0,0 +1,7 @@
+let
+ fib = n:
+ if n > 1
+ then fib (n - 1) + fib (n - 2)
+ else 1;
+in
+ fib
diff --git a/trivionomicon/templates/system-flake/sys/default.nix b/trivionomicon/templates/system-flake/sys/default.nix
new file mode 100644
index 0000000..fa0f994
--- /dev/null
+++ b/trivionomicon/templates/system-flake/sys/default.nix
@@ -0,0 +1,14 @@
+{pkgs, ...}: {
+ # Let 'nixos-version --json' know about the Git revision
+ # of this flake.
+ system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;
+
+ # Network configuration.
+ networking.firewall.allowedTCPPorts = [80];
+
+ # Enable a web server.
+ services.httpd = {
+ enable = true;
+ adminAddr = "morty@example.org";
+ };
+}
diff --git a/trivionomicon/templates/system-flake/sys/platform/foo/default.nix b/trivionomicon/templates/system-flake/sys/platform/foo/default.nix
new file mode 100644
index 0000000..ef84269
--- /dev/null
+++ b/trivionomicon/templates/system-flake/sys/platform/foo/default.nix
@@ -0,0 +1,6 @@
+{pkgs, ...}: {
+ boot.isContainer = true;
+
+ # Network configuration.
+ networking.useDHCP = false;
+}