diff --git a/devshell/default.nix b/devshell/default.nix index a542d93..f184d53 100644 --- a/devshell/default.nix +++ b/devshell/default.nix @@ -24,6 +24,7 @@ in coreutils nixVersions.stable rage + wireguard-tools (pkgs.writeShellScriptBin "deploy" '' exec ${deploy-rs.deploy-rs}/bin/deploy --skip-checks "$@" '') diff --git a/lib/constants.nix b/lib/constants.nix index 1cb357f..c34507e 100644 --- a/lib/constants.nix +++ b/lib/constants.nix @@ -135,6 +135,9 @@ rec { v4 = subnet 8 3 all.v4; v6 = subnet 4 3 all.v6; }; + qclk = { + v4 = subnet 8 4 all.v4; + }; cust = { v4 = subnet 8 100 all.v4; # single ip for routing only @@ -170,6 +173,10 @@ rec { jam-ctr = host 3 prefixes.cust.v4; }; + qclk = { + wgPort = 51821; + }; + firewallForwards = aa: [ { port = "http"; @@ -220,6 +227,12 @@ rec { dst = aa.simpcraft-oci.internal.ipv4.address; proto = "udp"; } + + { + port = qclk.wgPort; + dst = aa.qclk.internal.ipv4.address; + proto = "udp"; + } ]; fstrimConfig = { diff --git a/nixos/boxes/colony/default.nix b/nixos/boxes/colony/default.nix index 08802bd..8e19c27 100644 --- a/nixos/boxes/colony/default.nix +++ b/nixos/boxes/colony/default.nix @@ -264,10 +264,12 @@ in Destination = prefixes.ctrs.v6; Gateway = allAssignments.shill.internal.ipv6.address; } + { Destination = allAssignments.shill.internal.ipv4.address; Gateway = allAssignments.shill.routing.ipv4.address; } + { Destination = lib.my.c.tailscale.prefix.v4; Gateway = allAssignments.shill.routing.ipv4.address; @@ -276,6 +278,11 @@ in Destination = lib.my.c.tailscale.prefix.v6; Gateway = allAssignments.shill.internal.ipv6.address; } + { + Destination = prefixes.qclk.v4; + Gateway = allAssignments.shill.routing.ipv4.address; + } + { Destination = prefixes.jam.v6; Gateway = allAssignments.shill.internal.ipv6.address; diff --git a/nixos/boxes/colony/vms/estuary/default.nix b/nixos/boxes/colony/vms/estuary/default.nix index f36dedb..613a2fc 100644 --- a/nixos/boxes/colony/vms/estuary/default.nix +++ b/nixos/boxes/colony/vms/estuary/default.nix @@ -308,6 +308,11 @@ in Destination = lib.my.c.tailscale.prefix.v6; Gateway = allAssignments.colony.internal.ipv6.address; } + + { + Destination = prefixes.qclk.v4; + Gateway = allAssignments.colony.routing.ipv4.address; + } ] ++ (map (pName: [ { diff --git a/nixos/boxes/colony/vms/shill/containers/default.nix b/nixos/boxes/colony/vms/shill/containers/default.nix index 2a2ba3b..a69213c 100644 --- a/nixos/boxes/colony/vms/shill/containers/default.nix +++ b/nixos/boxes/colony/vms/shill/containers/default.nix @@ -8,5 +8,6 @@ ./object.nix ./toot.nix ./waffletail.nix + ./qclk ]; } diff --git a/nixos/boxes/colony/vms/shill/containers/qclk/default.nix b/nixos/boxes/colony/vms/shill/containers/qclk/default.nix new file mode 100644 index 0000000..825a99b --- /dev/null +++ b/nixos/boxes/colony/vms/shill/containers/qclk/default.nix @@ -0,0 +1,115 @@ +{ lib, ... }: +let + inherit (lib.my) net; + inherit (lib.my.c.colony) domain prefixes qclk; +in +{ + nixos.systems.qclk = { config, ... }: { + system = "x86_64-linux"; + nixpkgs = "mine"; + rendered = config.configuration.config.my.asContainer; + + assignments = { + internal = { + name = "qclk-ctr"; + inherit domain; + ipv4.address = net.cidr.host 10 prefixes.ctrs.v4; + ipv6 = { + iid = "::a"; + address = net.cidr.host 10 prefixes.ctrs.v6; + }; + }; + qclk = { + ipv4 = { + address = net.cidr.host 1 prefixes.qclk.v4; + gateway = null; + }; + }; + }; + + configuration = { lib, pkgs, config, assignments, ... }: + let + inherit (lib) concatStringsSep mkMerge mkIf mkForce; + inherit (lib.my) networkdAssignment; + + apiPort = 8080; + + instances = [ + { + host = 2; + wgKey = "D7z1FhcdxpnrGCE0wBW5PZb5BKuhCu6tcZ/5ZaYxdwQ="; + } + ]; + ipFor = i: net.cidr.host i.host prefixes.qclk.v4; + in + { + config = { + environment = { + systemPackages = with pkgs; [ + wireguard-tools + ]; + }; + + my = { + deploy.enable = false; + server.enable = true; + + secrets = { + key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC1kcfvahYmSk8IJKaUIcGkhxf/8Yse2XnU7Qqgcglyq"; + files = { + "qclk/wg.key" = { + group = "systemd-network"; + mode = "440"; + }; + }; + }; + + firewall = { + udp.allowed = [ qclk.wgPort ]; + extraRules = '' + table inet filter { + chain input { + iifname management tcp dport ${toString apiPort} accept + } + chain forward { + iifname host0 oifname management ip saddr { ${concatStringsSep ", " lib.my.c.as211024.trusted.v4} } accept + } + } + table inet nat { + chain postrouting { + iifname host0 oifname management snat ip to ${assignments.qclk.ipv4.address} + } + } + ''; + }; + }; + + systemd = { + network = { + netdevs."30-management" = { + netdevConfig = { + Name = "management"; + Kind = "wireguard"; + }; + wireguardConfig = { + PrivateKeyFile = config.age.secrets."qclk/wg.key".path; + ListenPort = qclk.wgPort; + }; + wireguardPeers = map (i: { + PublicKey = i.wgKey; + AllowedIPs = [ (ipFor i) ]; + }) instances; + }; + networks = { + "30-container-host0" = networkdAssignment "host0" assignments.internal; + + "30-management" = networkdAssignment "management" assignments.qclk; + }; + }; + }; + + services = { }; + }; + }; + }; +} diff --git a/nixos/boxes/colony/vms/shill/default.nix b/nixos/boxes/colony/vms/shill/default.nix index 7cc599e..e75d83a 100644 --- a/nixos/boxes/colony/vms/shill/default.nix +++ b/nixos/boxes/colony/vms/shill/default.nix @@ -152,6 +152,11 @@ in Destination = lib.my.c.tailscale.prefix.v6; Gateway = allAssignments.waffletail.internal.ipv6.address; } + + { + Destination = prefixes.qclk.v4; + Gateway = allAssignments.qclk.internal.ipv4.address; + } ]; } ]; @@ -211,6 +216,7 @@ in }; toot = {}; waffletail = {}; + qclk = {}; }; in mkMerge [ diff --git a/secrets/qclk/wg.key.age b/secrets/qclk/wg.key.age new file mode 100644 index 0000000..d57fb2d --- /dev/null +++ b/secrets/qclk/wg.key.age @@ -0,0 +1,13 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IFpiTEpXQSBPQjFB +R3p6OGZYOTlZcHV0djlnY2tPTVk2SDNaazM2Nm0vMytSTWJ0THo4CnNSUW4zR2Vo +V3hsVVFIOEhRM1ZpSnVmcmd6WFhKdGVNQk9IYlRoZFBGUjgKLT4gWDI1NTE5IDJs +NzlrMXQ5Ty9sdTkwNFpUVnp5MWlucUJLZWtWbGpMd1NTZm1UendPa0EKeWVTa2p6 +ejROR29UYU5GcWlxb1hjWnV6V1BOK29pL2pZRFVUZkU5NU9EUQotPiBfPk5oe0Fq +LWdyZWFzZSA2Jy1xCnhpYThsOVlMWTZEWVFYemlvQ1lKZlVnc0xnT29WVEtXUHF1 +SDJ1TmJ0Qmg0R1o2UTBFanAwcXVpbGtKR21UbXoKYVNUTXVweDhQUmU2TzFOc1M4 +Z3d6YjdIT29meHVUU0tTV2NnSkljcgotLS0gRFRZNlc3cmRVS25wU0ZZeEpKNmZS +Q1YxQkcyOGRDQ0VMSC9Ec2xka2NMOAppbDQ9/xJxLUc0OuOFq4b6r+fYCB4hm4ZB +aEF8B3csbjrIHoboxCNaYGNh1DibseZaaWygsDfMbAmbRw2xvBNgI/oq2/RjSda9 +dZm+1A== +-----END AGE ENCRYPTED FILE----- diff --git a/secrets/user-passwd.txt.age b/secrets/user-passwd.txt.age index 6a22ccf..5903276 100644 --- a/secrets/user-passwd.txt.age +++ b/secrets/user-passwd.txt.age @@ -1,69 +1,72 @@ -----BEGIN AGE ENCRYPTED FILE----- -YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBnQUpP -cDBxeFZBWmVlclJZdkRWOHhnK29DRzBHQ2I1ekJGeDk3WlZpenc0CmhLMVcwbGFH -YzBHY1BEb2ZHK0FtZHEyUmw1UFVSaEsyMnR5cVUrZ1pWZXMKLT4gc3NoLWVkMjU1 -MTkgM2JCM1pnIGVuVWVnYmFmWUt4bjlwNU5oVXcvTTJZTllMTk1yQTU4YTVjYlVl -dHh1WG8KdXBPeWdpNlYrUkJXeGVpTXlqWWhlTlJBQVduR3JhSDRqWmJuSkRjNDl2 -VQotPiBzc2gtZWQyNTUxOSBxKzBYY3cgSzFXb0g2cUxGbUxxa291cVUvK01ZRUF2 -QW5iZDA0MG9ORXlSNVBheDZtbwoyWlhIUHo0TDJWeTNOdzUzVTI3QVZVY0pEczZQ -MXE0OVpNSktkTExWcHowCi0+IHNzaC1lZDI1NTE5IFpCM2U2USAwMkg3cmZQcTdD -WnhPbjlmU2M3RnU5MHE4NERBUDNzVVB2Q29OeG1iR1dNCnVna1VRVTdxMHgxczk4 -aGdiZ1VhWlNsVGhrc2ZXdFNzVU92T1dxbW4rK3MKLT4gc3NoLWVkMjU1MTkgajY3 -RlhRIFFocTlvTTlJbXdKZkdqd2NlRHM3b0E0TFozTXBkWlBXa1JYWWhmM3Q4d1kK -YitLd00xUGJReElHNm9DMFhmUGh2WFF3WDJGYW1ueXlpcEQyVWhqZUduYwotPiBz -c2gtZWQyNTUxOSBjMFROYVEgRHhtOU1iWTduQVdjRCtRNWRMMU14a3p4V2gvek9s -M202c2NoU0Q5ZTVIOAp5UEt0MnZ1VTZ0anVUeldSV1lBVHZvQU1CRUsrV0pHRjlw -enJFdEVPR0tzCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyAzcWk4bnozcTN0eFgwYlQr -dzRHekdmTlM4Wkdyd1p4Ujh4WnhJVnh5bEJVCkRnd0xlWkdXNE9BN0x0MjZyMDhM -YlU2OVNzTnZvZGhjSE1uMWlkMUo0T2MKLT4gc3NoLWVkMjU1MTkgakk4UkFnIDFa -QlhjWm9tZ05oYmNuanRvTkVOSUVJa09xUVFaeE41WDVRZlE3SHFZU3MKYWtkcEFP -bkMyMytEcnVjOHZ0SVJaT3lhQmZ0amxXVVV5Qy9NTml4TWNWQQotPiBzc2gtZWQy -NTUxOSBoTWE0bncgMGhKOHJCQTBsNng1U0FZbjVDZWUrVzFPQmJGUEhqTlJLS0Zn -NEdPYW9TQQpCUytPOUZ6ZkhUcCtHTHQ2WmJqWjQ5MWFuaGFPRVg0SktPVGlEUEha -Q2JNCi0+IHNzaC1lZDI1NTE5IGV5cTNkZyBrTXFLcU1oQnBtZjFuV3Q1VkpLcEt5 -aDBmY0pGb0FNMG9Sek5lTUhTWkdzCmtGanpyWXJNZDJqVjdEd1dHQk1Qc1Qyd3d4 -VTJKZHhpb2xzc1NYdjZoL1kKLT4gc3NoLWVkMjU1MTkgN1dROVBBIGs2ajVzVHE4 -U2Z4TmdYQTFGL0RCL0YvNnNmTEdJNEkwTXQzR3JxbWlTVzQKUzl5aVlJTHRUbEpi -MEFKdmNSWWpHQUl3U01QaXgrUm1rTVNKL3JRSnYyRQotPiBzc2gtZWQyNTUxOSBn -U3hQMFEgdXAzU0NRU2J0WlJCRDFha3U3UXAreDFKb2gvVk5sTWt2L3RiWW1xUUps -QQpvemtsNGVDUStHTnRlVVV1dHBUNys4Mm9tVlUxdG9CejkxQ3FXeEVPcWc0Ci0+ -IHNzaC1lZDI1NTE5IFZGY3c1ZyByQXlBUFhKT1VqUWhlcnVUak5VZVB4VnlXeHQ1 -ZG9iS2tHOW9iblBnTmdJCmhJU2RSU200MEJWaDF6bnU2NktZK3ZPNFVKS1hIejBq -WW42L0Zqb1hzMjAKLT4gc3NoLWVkMjU1MTkgaGtidHZnIGpVM3h2SjJNSTNPWUFw -VFVqOHRjUm81RGRNQUNsU1NOcXZGaDMyMUp1bTAKQjIzY3lxeWxodWtxbDNyamkv -Y1hjcTc2NDNyMEMxNkkxUHluaGx3YWppUQotPiBzc2gtZWQyNTUxOSBldDJ6cFEg -ZEZYQVN4TFkvQlBwSTVzNS9RVER3Wjk4NnZFa3J0OGFhQnNSMUcvUkZVbwppR3BM -UGNoWFQza0RYQVZOcE5Ea21tYTJpMFp6UUVoMFh3Ym14dGJUUldFCi0+IHNzaC1l -ZDI1NTE5IFpOcUlvZyBXSEhQNXRMaVBsMi9QUnZBUVNWU1RjdkRjSEF1ZGtVa1hM -RnVocFRqeTNBCmVGWDhndHZ6VGFXZW1BR0VKQ0dPYXVQc0RBbmJtaFl6RlEzWDhI -VmxWUjQKLT4gc3NoLWVkMjU1MTkgcUxqcXlRIFZSYkNlNDRTa0lwbGE3MXRZeWo0 -UDJnSGJDRDR3bkFPWEE1cTNwN0hPbncKU2grdG92aG5NRk9zTzd4RTAzVEo1NmlQ -dE9JdXVCa3luUWtTNXhlUjhBYwotPiBzc2gtZWQyNTUxOSBCYVFsUmcgaHREazZj -SmVubFlQS01WeTJ0N1NLWjBYMlFVUms1djg4Z0c5ZWQrdFJRRQpLYjhuOFVBamJR -MlVkTGxTMFl4YWloZDc1bTJqL2hOVG9VME5SdU51R0JrCi0+IHNzaC1lZDI1NTE5 -IHMrcVJmZyBwL3NwQjhHT2JzalVCMnVjQ1RCVXdmZkVEK1hka2U1V2VSMFhqeStM -OG5vClNiVVpUQ3NpWjhLNkQxUEVxWlpEVllST2RCamFTU1R3SXdnSWEzZHJucUkK -LT4gc3NoLWVkMjU1MTkgNjJKY2NBIG5iUTE4MjlTT2VoUXBuTkZPVXhHMVJVck1N -SmNGdmJvOUFwL0dpZTRoVG8KbVMveEg2aG02V0ZDdGlpMlptYUY4TjM2S2RPVGFN -Rnd5ai9zZXBxQXBJYwotPiBzc2gtZWQyNTUxOSAvaHgvZEEgQjNGMWUrMm9ZMHBT -ZDlFVVpLNm5lQVpaSy9WVlMrUGVDS2IvSmdWbHN3UQpscXFvZnVUVXRISHBKMjBP -dGVyOU4xV3d6dFhQZGJOY0E2NnhFSjduaUVFCi0+IHNzaC1lZDI1NTE5IFd6TEdI -QSBMa2k0V3ZvZ01oVmdBd0RlZ0NNSWYzZjI1disyL21lelFxdWE4UzJqTzBRCkll -VHBvZFB2T0pFRWlsOVdpQ3ZQTnZEaW4rUzlWQWp1aTJwSzgrcEc0bnMKLT4gc3No -LWVkMjU1MTkgSEovSjdBIE5YVC84RG5wT0pHb3E1YUJaTS84VzVrNlNWSVdSd1ZJ -Y1FEbUlGV3NqMjgKYThMSHdzQkZxSWlLS3NnM25uVXRnMGN6MEdheHFNN1liV0lZ -bk1JTmtVdwotPiBzc2gtZWQyNTUxOSBPRXFNc2cgSkx3QlNMTUFLQThDRkdweWxX -eEhLNHRheGZycFdIWXRjLzNSZmFOTUZqVQpKYS9FSS9FQkdheGQ2OVpaT1Y2MGRG -Y1l5OXJZWnRETkowM3dzNDYrQUVRCi0+IHNzaC1lZDI1NTE5IC9FSlh2ZyBHeTI5 -cmowT2xDU2EyNjV1djEyOXM1b1Myd2RCbmU2YjJ5ZFNKVk1UYkR3Ck9ad1RReFNM -U3JWSTdKV2FLbVIzaGIzR1BDN09UME83aGxsUkxpOU1PbE0KLT4gWDI1NTE5IG9z -VHgwWXhINTZndXpTSXdGMmdkdFpPRy8rQlJZUldDeFBVcUNvbUQrMm8KUytDdm5z -bTJTUnFwQnVkWXRrNkIrVnp4OTdZMUJqMkNnVVdGS0tJMjJiawotPiAoRCciTWs7 -LWdyZWFzZSBHPWFYZC1lCjNiejRKNTB1cUlzc1FtanlLQ1AwNmhUTkNuZHptLzBK -My9FZi9uVUd0ZlR1d04zS3BjVFJHZDR1cmNmNWx0YjcKQmdLbk16UW9DRE12UnVy -Y2twSS8KLS0tIDhENUJrVVQ2RWR0MTlhbksxODZYUWpnZFJJTTFWcnpoenEzVVpJ -SDlJTkUKjRfkdYqpB50PeibFrP5Xl930/HjYfKNpFGS7n2i8dwtVC/hFem8GshQJ -NwgE1/GIPq5gKVRKaVYLaQIKCrRZl9+SDTPQB4HcKKxOD/gW0cshXyjIqiY30keZ -ThF1h3sZbOkyGwNg/RGUFihEy+dZ7o/rpDKMAVkPzSFEN0fnS5N9GpJkuTIH074w -dA== +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IERMTWVGZyBVUDR4 +Um1XS00yUDFIRnYyZzg2KzYzanBIMWFNTmV1MVF6ei8rZDBiTXowCnBBRFEyQU14 +ZU5MdSt0NnRJdUMyMyt6dVlOWHBqUnkvRWNmMjNRUENKeTgKLT4gc3NoLWVkMjU1 +MTkgM2JCM1pnIHFyc2laWnBTQU0rcThOamJTcEtlUGNsSW8reTc2eTJjbVBkZlJu +cXEzbUUKcmFrTEVjaXY2a0lJNEtCWXNjTUsxNENkSWZmZUJhRm5ydWZ6WlJ1aDdR +RQotPiBzc2gtZWQyNTUxOSBxKzBYY3cgRVBuOEJ4K0NRVjdLdFhIU2Y3ZGQwL3F4 +clFjMVNsOWNvTU8wVlRoNG5CZwpycFRlMzFjZ0drN0t5QXpoMkJ4aERMYkxVSFhU +STJTdUNzeWtkUmFMTHVBCi0+IHNzaC1lZDI1NTE5IFpCM2U2USBBRUhnNlNzbDVX +Q1ArRENrZzBrNkhhSUd5dEZnM2oxRUtmYWx2L1NtbG53ClZIalNsaUNBUUtKWGpT +dTM3VExldm0xRXJoSWZ0SU4vdWk5SDlZTEFPczQKLT4gc3NoLWVkMjU1MTkgajY3 +RlhRIGR0VkhtNWxCK2xSYUNlS2hhdzRldEVZRDQwNmVnN0dtRTdOamFSM1Jqek0K +YS9uWGMyY3JzeUZCWkhLTzk4d1dxT0NkbEQ3UnlWOStCdUh0bkg3K2N3TQotPiBz +c2gtZWQyNTUxOSBjMFROYVEgYXJhZUdOeEphOGxkMTZmamJxdmMrTElkYkFScVA3 +alExSC9TVTJzeUFqNApsZXo1cC9wdnp3Zml4bG52ekFHMEUyU29acFFJeU1VN3Mr +ZlorWC9VWDZzCi0+IHNzaC1lZDI1NTE5IG44Q3BVdyBTenhVdjNncGxudDJ2Y3lw +K0JIOFJDd2VVQzFkWGc1STROdFZqbnUrYlJnCk5MTWxRYVRPcUFjMmdySEJ5Rndy +TzdnNGErNnBRa1dTSFVFekxQUitOYTAKLT4gc3NoLWVkMjU1MTkgakk4UkFnIGtL +c1psRWRRN1hNZUNiVHFmR3JGVm1jUWJtdm91ZVR6M01zNmhGdW9pRTAKNGpwek8w +QkRnSkZXUjhEMEpPaUdkeGwxZDRGbTRSMjg1Z1pMdEVSaTJEdwotPiBzc2gtZWQy +NTUxOSBoTWE0bncgYmRqR1FRaDdQQ09ZZHQwWmQxVUJ2QWdLYjdoRlNLU09GYUNi +ajJhMWx5QQo3ZWFNWjMvTzNxSXJjeTY5cTNMWmk0K0IzZ053Mmd6T1hhaVFTVVBj +NHBrCi0+IHNzaC1lZDI1NTE5IGV5cTNkZyBXbUdJKzdMZDF1NW1pTi94aUtjNGpo +aGVLbno0RzE1MXlURTJJQ3hRb1dVClg5K2FwRHBvcXIwVUl1U21GSnJsSmJmMGZN +cmdBcmRiRERzcjJmZzV4Q2sKLT4gc3NoLWVkMjU1MTkgN1dROVBBIEIrays1YUJN +TkRMS01oVzQyZEJuSjFPTTV4YkZSMDdTV0UvZE4rZ1U3SFEKWEZSL0g0dmFnelJC +S3VGZDlaTHhJQ3NaaEc2aUsvRmdKdjRNZ1VXMExmQQotPiBzc2gtZWQyNTUxOSBn +U3hQMFEgODNUUEg4M0hLL3RSUXk4M3dGV0tZNjJXQWxabmxLanF0Slc0WWMyUkNo +bwpCMGlaZDdodk4zeDROczVFc0FxM25qMFdicWZZSVpjb2tiT081bUVUTGFzCi0+ +IHNzaC1lZDI1NTE5IFZGY3c1ZyBKanVnSDI0bUhvS3RVbzdSc0s2TmQzSVdEczRF +eU1CazZPM094eEt1ZGp3Cm1HWGluLzhoRUtNRDZOcVJDVUR1R3dneHNHa1M1VGpH +YWF3TDQ5cS9saFUKLT4gc3NoLWVkMjU1MTkgaGtidHZnIHJLN2dJQnA4eGo5SnU3 +SkttSlM2YXNERXJOYjc1Tlo4NnhFakdYT0dqUWMKQllrZm83NHJrYmtWaytCc1VI +aVhESUtYeHpoT0JmdStSRURMZ0JldlQwYwotPiBzc2gtZWQyNTUxOSBldDJ6cFEg +d3NnSXpMRzU0QjBBL0c4SGw5Znl6d3hRdWxvbHdXZCtIeVdnU1F6MFVVQQpiQjVX +TSsycGZqMVNWajZHcFkyN2JwY2RqcGRlNitRWXgxWnN5TzlpU1lRCi0+IHNzaC1l +ZDI1NTE5IFpiTEpXQSB3VmFwR2ZqR2p4OXlpSnQrbExqTktkaEJ4emxLM2ZZbGdx +U0drOWtxUGprClgyYnd1M1NQem1rZkxwUk5tVXBLNGVDMFVjNjc5Lys4N0RsajZN +eG9LeEEKLT4gc3NoLWVkMjU1MTkgWk5xSW9nIFl3QUlPNnVHNXNwQ2sxRUEycFda +TkJsUmx0dCtRdnRVRVAzY3pPbm1LM0EKbVZDMHBSOFBiMFVQbkxHOGpkQjhrbDRJ +YUN0M2JPOW1PbjVtQURaUnVFbwotPiBzc2gtZWQyNTUxOSBxTGpxeVEgUXc5TUxn +YXk2ai9EbHdVeFVsUk96bHZIRFdlcDFqYkxLQ3FJaFBQVG93bwpTSFJ5dmJiN2tt +TVlLUlBhb3VmSG8zVHNYdC9HVjcwN3JUVVVWN3BFUkhvCi0+IHNzaC1lZDI1NTE5 +IEJhUWxSZyAxYkNsekljV0s1ZWR2eVZnSk9Oc2QvWjE2a2dMaldDYzJRU0FWUVE0 +Z0FvCnk5UlhrT0ZaK3FXTThVY0RKZlE0d0FTajJLRCtSNWdvWjd5V3hZNEg4dUkK +LT4gc3NoLWVkMjU1MTkgcytxUmZnIHA5cGpXWlMvTlVreDNremhCa1FDUlFVYk45 +OHhjaUhYTWZVa3dySzNLeW8KNXZnZzFPNC8zMExuMG4yUTJFMDgxTFdGdDZ6VVl1 +WEFGUC9zNVgrd2RRdwotPiBzc2gtZWQyNTUxOSA2MkpjY0EgMG51elJWRWRDNzRM +SERza2RiNFBoOHc1eCt0SWtmUy90dGl0VEd6QTJENApodnNBM1FkUlZ2ZjB6b1Np +QWNXdjVoNFlsa0NOQWp6TUw2TVQrU3VNRlVZCi0+IHNzaC1lZDI1NTE5IC9oeC9k +QSBxdlhXM3Rqb3J4YjVDUzdhUUVYQlFvSTJjZXA5MHBYY0NXWVR0VzllR2hzCkU2 +K2xCY2tGeEJjK1dMYkhCZ29pR3EzYndWUXF4bWorNC83d1E3U3luMFUKLT4gc3No +LWVkMjU1MTkgV3pMR0hBIGg1MjIydFM3YlM3aWVFR0h4TytwRWxYWTVkTXN4VkdW +TnJ0bXQ0WTduQUEKemtad2lsTTlPUEtUaVpFLzNPVFhqd3VpeWJWbDFyayt2VVhy +Q0FSb01rRQotPiBzc2gtZWQyNTUxOSBISi9KN0EgTkdKZUx2U1NTODZzTlpJb2xT +VFptQ3hWOS9BMCsyZXdsM3ErMXhtaHlFQQoyUnp3RW81VUh6OVRQcGhJOXYxNXRR +NHNGT3ZIU2ZQb2c5aEg0UmhRcG13Ci0+IHNzaC1lZDI1NTE5IE9FcU1zZyBLMi9r +bmFyTnBCU1lsdUpDWTJsd3ltRzAxZmw5eDNqVUtjMkR0OGF1dVRjCndrNmVHcmYy +c0lQOFM5SjBjN1ZqZXk1Vkk3RzA0b3JtaWZrdDBmdmFrYXcKLT4gc3NoLWVkMjU1 +MTkgL0VKWHZnIEV6eVNrNEZvVWhPMXppeFpmSEt1Y2NqcmtUOXAxQ1lOWVdtcnlm +R3B3VFEKVXJJRWlmOFVHZ3hyWWhLZE03VlNlM0M4ejFDYjM1b1c0YWhMMVcrRXlH +bwotPiBYMjU1MTkgUkRPY2JrSGZYeGNVWldVbTAzbkdtbHdUS1hoZXg2R2JEOGtC +ckZSOWV3TQpGejNQOUlxb05oWE9hRWdjbzI2a0NKVkpHMG1PMWlMWVZpYkVQNlpx +c2xRCi0+ICwlLDsrbWYtZ3JlYXNlIE8mcz1jaywgeiJbOE9FeyAjXFl4Ugo1c2VM +THdsOFlhODVMV3JsYzY3QU5Hb1BJTHBWNFEvalRHN3lXQlBBZFVvQXRIdXpXYVpU +b0NLRG40WWhMQ2hDCnZyS1d6SGxGekIzWUs2Uk5XSFRscTIrTTEwNzJKMExGcG5m +UWR0MWtBNnk4bDBYYStVQzFwZDlWRzRDNXJVZm0KajVrCi0tLSBkQ044Z3A5R0dt +S0htaUZaSzdPOTNCcXZrSWFVVHlTZk0zejBuT21yQzFBCo6rc9fznstf3eXBRUA8 +73MZAYqSnJ5wVMrYrwGfT9lXvKbHCOvkgjUI6Ieo0nuw+aZpXoV3t9HfZv62UEll +ZZVu+ieRCZqOOqZKKZ3TCP24vdXun8Tu+3YK8fyn88QSRH/0ZMnqI9FXbtsUhsF8 +2o7m7Fn48B0nVKy16HZyBsksknAuZCkfS/JOkgI= -----END AGE ENCRYPTED FILE-----