diff --git a/docs/README.md b/docs/README.md index 544666a..cd1e0c3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -53,6 +53,8 @@ colony (physical VM host, ams1) ├── git ────── Gitea + Gitea Actions runner ├── mail ───── Debian VM running mailcow (not NixOS) └── darts ──── third-party/customer VM (opaque, not NixOS) + +portcullis (bare-metal edge box for Nikhef — staged, not yet in service) ``` ## Site: home diff --git a/docs/networking.md b/docs/networking.md index 03867b0..b89a414 100644 --- a/docs/networking.md +++ b/docs/networking.md @@ -266,6 +266,10 @@ On top of that: `p2pTunnels` (`10.100.5.0/24`) holds point-to-point tunnel /30s public blocks and the per-customer `mail` / `darts` / `jam` prefixes carry customer-facing services with their own public addresses (announced by BGP, routed via the host). +This layout is expected to change: [`portcullis`](sites/colony/portcullis.md) is bare-metal edge +hardware headed for Nikhef that will take over most of `estuary`'s routing. It has no assignments +yet and the replacement topology is still being designed. + ## home The home site prefixes (`lib.my.c.home.prefixes`) come from `192.168.64.0/18` and diff --git a/docs/sites/colony/README.md b/docs/sites/colony/README.md index 82de5bc..cdfa6de 100644 --- a/docs/sites/colony/README.md +++ b/docs/sites/colony/README.md @@ -24,9 +24,13 @@ prefixes and routing overview are in the [`colony` section of networking.md](../ | [`git`](git.md) | Gitea + Gitea Actions runner | | [`mail`](mail.md) | Debian VM running mailcow (not NixOS) | | [`darts`](darts.md) | Third-party/customer VM (not NixOS) | +| [`portcullis`](portcullis.md) | Bare-metal edge box for Nikhef; being staged, not yet in service | The applications running on `shill` are listed on its own page — see [shill/README.md](shill/README.md#containers). `mail` and `darts` are host-defined VMs whose guest operating systems are managed out of band; their pages document only what this repository controls. + +`portcullis` is new hardware headed for Nikhef that will take over most of `estuary`'s edge routing. +It is not deployed yet and the resulting topology is still being worked out. diff --git a/docs/sites/colony/portcullis.md b/docs/sites/colony/portcullis.md new file mode 100644 index 0000000..246dd9d --- /dev/null +++ b/docs/sites/colony/portcullis.md @@ -0,0 +1,60 @@ +# portcullis + +A bare-metal box destined for Nikhef, intended to take over most of the colony edge +routing currently done by the [`estuary`](estuary.md) VM. + +- **Source:** [`nixos/boxes/colony/portcullis/`](../../../nixos/boxes/colony/portcullis) +- **Host:** bare metal +- **nixpkgs:** `mine-stable` + +## Hardware + +| Component | Inventory | +|---|---| +| Platform | Mini PC (no vendor DMI strings) | +| CPU | Intel N150 (4 cores / 4 threads) | +| Memory | 8 GiB | +| Storage | One 128 GB NVMe SSD (`nvme0n1`), partitioned as a 2 GiB ESP plus an LVM PV holding the `nix` and `persist` volumes | +| Network | Four Intel I226-V 2.5 GbE ports (`et2g5-0`…`et2g5-3`) and one dual-port Intel 82599ES 10 GbE SFP+ card (`et10g-0`, `et10g-1`) | +| Management | JetKVM (HDMI/USB KVM with virtual media) | + +## Role + +Not yet in service. The eventual job is to be the physical edge for the colony site at Nikhef, +taking over most of what `estuary` does today — WAN termination, firewalling and NAT, BGP for +AS211024 and DNS. Some of that functionality stays on `estuary`, and the surrounding network +topology will change with the move, so the split is not settled yet. Until it is, the config in +this repository covers only what is needed to boot and reach the box. + +## Network assignments + +`portcullis` has no static assignments yet. It is being staged at home before it is racked, so it +takes DHCP on the home `lo` VLAN; the colony assignments land alongside the routing config once the +topology is decided. + +## Networking + +- The four I226-V ports are named `et2g5-0`…`et2g5-3` and the 82599ES SFP+ ports `et10g-0` / + `et10g-1`, pinned by permanent MAC address in `.link` files. +- Bootstrap only: a single `.network` matches every `et2g5-*` port and takes DHCP, so whichever + port happens to be patched in brings the box up. `wait-online.anyInterface` keeps boot from + blocking on the unpatched ports. +- kea registers the DHCP hostname, so while staged the box answers to `portcullis.dyn.h.nul.ie` — + which is also what `my.deploy.node.hostname` points at, since there is no colony FQDN for it yet. + +## Storage + +A single NVMe SSD, following the usual tmpfs-root layout: a 2 GiB ESP at `/boot`, then one LVM PV +in volume group `main` carrying `portcullis-nix` (48 GiB, `/nix`) and `portcullis-persist` (the +remainder, `/persist`). + +## Secrets + +`my.secrets.key` is the SSH host key adopted from the installer session at install time (seeded onto +the persist volume before first boot), so secrets could be encrypted for the box without waiting for +it to come up. The box declares nothing of its own yet — only the default `user-passwd.txt` that +`my.user` brings in. + +## Notable config files + +- [`nixos/boxes/colony/portcullis/default.nix`](../../../nixos/boxes/colony/portcullis/default.nix) — hardware, filesystems and bootstrap networking. diff --git a/flake.nix b/flake.nix index 62ca132..61f89e3 100644 --- a/flake.nix +++ b/flake.nix @@ -181,6 +181,7 @@ # Systems nixos/installer.nix nixos/boxes/colony + nixos/boxes/colony/portcullis nixos/boxes/tower nixos/boxes/home/stream.nix nixos/boxes/home/palace diff --git a/nixos/boxes/colony/portcullis/default.nix b/nixos/boxes/colony/portcullis/default.nix new file mode 100644 index 0000000..22293b0 --- /dev/null +++ b/nixos/boxes/colony/portcullis/default.nix @@ -0,0 +1,115 @@ +{ lib, ... }: +let + inherit (lib.my.c.colony) domain; +in +{ + nixos.systems.portcullis = { + system = "x86_64-linux"; + nixpkgs = "mine-stable"; + home-manager = "mine-stable"; + + configuration = { lib, pkgs, config, ... }: + { + hardware = { + enableRedistributableFirmware = true; + cpu = { + intel.updateMicrocode = true; + }; + }; + + boot = { + kernelModules = [ "kvm-intel" ]; + kernelParams = [ "intel_iommu=on" ]; + initrd = { + availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" "usbhid" "sd_mod" "sr_mod" ]; + kernelModules = [ "dm-snapshot" ]; + }; + }; + + fileSystems = { + "/boot" = { + device = "/dev/disk/by-uuid/1A70-EBCB"; + fsType = "vfat"; + options = [ "fmask=0022" "dmask=0022" ]; + }; + "/nix" = { + device = "/dev/main/portcullis-nix"; + fsType = "ext4"; + }; + "/persist" = { + device = "/dev/main/portcullis-persist"; + fsType = "ext4"; + neededForBoot = true; + }; + }; + + networking = { inherit domain; }; + + environment.systemPackages = with pkgs; [ + pciutils + usbutils + ethtool + lm_sensors + smartmontools + ]; + + systemd.network = { + # Only one port is patched in while the box is being staged, so don't block + # boot on the others coming up. + wait-online.anyInterface = true; + + links = { + "10-et2g5-0" = { + matchConfig.PermanentMACAddress = "00:d0:b4:05:ed:48"; + linkConfig.Name = "et2g5-0"; + }; + "10-et2g5-1" = { + matchConfig.PermanentMACAddress = "00:d0:b4:05:ed:49"; + linkConfig.Name = "et2g5-1"; + }; + "10-et2g5-2" = { + matchConfig.PermanentMACAddress = "00:d0:b4:05:ed:4a"; + linkConfig.Name = "et2g5-2"; + }; + "10-et2g5-3" = { + matchConfig.PermanentMACAddress = "00:d0:b4:05:ed:4b"; + linkConfig.Name = "et2g5-3"; + }; + + "11-et10g-0" = { + matchConfig.PermanentMACAddress = "60:be:b4:2e:9b:a2"; + linkConfig.Name = "et10g-0"; + }; + "11-et10g-1" = { + matchConfig.PermanentMACAddress = "60:be:b4:2e:9b:a3"; + linkConfig.Name = "et10g-1"; + }; + }; + + networks = { + # TODO: replace with the colony assignments and routing config once portcullis is + # racked at Nikhef. Until then it is staged on the home lo VLAN, so every 2.5G port + # takes DHCP and whichever one is patched in provides connectivity. kea registers + # the DHCP hostname, making the box reachable as `portcullis.dyn.h.nul.ie`. + "80-bootstrap" = { + matchConfig.Name = "et2g5-*"; + DHCP = "yes"; + networkConfig.IPv6PrivacyExtensions = "no"; + linkConfig.RequiredForOnline = "routable"; + }; + }; + }; + + my = { + # As above: no colony assignment yet, so point deploy at the staging DHCP name. + deploy.node.hostname = "portcullis.dyn.${lib.my.c.home.domain}"; + + secrets = { + key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAUolR93Byg+Daw8pUYHVpQ34ioxSc2C8vzj9F4KbqMs"; + }; + + server.enable = true; + }; + }; + }; +} diff --git a/secrets/user-passwd.txt.age b/secrets/user-passwd.txt.age index 7d2787e..5647576 100644 --- a/secrets/user-passwd.txt.age +++ b/secrets/user-passwd.txt.age @@ -1,76 +1,80 @@ -----BEGIN AGE ENCRYPTED FILE----- -YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHNqUFR5ZyBkWHB2 -MHNUSnRIQkc4OENhN2dVdVlFZFRlWW5oVW9WbENaTGcwK2ZnQVFRCkQyYjdNaEtK -SXE5RExTMm9EZC9GSEJGcWNabUgyOERBZmFmV0VqRFVXWTgKLT4gc3NoLWVkMjU1 -MTkgRExNZUZnIEhJNHN3c0lGL1lrMTA0ZHV2bHdPZ0dveDNBNVlzazEwbU9NcVZl -Z3RKelUKaWEwTTZvSTA0T2pKSGVoc3gwL3VPWjNPOFk3dTNjYVo5S2tPWUNtV3Fw -dwotPiBzc2gtZWQyNTUxOSAzYkIzWmcgMEN2dDJiRHYrQzRIb1JJVXp1V0ZyMkdu -RWNtKy93QVR4SVJkK1VXTlUyQQpNdUU1c1NOdi9ZbmFTNHJBWmNTZFp2NDZORWp1 -ZzZzMzU3ZWFVYU1Lc1k0Ci0+IHNzaC1lZDI1NTE5IHErMFhjdyBiVS9ZeVE5Vytp -a3p2c2xYM28rM0Q1UWMyNkQxYWRScStGRGVhTTYvQWc4ClNvSksydmhid20yTzNC -ZHF2b252MWwzRG9Zdi9uRVpqL1BacGRaemo5OEkKLT4gc3NoLWVkMjU1MTkgWkIz -ZTZRIFVZUTVjNS9pak9JSnF4N2JOMEZINmtKTzU5OUxHbHRKeng2cldvK2NXU2sK -T0M3QTZJU2lqMk9nRGl2c3QwNTlWOEwyYVJUK3pleEtMZ0lYbm9TSmVUZwotPiBz -c2gtZWQyNTUxOSBqNjdGWFEgRzRXYTBxQWduN2QvZk84NXVWVHlQN2RiS0pkYXM2 -U2cvM0JKRXZvTjAxdwpCbWdMZVpMaXBBNHRRZjN4aU5lNmhRNmMzSnBIWUNtbW1w -ZStLaXlUL09ZCi0+IHNzaC1lZDI1NTE5IGMwVE5hUSBxK09aSTRaUzZ4VnArMlF4 -ZFZvNmUrR1hPKzB1SUdRS2Z2dmgyVlROOUVZCllUcDNCSEpVUmVUN2RSYjZ5aDdp -SWhCVFlwcWxJMkxodEwrQXNDOTh0TlUKLT4gc3NoLWVkMjU1MTkgbjhDcFV3IHJ4 -Y1krN2hHTjhOakZSZ3VNNEZnYVVLb1BTZ01iT2dyRjdUdkRodit0QUkKRitpVFJB -WDU2eGw2aUhQZFcrMTB6MU5VTURPNE5HbUFYendOMnNDRXRQcwotPiBzc2gtZWQy -NTUxOSBWN2xnR3cgcUNRZkp6R0llR0o0RmhvanBoamdoNVBKRWl0Sm1sQVhBRGJw -MFFDcmdUbwpENlEvaTh4OUhVQ0VTeXBGMTBoajd1eE42YzYvc0ZvcWlVYU1HWnkr -R0FnCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyBFdEpIT3F1MGVtZ0ppN05hVDBLRjZz -eTRWdjZkMGM0SWpqeVJpRXRGc2pRClVpTlB6Q3lCZ3FXd1g1eXU3Y3grRVBJRjBC -aERTanp4dDhGRFdteThNNTgKLT4gc3NoLWVkMjU1MTkgVCtzYkdBIEpselBValht -TTNtY2lTYWg3VHBUTWNIemdiQXpHd01jMS9BeERMclQ0RGcKYU85dnN3ZEJyQmZZ -ZE9ZYXl4Ym1BZlBkcm9jMXBhZ1J3aUlxR1dPNm96dwotPiBzc2gtZWQyNTUxOSBo -TWE0bncgcXdIK21EVDVMZGhMMEltQ3RNbkx5NDhGVWRVdU4wZlhUNDY0bEZTcEZG -QQpUSGZOb0FoSTgxckp0R3dxVjVPZkQ0b3Z5WXpjU1Q1Qy8zaGNVNzh4ZGJvCi0+ -IHNzaC1lZDI1NTE5IGV5cTNkZyBwaGF3NXVNWUVQUUpuUm9pVHVRK1NoV1FmVFMz -dys1bE9WaDdNV0RXZFRVCmVJSUx0VkQvbDRjOWdvNlhCNm9RSnhnUHFpYnp0ZjVM -UG82UElhM3R6MFkKLT4gc3NoLWVkMjU1MTkgN1dROVBBIERKYnFGQm9pVlIzYWxu -M3Fza0RucE9SczQzRk5ialU2R215L1NwcVU2bW8Ka2hCL2JSU1c1bEhFS0t3VnEy -YWtaMG5mZHBxYjNkK0JQUjlmVHJYSmNUMAotPiBzc2gtZWQyNTUxOSBnU3hQMFEg -VHhRN0VEV0xGL0hJUHd1V0drWVJzaWtucXJ2c2xMUVpYMFc2TklLUGdYVQp0VWZj -UEZGeGhaRDh4SmFsek93ejBUM1A3OVorTWFmcWt0QkVCZmV0QU5ZCi0+IHNzaC1l -ZDI1NTE5IFZGY3c1ZyBmOHgraG50b2NiREZIcjRacTUwZ1Z3R2h0QXlHMTl6SFNJ -Qlc4MTFtT2k4CkVSdzY3cEVpR3J3L0szMXBVdmd2OUFsWGJwanRtSGl3QmRyREhJ -WjRwS2sKLT4gc3NoLWVkMjU1MTkgaGtidHZnIGVVNDZzenBDRlRmeW4ybUJqamRD -UFFpWDY1ZjJuK1VQNWJJSGIyaFJnbmcKcmg3b284YmZQUWt0clBjVDZVZk5CUUlo -aFRWWUwzVmVPcFBDaW1xKzRqSQotPiBzc2gtZWQyNTUxOSBldDJ6cFEgWEZpOXdx -bWo3NnZYSjFTdldoSDBBMVVobHRXYWJjZEd2RVBIanRrQUZROApkZG82RUZHSkRH -TGkyTG1tRUlRMEg5MVRwRHNjTE9UL1BMRUpDdXVLZ2tVCi0+IHNzaC1lZDI1NTE5 -IFpiTEpXQSB0ZWtnRFVWKzRkSU45enFadkx6N3FpRmE1MnByZEljd3FyWGFyd2Ja -QVNvClpiZkxsQ04zR2pzOXBtODdnbjdSaHBtSVFVT3V2aFdyZ2FoaytISmNzR0UK -LT4gc3NoLWVkMjU1MTkgWk5xSW9nIHMvWElOMTgvR0ZveHZLSlVqNW9PSmNvdm92 -ZW92dHhvbG8vRzl2NFdqMFEKUktLWEJuQ25LM1J6OXBvRlRlMEFEeXlhV3M1Yk85 -Wk0rZWJMQ3U2SVYrcwotPiBzc2gtZWQyNTUxOSBxTGpxeVEgODlpYkhNQmFkNjlp -ZUYyZ0VDdzBsTmk5TGVPU0VTRnZlSUdMazN3cXB4awpGbEhWMVR0N0NzTGljeEpw -dWtrTXR0QW5CVHE5enA2dXZZNm55ajVSa3NVCi0+IHNzaC1lZDI1NTE5IEJhUWxS -ZyBJc2xSZUJkaEd5U1EyV0J6T2pUU1ZWMnRPSzYwNFRERndsdThYeFFQSUVJCmlT -OWh1dnpNRDU5WlNSaW5FTUZ5QVVHSmw0NUpQMklOb3JYU3FSM3ZTWEUKLT4gc3No -LWVkMjU1MTkgcytxUmZnIERvYU1PNXJkWEs0VkI5YWNuY3ZGK2xpVkpxN01zbHA2 -cm9DUzk1WHIrRWsKZVRGWUwrdmVnOTh4clFHdm1yL0JuSVRpVldjWkMwUkdFTk5J -LzNlT0dZUQotPiBzc2gtZWQyNTUxOSA2MkpjY0EgTXI5QVZySXpsQlVoTE51c29j -MWltaUZHZUlPUEo1WXZNdUUzSWdWRU94MApMVUYzYlhNZDc5RTRzc0NxNW5PblU0 -WndIV1FZTm51ZlhQdWFQa2NNS25FCi0+IHNzaC1lZDI1NTE5IC9oeC9kQSBWUkJS -ZmR2a3BDdHRrVUhqejFjZFI4cWw1MEkrRWUwdHZHZEloemtUT2pBCmFYU21lRllo -MTlic204cU41Vi95dFBMSSs2eWtVSzJndG1keWdVeUgxNFEKLT4gc3NoLWVkMjU1 -MTkgSEovSjdBIGhhck53d1ZzYVY5ZjF5VHpXYVBDMGZ5SGdTL3B4NHQ2a3lENGti -NXhZVGMKV3B0d0IwNm5qM0xDUWdOTEZ3Q3ErWGdNRmtIeTBMSjV1eDYzMUVYVFpY -cwotPiBzc2gtZWQyNTUxOSBPRXFNc2cgcm9ZOS81emFxd2toNTRFUW1LRi9jU3FF -VUdYRzRWTm5uV0ZjclJPZmsyQQoxZnRtTzZ5YzRJTVRGalU4NFZhQmZlMjhtY2Nv -Q1oyZURhQUpjR2dvRVNRCi0+IHNzaC1lZDI1NTE5IC9FSlh2ZyA5aUNiQk1FZUtU -S0hta1lOMVlWL1RwdjUvQnl2MTg5VWQrMnNCVERkVkZrCkFraTR4UmFBbXpOR1lq -TTFCSmZmV0R1VjhWb2V0RXdiYkpaek0rdGVsRE0KLT4gWDI1NTE5IEpZSlNOZk5D -WlZ3VFFpVUx2RHlwblVEZHZyVVNGbHNrZ3hUY1FYQUJNMWMKYlo4dFVnS2hhYk1m -THZXMktudExKdEE1enlGWUgyM3FiMGpFbmR6RkNyawotPiBGImFlO2V5Ky1ncmVh -c2UKdTZXVjRtcTR2TDFITzB1d3J3RG1hejk1am15SEswR05PMFdoTXR2UVpoRE9H -dkMvQldlc1FPWlRFSURXN3ppSQoyU0pSRHFIS2I3d1dtTE5OTFFXSTYyR2tTbTZB -RDVROStRCi0tLSAvWEcyR09pQnRhSzN4d2kzSzduOUVtTXd2U25CWmZJdWt5NnNl -RHVieGNBCi411IjgmUKttjX6ljaZGWivstOajx2pkTVLV/zFiEj3jv+KDGy1psZQ -no+eatGMO8LeJhGJ6H7TBKOmJhFMfoQp1XKJA8OGY+FGZ98bit04djo3jqbVSOms -JSPRTvTxxQx+40yO+ETV+2qkRU1OdJTobz9YvuqGlHrJS8UNN30QMPT0ienu3QTY -Tbo= +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IHNqUFR5ZyArcmVy +aWRwblUvTDlpdzVjTy9GdmsxUSswVlBoa01WU0J0WjVPNTlaazJZCnpjYW14dkU5 +RFBZS1B2V0J3U2ZkUzJCZlN3WUZ0QzUvRGc3QkUyL3VXRWsKLT4gc3NoLWVkMjU1 +MTkgRExNZUZnIGFFanNQbkFRQzJxcU5heE8xRlM2clZTaldSR3M2SzVyMHJDakFt +eWNHU1EKcWFka3hQajV5d1NiaENUNFhOUlpoSFlJUm8xSWNXVE5HaGM3blp0OVAy +TQotPiBzc2gtZWQyNTUxOSAzYkIzWmcgdFNqcnJoWjh1SDN5Vml5UC8rZ1NXSi82 +Sm11QXJKUXI5Ulc5Mi9rL3UxawpzSFVXQzBQbUZFM3l2aHlIU1dzREMvRXdrMWFL +cEptWW4yVWF6aTJTVUdBCi0+IHNzaC1lZDI1NTE5IHErMFhjdyBCTnhBMG5RcTdt +MHg5aVN2ZmZQR3VTcFo1K3lBMTh3c2dBRjlzRWdjM2pvCkpwZTFZVExJc25aLzFy +OWZsNjVzMmNRREJ4ME56TVRneEZIdUdqODVZZnMKLT4gc3NoLWVkMjU1MTkgWkIz +ZTZRIDlvYURqSFRVNUdEM1lIV3oxQ00zMG5CNXIyNnhrVXpFd3VhS0IwTDhqRlkK +UzhsN3hLSUpQZ2lrNHNVd0s1aXBIY3ZaVm0rZjlXU0RSbU1Bb2h2NlBNawotPiBz +c2gtZWQyNTUxOSBqNjdGWFEgaUsxSzNGS09nMGo0eXlsUVdDL2R5UjVXYm9PZ3R1 +R0cra1JWbldnREJ3UQozeVYveGNUTExDUEJjT254NGlzTGxLSkl2akpqRnVmWU0y +Z09oZFQ0YnFzCi0+IHNzaC1lZDI1NTE5IGMwVE5hUSBIQlZSU3VOYythUHo2NERV +cE1rbDNlazMzZk1CMlJaM295K09POUZUc1dJCkZ1Ui9DZ2JsUm9FWithQmMwcHpm +SkNTcEtpSWVJdjJoZG1KY29hSEIvdDQKLT4gc3NoLWVkMjU1MTkgbjhDcFV3ICtP +dUUwMGx4WEtkQ21ySEFMREVXMHJaSitPalkxdXpPZTJJczZsUEI1MWMKVzRaOE10 +MEhjSHFVZW1RKzVDNnBYV2EyQXFTc2ozcVZlb0g4Z20zV3hROAotPiBzc2gtZWQy +NTUxOSBWN2xnR3cgSmY1VEE1TjVROTU2U3lvMFNuaVhKNXlrNm1GV3NPSGtIZzhJ +YkVNV1hXSQpZVzhlMnd4OTViN1ZmZlI2TkRMZ29sSU8rY0ZxcUhxY1U3UlM5MHRi +N0VBCi0+IHNzaC1lZDI1NTE5IGpJOFJBZyAybmhuVGIzd1V3cCtoS2UxdVJ5S1p6 +UmowTEpvSDA2Mjl3Q0dBeENhUXlJCmFCWkZ5VVBKUnRtTGlvcUtMblJWNlVPTHRa +RWdJY3kyL2dyUTV4Y09CWTgKLT4gc3NoLWVkMjU1MTkgVCtzYkdBIFE0R1hTaVAr +aVBObnNVdkx2YVJ4TTJKYk9QUVhEbXlFQW1ESXVmWTBSbDAKVkJwRlZNVlBwNVJx +WE9vVjl2OXFQcnZUTCtSS0NVQ1dFUmJXaDlhcVYwSQotPiBzc2gtZWQyNTUxOSBo +TWE0bncgc0o4b2VsUDZsRDFlaFlJWEpkNU5jRERnWGJ0blJMbXhkR3RWQ1gxNkpB +dwp4YU1WdGpJNUtQc09lRDdFVXNZdThWUEVnZDFvdVhUaW1JZUdQaGlId0NRCi0+ +IHNzaC1lZDI1NTE5IGV5cTNkZyBJTzdrSFdVTERDVk5hNHZsL1N6U010Y1ltZkpY +VS9vUXl6N1FDV3pvWUhNCm1UUHZNTUlrMjdybkVEaWV1NmVlY2hFeklJZndFQUpP +VGRNbzZ2SXVPVncKLT4gc3NoLWVkMjU1MTkgN1dROVBBIDdzKzBGUGNXZTYramx2 +VnAzYlcvOTZ6MTRtSGZTRFY0SFluQWMwTVdsMncKTG83dWdTbldMbnRBMVkwSnBu +QkxDTUhhUERXeUl2UXVEaldvRjZtQXZsbwotPiBzc2gtZWQyNTUxOSBnU3hQMFEg +SnBrUFhPa3dmMC84V1E0VVlyUC9VME1HWThPaDNxKzZLZC9Ybnd5aHdsYwpxQk1m +SW9TY2NOSExZeVJGY3NUbVcvMm5OUytjUnhJR1ZFV1NZUDRqdnRrCi0+IHNzaC1l +ZDI1NTE5IFZGY3c1ZyBac29qNmN5aGhpNDVVRHNsc1NIYzViZUdZK2tnSzFTc3pr +SWxFcXFONzNrCmxRK1haWkJ6aXU3amNPZ2hlMnovUDllTGMvSGZiTnNJWjhZN2k3 +VnFmMzgKLT4gc3NoLWVkMjU1MTkgaGtidHZnIG41VkQyQW9rcmY2N2E2Qmc2bUds +bWpUSWsxVHMvS2ZGUXhvSjNnanA5d0EKRE1IQ3UzNWE4VFdaQXZGakNscEE3RkQ3 +V2FESTdIWGRFOWV2QmpuaWZOYwotPiBzc2gtZWQyNTUxOSBldDJ6cFEgM1NwL3Jt +WDBHQmErN2JzNUVTelVqb1dRMzlha3NYVEVvRGRrMW9jN0ZoWQpkZ3N1TUExRVhz +aEE1QXFEbytySkdlcmpyV0JvRzFpRUZJc0VlenhBNDg0Ci0+IHNzaC1lZDI1NTE5 +IENrT1RXUSBCSU8xbTBNaXRqK0kzZVZOUGo3ZmZYd09sMTd6UHJvU2t5SUJBams1 +R0FjCjEzSEN0ZXd2NmI1M2xvWG1CRTNtcUZZZHhjOVpqemNXS3ByQWtmSy9MdmcK +LT4gc3NoLWVkMjU1MTkgWmJMSldBIEx6TUdIT1I4VEIzbXFBdWh0eFZKSnN5R2pZ +VjhYejVtczZSTko5Ty93M2cKNUlBUHFKd0JwNFFHYk9pcnpTcVYvWmZrL3BIWDUx +cW9vOEpkM1J1emorSQotPiBzc2gtZWQyNTUxOSBaTnFJb2cgY1VUU3BJeFBRYkN4 +aWFsWEVWL2NHenYxODcvcnJHZXhRbERFU3YzQlZ4UQo4Z000SGJia01MdHpQU1kw +VjRLWXhGczJNWWNMdVhWV09TUXB2UE1PejZZCi0+IHNzaC1lZDI1NTE5IHFManF5 +USAzOWRKUTZDVTVpVlFuWGgrdlNYN2RBQXArbFNoN1k4OWxQR0VIZHRUWXlvCi9Y +blkrellUVVROYUMyWHdBK1NHdjQ5YWs2blpvbS9JZVkybUVPbFRxb2sKLT4gc3No +LWVkMjU1MTkgQmFRbFJnIDhoR0lXTlNLQ3Z2WTZXQUFlQ25odmJPeFI1TWIyWUlv +SG02SjFYR29HQ1EKKzlqaTdMWmpwVCtQWDFDZlk3aXQ0L2t3YkZudHAzSC9WK2Vr +L3RXbW44SQotPiBzc2gtZWQyNTUxOSBzK3FSZmcgYzFia3NxQWJvOFFqa3g2ZkFL +YVlXOTRzdTFUZWIvV1piM2RDSDh0Z21nUQptQ1dSSC83Wnd4cnJQcDNPRlhtV24v +THZ6bUd6Q25SU0Q4b3R6Y0d3dkQ0Ci0+IHNzaC1lZDI1NTE5IDYySmNjQSBCcFhE +SUVnRzZCQitpNjd1S0h4VmxWSzBDMlkrbURLVlZ5ZzIzWE1TUlZrClF0bVh3UU5k +TFRvWlc2Z2pXMzhiY3ZyN2g3akhQa25zY3NhSEhWV05DUFEKLT4gc3NoLWVkMjU1 +MTkgL2h4L2RBIHc0UWp1WEdNWnJsaUpVTmU5Q2tITGNNYkRFcEllUENTMDgyOCtG +NCtIM1kKVmV2MjB1WlAva0xKMDdrWE43NUV1YXNOc0FTV0NNbnZuaXpVTWhvc2ZL +bwotPiBzc2gtZWQyNTUxOSBXekxHSEEgdmJRZU5SVCsxelMxOXIwZ3FLeEhlYURX +cmptKzQvZkZUZVJzM1h0UENYbwpTempycGIrU3J0b0FvaTJOek5VZ2RzeTA5NGRC +N1JYY3hMYVVLM1diZE44Ci0+IHNzaC1lZDI1NTE5IEhKL0o3QSBSRkZyTXJ1djhJ +aWt4Mk9iaitSSTdtWk9Eeklvb1VLU2oxVmQ1L0NDYUZzCkdIcmJBQ0RqbFlDdHh4 +a0o3Ujd2ZEZPbFJKOFozS3UxR3lldERYaVY5S0EKLT4gc3NoLWVkMjU1MTkgT0Vx +TXNnIHgwbTFxV3ZrR0h2SHBocEluZTZmSnBmUStKMkNtRVhTZTJNeVM3akZjVUEK +V3FKZGlxMmw3QzB3VnAxUXBnK2RzdUNUU3MwSHVIcXg3UHFVSyt1QklhSQotPiBz +c2gtZWQyNTUxOSAvRUpYdmcgSVdJOVdaNW9PdVY5TE9iNjFlY0ZQN001dnNENWR6 +cU5DSTVpcEMvRHpSUQo5SnZmMmRCdldKQ2VCSC8zaG1yTVMra2p3QkZHNVF3WmNR +a2VMNlJpRXNJCi0+IFgyNTUxOSBYU3VVMkttYUc5NVpBU0FSZk5MNXIvRVIxd0w5 +RHZxcmdLb2dmaVlTWGxZCm9lNUloSGJxcmYvcFVkc3dDNXNmUkZNbXB0elpwMVBB +dWdpSTJZQlgwUk0KLT4gPipeLWdyZWFzZSA8ZCBNcmxSP1BrCjZpcVoxcFNmV2Zi +K0pxeHlKSmJ0ZWNIdm5mYk1Wano5VHZBb2wxTExxT0dKajFNMnZGU1JYODhXT3Jy +MElGNG4KUEh2V0MvZkg5UmN3SVJEajQ3NVhXUk5YWFZPVnFyZkpsRjhnCi0tLSBS +Ulh4WkhVY3BuYXFicjhoN29DbFJwemlrczFQcUxpMTNaRXFLOWc2YTJFCvATVcNx +h0TZBbnm6QBWZVNDRiU8yHFAgaS/25pRvcaixnji3NkeKYYuEEnVSw6oUthhVSSg +g222QeHfXortX7m+/zTD0uIhdVm7e+emA8LBxsQEOgeDy33XA3Hi9yX2BFGV7l82 +NTBlLbCiH0mlFZ6ZO8rtA/nMcriCQUb2QZ+TaSGAop4RHObEeFw= -----END AGE ENCRYPTED FILE-----