From 0d902afdc30b1b4b2575ef3539ec50fb3d4ace36 Mon Sep 17 00:00:00 2001 From: C4 Patino Date: Wed, 24 Jun 2026 22:54:03 -0500 Subject: [PATCH] feat: modify all servarr and qbittorrent services to use postgresql --- modules/nixos/bundles/common/default.nix | 2 +- .../services/apps/qbittorrent/default.nix | 27 +++++++++- .../services/apps/servarr/autobrr/default.nix | 44 ++++++++++++----- .../services/apps/servarr/bazarr/default.nix | 45 +++++++++++++---- .../services/apps/servarr/lidarr/default.nix | 46 ++++++++++++++---- .../apps/servarr/prowlarr/default.nix | 46 ++++++++++++++---- .../services/apps/servarr/radarr/default.nix | 46 ++++++++++++++---- .../services/apps/servarr/seerr/default.nix | 43 +++++++++++++--- .../services/apps/servarr/sonarr/default.nix | 46 ++++++++++++++---- secrets/crypt/secrets.json | Bin 3361 -> 3617 bytes 10 files changed, 275 insertions(+), 70 deletions(-) diff --git a/modules/nixos/bundles/common/default.nix b/modules/nixos/bundles/common/default.nix index 88472e2..ce1aece 100644 --- a/modules/nixos/bundles/common/default.nix +++ b/modules/nixos/bundles/common/default.nix @@ -69,7 +69,7 @@ in { impermanence = enabled; postgresql = { databases = { - shiori = ["autobrr" "bazarr" "lidarr" "lidarr-log" "prowlarr" "prowlarr-log" "radarr" "radarr-log" "seerr" "sonarr" "sonarr-log"]; + shiori = ["autobrr" "bazarr" "lidarr" "lidarr-log" "prowlarr" "prowlarr-log" "qui" "radarr" "radarr-log" "seerr" "sonarr" "sonarr-log"]; tsuki = ["forgejo" "grafana" "terraform" "vaultwarden"]; }; }; diff --git a/modules/nixos/services/apps/qbittorrent/default.nix b/modules/nixos/services/apps/qbittorrent/default.nix index 6a6b772..c5ef52d 100644 --- a/modules/nixos/services/apps/qbittorrent/default.nix +++ b/modules/nixos/services/apps/qbittorrent/default.nix @@ -7,10 +7,11 @@ ... }: let inherit (lib) mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost hostHasService resolveServicePort resolveDatabaseIP readJsonOrEmpty getIn; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; uid = 980; gid = 975; @@ -18,6 +19,7 @@ isEnabled = hostHasService networkCfg.network-services hostName "qbittorrent"; port = resolveServicePort networkCfg.network-services "qbittorrent" 9000; torrentingPort = 23345; + dbHost = resolveDatabaseHost pgCfg.databases "qui"; in { config = mkIf isEnabled { containers.qbittorrent = { @@ -178,9 +180,25 @@ in { settings = { host = "0.0.0.0"; port = port; + + databaseEngine = "postgres"; + databaseHost = resolveDatabaseIP networkCfg.devices pgCfg.databases "qui"; + databasePort = 5600; + databaseName = "qui"; + databaseUser = "qui"; + databasePassword = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.qui.password"; }; }; + systemd.services.qui = mkIf (dbHost == hostName) { + after = ["postgresql.service"]; + requires = ["postgresql.service"]; + serviceConfig.RestartSec = "1s"; + }; + sops.secrets = { "openvpn" = {}; "qui" = {}; @@ -200,6 +218,7 @@ in { ${namespace}.services.storage.impermanence.folders = let qbittorrentUser = config.users.users.qbittorrent; + quiUser = config.users.users.qui; in [ { directory = "/var/lib/qBittorrent"; @@ -207,6 +226,12 @@ in { group = qbittorrentUser.group; mode = "700"; } + { + directory = "/var/lib/qui"; + user = quiUser.name; + group = quiUser.group; + mode = "700"; + } ]; networking = { diff --git a/modules/nixos/services/apps/servarr/autobrr/default.nix b/modules/nixos/services/apps/servarr/autobrr/default.nix index b90a1b6..d37be10 100644 --- a/modules/nixos/services/apps/servarr/autobrr/default.nix +++ b/modules/nixos/services/apps/servarr/autobrr/default.nix @@ -1,18 +1,21 @@ { config, + inputs, lib, namespace, pkgs, ... }: let - inherit (lib) mkForce mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib) mkForce mkIf mkMerge; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost resolveDatabaseIP readJsonOrEmpty getIn hostHasService resolveServicePort; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; isEnabled = hostHasService networkCfg.network-services hostName "autobrr"; port = resolveServicePort networkCfg.network-services "autobrr" 7474; + dbHost = resolveDatabaseHost pgCfg.databases "autobrr"; in { config = mkIf isEnabled { services.autobrr = { @@ -22,6 +25,17 @@ in { settings = { host = "0.0.0.0"; port = port; + + databaseType = "postgres"; + postgresHost = resolveDatabaseIP networkCfg.devices pgCfg.databases "autobrr"; + postgresPort = 5600; + postgresDatabase = "autobrr"; + postgresUser = "autobrr"; + postgresPass = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.autobrr.password"; + postgresSSLMode = "disable"; }; }; @@ -62,15 +76,23 @@ in { [ "$remaining_space" -gt "$required_space" ] ''; - in { - path = [checkAutobrrSpace]; - serviceConfig = { - DynamicUser = mkForce false; - User = autobrrUser.name; - Group = autobrrUser.group; - UMask = mkForce "0002"; - }; - }; + in + mkMerge [ + { + path = [checkAutobrrSpace]; + serviceConfig = { + DynamicUser = mkForce false; + User = autobrrUser.name; + Group = autobrrUser.group; + UMask = mkForce "0002"; + }; + } + (mkIf (dbHost == hostName) { + after = ["postgresql.service" "pgbouncer.service"]; + requires = ["postgresql.service" "pgbouncer.service"]; + serviceConfig.RestartSec = "1s"; + }) + ]; }; sops.secrets = { diff --git a/modules/nixos/services/apps/servarr/bazarr/default.nix b/modules/nixos/services/apps/servarr/bazarr/default.nix index 6d8407c..1eac723 100644 --- a/modules/nixos/services/apps/servarr/bazarr/default.nix +++ b/modules/nixos/services/apps/servarr/bazarr/default.nix @@ -1,17 +1,20 @@ { config, + inputs, lib, namespace, ... }: let - inherit (lib) mkForce mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib) mkForce mkIf mkMerge; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost resolveDatabaseIP readJsonOrEmpty getIn hostHasService resolveServicePort; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; isEnabled = hostHasService networkCfg.network-services hostName "bazarr"; port = resolveServicePort networkCfg.network-services "bazarr" 6767; + dbHost = resolveDatabaseHost pgCfg.databases "bazarr"; in { config = mkIf isEnabled { services.bazarr = { @@ -19,14 +22,38 @@ in { listenPort = port; }; - systemd.services.bazarr.serviceConfig = let + systemd.services.bazarr = let bazarrUser = config.users.users.bazarr; - in { - DynamicUser = mkForce false; - User = bazarrUser.name; - Group = bazarrUser.group; - UMask = mkForce "0002"; - }; + dbIp = resolveDatabaseIP networkCfg.devices pgCfg.databases "bazarr"; + password = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.bazarr.password"; + in + mkMerge [ + { + environment = { + POSTGRES_ENABLED = "true"; + POSTGRES_HOST = "${dbIp}"; + POSTGRES_PORT = "5600"; + POSTGRES_DATABASE = "bazarr"; + POSTGRES_USERNAME = "bazarr"; + POSTGRES_PASSWORD = password; + }; + + serviceConfig = { + DynamicUser = mkForce false; + User = bazarrUser.name; + Group = bazarrUser.group; + UMask = mkForce "0002"; + }; + } + (mkIf (dbHost == hostName) { + after = ["postgresql.service" "pgbouncer.service"]; + requires = ["postgresql.service" "pgbouncer.service"]; + serviceConfig.RestartSec = "1s"; + }) + ]; users = { users.bazarr = { diff --git a/modules/nixos/services/apps/servarr/lidarr/default.nix b/modules/nixos/services/apps/servarr/lidarr/default.nix index 14f4a12..bb77c3b 100644 --- a/modules/nixos/services/apps/servarr/lidarr/default.nix +++ b/modules/nixos/services/apps/servarr/lidarr/default.nix @@ -1,32 +1,58 @@ { config, + inputs, lib, namespace, ... }: let - inherit (lib) mkForce mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib) mkForce mkIf mkMerge; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost resolveDatabaseIP readJsonOrEmpty getIn hostHasService resolveServicePort; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; isEnabled = hostHasService networkCfg.network-services hostName "lidarr"; port = resolveServicePort networkCfg.network-services "lidarr" 8686; + dbHost = resolveDatabaseHost pgCfg.databases "lidarr"; in { config = mkIf isEnabled { services.lidarr = { enable = true; - settings.server.port = port; + settings = { + server.port = port; + postgres = { + host = resolveDatabaseIP networkCfg.devices pgCfg.databases "lidarr"; + port = 5600; + user = "lidarr"; + maindb = "lidarr"; + logdb = "lidarr-log"; + password = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.lidarr.password"; + }; + }; }; - systemd.services.lidarr.serviceConfig = let + systemd.services.lidarr = let lidarrUser = config.users.users.lidarr; - in { - DynamicUser = mkForce false; - User = lidarrUser.name; - Group = lidarrUser.group; - UMask = mkForce "0002"; - }; + in + mkMerge [ + { + serviceConfig = { + DynamicUser = mkForce false; + User = lidarrUser.name; + Group = lidarrUser.group; + UMask = mkForce "0002"; + }; + } + (mkIf (dbHost == hostName) { + after = ["postgresql.service" "pgbouncer.service"]; + requires = ["postgresql.service" "pgbouncer.service"]; + serviceConfig.RestartSec = "1s"; + }) + ]; users = { users.lidarr = { diff --git a/modules/nixos/services/apps/servarr/prowlarr/default.nix b/modules/nixos/services/apps/servarr/prowlarr/default.nix index 0925a8f..1aee070 100644 --- a/modules/nixos/services/apps/servarr/prowlarr/default.nix +++ b/modules/nixos/services/apps/servarr/prowlarr/default.nix @@ -1,32 +1,58 @@ { config, + inputs, lib, namespace, ... }: let - inherit (lib) mkForce mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib) mkForce mkIf mkMerge; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost resolveDatabaseIP readJsonOrEmpty getIn hostHasService resolveServicePort; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; isEnabled = hostHasService networkCfg.network-services hostName "prowlarr"; port = resolveServicePort networkCfg.network-services "prowlarr" 9696; + dbHost = resolveDatabaseHost pgCfg.databases "prowlarr"; in { config = mkIf isEnabled { services.prowlarr = { enable = true; - settings.server.port = port; + settings = { + server.port = port; + postgres = { + host = resolveDatabaseIP networkCfg.devices pgCfg.databases "prowlarr"; + port = 5600; + user = "prowlarr"; + maindb = "prowlarr"; + logdb = "prowlarr-log"; + password = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.prowlarr.password"; + }; + }; }; - systemd.services.prowlarr.serviceConfig = let + systemd.services.prowlarr = let prowlarrUser = config.users.users.prowlarr; - in { - DynamicUser = mkForce false; - User = prowlarrUser.name; - Group = prowlarrUser.group; - UMask = mkForce "0002"; - }; + in + mkMerge [ + { + serviceConfig = { + DynamicUser = mkForce false; + User = prowlarrUser.name; + Group = prowlarrUser.group; + UMask = mkForce "0002"; + }; + } + (mkIf (dbHost == hostName) { + after = ["postgresql.service" "pgbouncer.service"]; + requires = ["postgresql.service" "pgbouncer.service"]; + serviceConfig.RestartSec = "1s"; + }) + ]; users = { users.prowlarr = { diff --git a/modules/nixos/services/apps/servarr/radarr/default.nix b/modules/nixos/services/apps/servarr/radarr/default.nix index 9d96df2..b1f653d 100644 --- a/modules/nixos/services/apps/servarr/radarr/default.nix +++ b/modules/nixos/services/apps/servarr/radarr/default.nix @@ -1,32 +1,58 @@ { config, + inputs, lib, namespace, ... }: let - inherit (lib) mkForce mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib) mkForce mkIf mkMerge; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost resolveDatabaseIP readJsonOrEmpty getIn hostHasService resolveServicePort; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; isEnabled = hostHasService networkCfg.network-services hostName "radarr"; port = resolveServicePort networkCfg.network-services "radarr" 7878; + dbHost = resolveDatabaseHost pgCfg.databases "radarr"; in { config = mkIf isEnabled { services.radarr = { enable = true; - settings.server.port = port; + settings = { + server.port = port; + postgres = { + host = resolveDatabaseIP networkCfg.devices pgCfg.databases "radarr"; + port = 5600; + user = "radarr"; + maindb = "radarr"; + logdb = "radarr-log"; + password = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.radarr.password"; + }; + }; }; - systemd.services.radarr.serviceConfig = let + systemd.services.radarr = let radarrUser = config.users.users.radarr; - in { - DynamicUser = mkForce false; - User = radarrUser.name; - Group = radarrUser.group; - UMask = mkForce "0002"; - }; + in + mkMerge [ + { + serviceConfig = { + DynamicUser = mkForce false; + User = radarrUser.name; + Group = radarrUser.group; + UMask = mkForce "0002"; + }; + } + (mkIf (dbHost == hostName) { + after = ["postgresql.service" "pgbouncer.service"]; + requires = ["postgresql.service" "pgbouncer.service"]; + serviceConfig.RestartSec = "1s"; + }) + ]; users = { users.radarr = { diff --git a/modules/nixos/services/apps/servarr/seerr/default.nix b/modules/nixos/services/apps/servarr/seerr/default.nix index bc79edd..32cf7d5 100644 --- a/modules/nixos/services/apps/servarr/seerr/default.nix +++ b/modules/nixos/services/apps/servarr/seerr/default.nix @@ -1,17 +1,20 @@ { config, + inputs, lib, namespace, ... }: let - inherit (lib) mkForce mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib) mkForce mkIf mkMerge; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost resolveDatabaseIP readJsonOrEmpty getIn hostHasService resolveServicePort; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; isEnabled = hostHasService networkCfg.network-services hostName "seerr"; port = resolveServicePort networkCfg.network-services "seerr" 5055; + dbHost = resolveDatabaseHost pgCfg.databases "seerr"; in { config = mkIf isEnabled { services.seerr = { @@ -20,13 +23,37 @@ in { openFirewall = true; }; - systemd.services.seerr.serviceConfig = let + systemd.services.seerr = let seerrUser = config.users.users.seerr; - in { - DynamicUser = mkForce false; - User = seerrUser.name; - Group = seerrUser.group; - }; + dbIp = resolveDatabaseIP networkCfg.devices pgCfg.databases "seerr"; + password = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.seerr.password"; + in + mkMerge [ + { + environment = { + DB_TYPE = "postgres"; + DB_HOST = dbIp; + DB_PORT = "5600"; + DB_USER = "seerr"; + DB_PASS = password; + DB_NAME = "seerr"; + }; + + serviceConfig = { + DynamicUser = mkForce false; + User = seerrUser.name; + Group = seerrUser.group; + }; + } + (mkIf (dbHost == hostName) { + after = ["postgresql.service" "pgbouncer.service"]; + requires = ["postgresql.service" "pgbouncer.service"]; + serviceConfig.RestartSec = "1s"; + }) + ]; users = { users.seerr = { diff --git a/modules/nixos/services/apps/servarr/sonarr/default.nix b/modules/nixos/services/apps/servarr/sonarr/default.nix index 4684e8c..163fa6d 100644 --- a/modules/nixos/services/apps/servarr/sonarr/default.nix +++ b/modules/nixos/services/apps/servarr/sonarr/default.nix @@ -1,32 +1,58 @@ { config, + inputs, lib, namespace, ... }: let - inherit (lib) mkForce mkIf; - inherit (lib.${namespace}) getAttrByNamespace hostHasService resolveServicePort; + inherit (lib) mkForce mkIf mkMerge; + inherit (lib.${namespace}) getAttrByNamespace resolveDatabaseHost resolveDatabaseIP readJsonOrEmpty getIn hostHasService resolveServicePort; inherit (config.networking) hostName; networkCfg = getAttrByNamespace config "${namespace}.services.networking"; + pgCfg = getAttrByNamespace config "${namespace}.services.storage.postgresql"; isEnabled = hostHasService networkCfg.network-services hostName "sonarr"; port = resolveServicePort networkCfg.network-services "sonarr" 8989; + dbHost = resolveDatabaseHost pgCfg.databases "sonarr"; in { config = mkIf isEnabled { services.sonarr = { enable = true; - settings.server.port = port; + settings = { + server.port = port; + postgres = { + host = resolveDatabaseIP networkCfg.devices pgCfg.databases "sonarr"; + port = 5600; + user = "sonarr"; + maindb = "sonarr"; + logdb = "sonarr-log"; + password = + "${inputs.self}/secrets/crypt/secrets.json" + |> readJsonOrEmpty + |> getIn "postgresql.sonarr.password"; + }; + }; }; - systemd.services.sonarr.serviceConfig = let + systemd.services.sonarr = let sonarrUser = config.users.users.sonarr; - in { - DynamicUser = mkForce false; - User = sonarrUser.name; - Group = sonarrUser.group; - UMask = mkForce "0002"; - }; + in + mkMerge [ + { + serviceConfig = { + DynamicUser = mkForce false; + User = sonarrUser.name; + Group = sonarrUser.group; + UMask = mkForce "0002"; + }; + } + (mkIf (dbHost == hostName) { + after = ["postgresql.service" "pgbouncer.service"]; + requires = ["postgresql.service" "pgbouncer.service"]; + serviceConfig.RestartSec = "1s"; + }) + ]; users = { users.sonarr = { diff --git a/secrets/crypt/secrets.json b/secrets/crypt/secrets.json index def3d4609bd99e258a10979e203d21d3a179a8b6..dd3f839273fab5df2a69e581c74e30bbc17f3715 100755 GIT binary patch literal 3617 zcmZQ@_Y83kiVO&0ST*lWs<>1{(PiV_PyMrRU;lh|cDP-g$W+l#k;io&9xr5H^8YGr zXuRFL`s!(an?>gyEo9ZqRN0%}<0X(IcPqz0B<671jm;}wC@nGItU431#6;`W;>V{? zy^uKLRJtsX8Q#YRGt8{vm z>eIzDbhfPaYcD$V_{BFPao@VF0w-pCUMQ@x?w3^YqW4S7*H`3rnEcG2JH1GI_2+>7 zIX}Kks#w1LvUBRzB8#Y`%z6c22?DZ5q6BF=tljbtG>7$5ixfvwqm)1wFh> zM@&vRz2E$uZ(H#PgCz<|)6~B@HfC#dY+Uzv`O5dk{kL^eC$7?uQ2$m?d}Px9zcw4^ zu}qzD+3t1g>q5yzpAT=?v>?dZqT+Hn*VFH5rUy53F=;Z)<~}uV^F0a1B!}M$lh+7O zRA8u()JgqPyk%8a&Z;Bj5iMS?KUlS!2sNAy`EvGH<0QM18gb32*|YgJGk`xLN8*4%!=VZYPU3YoJsZ>GiH-D&4ZfhKIPPxhwuxvxvq2nA^(oJWj9@p%zG<0g#z4&hu$4d6uA>tuI0ule?!>#Y1 zKjryFIvA;Y`w}Ta%6m)*lO8 z^vBY*ea36y^Xt#-n6-G-KV#O%uivpu(wpT!r#AbOe^uc;zjr}7N*6xPi`lNXMr8l) zO`E1CUhe$JloCGUiGSg*|2i4G`yVhoPqcm+z02@(O+B-pzx%OR-K9whJF|Fx@k?`c zvUMGAo%ZY7lg3v(OCp#4I{9_ZG_w<#ud5Od{Oz-s5q&ew@;pd(s=S05*9CMw^q`5od60?;0%ct@z2b{ba1kw)X{#e-j zLEJ=6e^N-%)e6Q=#f?lWAEj%kI$aM_o%`d1sGD8fPP_9>8FxjBxt16H%s9R4g!tbY zR`1}C;->4BdM_;!cb~iSLE-V96&j~E%U@WDMGr5ZcxT#uz0{uRrf>hu%;xZx zE{d1qIU$q(Xy**ipWY0%-!)6v-~BQ;W3lGheUDr}A3YFyTvqC0QG#&{n$l^v#s zELhVO_^gjUy5OdDP%T9y{N`=NnXdPPK7Wc!WL>^;iulstFrizsyWizrQQ8{H?vqX(`|2tA@7@A- zo+r<=eqPlMU3jAI%Z5ka`)A6|$yB_!+wg?pjG4E}lm1+&J-qk2!Ibs>*FE(QC1-?v zGSHZ1*_OCY#`;^Fsn6${J$vd;E&g7rzh~N;Q=Qo^@!4{oS0x{?Enr^Z(s5Ojn>TUB zv1bb9oHO36ymKnN>)g3TYFA}kauZLkSajz4CY#*v*Vax-IK7==Zr-)Fjq=|Dc$eh4 zF(sMp_?+T1F(OMjYTds(lb2*axVmzabJ6y7J9NW4&)1qTKPlYVdGWN2>elw(Ojce^ z1GGAFaue8;@H_LRN%l^O`MeIVZD;&ZL*99j>~NIZ|6>D^5|@@z481akK<%IF{8j&csu0_nS#-pXakToC}-za`qR7%p(WiG;=?aJy0Z> zZr{S_aD{uy?6uFl9=e{inw=&y-MU`gQ%l)gYf;yknXw&ep2?PPX5as0Wfyky^Rqc- z7W2`?`J?!$ zKxgx(j)j`{T~3>1i*@eqRLX6B#CW~a`D|ms&%Y(&s=Md^SZME`bEbEOV34sw_vKIO z(q}TyAIs44jC7qjng$|Zy964S1p=`_?6X9K-f|q>L+Sc@U z@3&3txvzqa)Y{fRwY_^d=EUuuk6cXJnaUaee^<=mi&bARYeRT3mqz&0Sl9fCPbOu2 z->As2Xsb?r&-$ZFC%Pql+%D93Z-O<)$?sb?eEr(?ankDvA6?1~w;AlIir(>d%YW%V ze1B#sJ$zwT5Xn;(y5~UJK0(eq!3SpCch3q{mtff^7RSNyd|qe$h6!0V+SBL%d3OHy zU9}Sve@uF`@BN8>4h#Daa|6Q{xdiuKGG%`CVpi+l`;QV$xPIq{MwhG(QR`#atLuHa zyRiH9q{V{L_v<$s$vyF{=7A*>CU4&C%%+;5<@UDxg876cH;T%i zDf>FOxgGNP8lR+dh-WV6iDy@KsZZfiJU{ne|Hbe5muGy~TE9c(8Q(3XWjm&_YVMz{ zu)|MbtI9Rk10Cu6HlOjC$JStbZkZrMl0?uvi&}?I!D)HEQwt+=KaA7VaSVHK*}mAJuiM^}`Y!6@0`*0qH_~=L3s8%- zkMQ;Q^pC|~;gF5qANhsXIS!mzA3o7?*&%u7a257#M~+=NV39vx`uMyo5v|=7kM+g3 zXT&|d=1{Zj&fWi&ck;p$_OJT!<-EB<2Cr{ug{aQ+?1es|+ZRR^pJu(d&SicNa^?fDr{d7cXj7^v+Wa3zubP{O~{YK-C45=vyNVWqPJF2@?gau z+4nDJZ=G~5D?wpH3+E286UVY_{~z??|GPDG^XW{tPjjZbw!w1IC@qVU9^_|y;ynqmD3`j3G4|Ef6Tdf zP^9!?-Ku~LCcAF=n|2jObCJ>@4Sd?=OB z>6q(tc!}oYyRN$4yu0cZd}B|~NMDr+0QpVV&S~Q6n{@+(aoBgq?XnE z2Yr{!aJMoOmI!oJ4L`>S3$>s9b9g1&uE}pPn^JA~M;X_{Sb?R#Kz7%Zz(;xon z!o1U)1&)P2c{<6&q4)I;OV)*#CN?pI%@r(Zjd^tF^zx2LSv=cUy3|hm&UI^RP=oxW z4`r-3CwgzZHSg8M@@oq2ucvYg9MOGxcT2a~GbW+>S%E4su{AEtbqiw^>p#zxX3`bp z>fY<;xc{7wnb}koW##TS)|Vf+RxX>9=N_Lj>B5g+PiF9|c1U*KYTvOh2cCu5nw+Zau({un;dDXvY520{xo0ljP}?9bxZ%WP z-A#`bx5tE?<_zVP_;zSPg~<1LjZ6={YLbnczUE&}Rzue?wS4UPhj)%=z0kfDp6&VB@=?p(=IQG5!+yrw_3Pi?F0jHaX0MFsf1$}c^Ma#a ey9-2K$UZ50*X!rw_n%|-#VppEzG6=0qIUpRj1ffu literal 3361 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 Uu0DD`iT}y9S4BS`wCs2R0JWi@mjD0&