From 495d54def88b24a97a61edde2d551b9366691473 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Sat, 24 Aug 2024 03:36:28 -0600 Subject: [PATCH 01/24] wip: add authelia config --- sys/srv/authelia.nix | 106 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 sys/srv/authelia.nix diff --git a/sys/srv/authelia.nix b/sys/srv/authelia.nix new file mode 100644 index 0000000..914ff47 --- /dev/null +++ b/sys/srv/authelia.nix @@ -0,0 +1,106 @@ +{ + lib, + pkgs, + ... +}: +with lib; { + systemd.services.authelia.serviceConfig.LoadCredential = ["storageEncryptionKeyFile.txt:/var/trust/authelia/storageEncryptionKeyFile.csv" "jwtSecretFile.txt:/var/trust/authelia/jwtSecretFile.csv"]; + + services = { + nginx = { + virtualHosts."auth.posixlycorrect.com" = { + enableACME = true; + forceSSL = true; + }; + }; + + authelia.instances.main = { + enable = true; + # config based on https://github.com/authelia/authelia/blob/master/config.template.yml + settings = { + secrets = { + jwtSecretFile = "TODO:"; + storageEncryptionKeyFile = "TODO:"; + }; + + theme = "dark"; + default_2fa_method = "totp"; + server = { + disable_healthcheck = true; + port = 9091; + host = "localhost"; + address = "tcp://:9091/"; + }; + # tls settings not modified https://github.com/authelia/authelia/blob/master/config.template.yml#L53 + log = { + level = "info"; + format = "text"; + }; + telemetry.enabled = false; + totp = { + disable = false; + issuer = "https://getaegis.app/ or whatever you prefer"; + # default values assumed https://github.com/authelia/authelia/blob/master/config.template.yml#L181 + }; + webauthn = { + disable = false; + # default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L231 + }; + duo_api.disable = true; + # identity_validation default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L266 + authentication_backend.file = { + path = "/var/trust/authelia/users_database.yml"; #TODO: + password.algorithm = "argon2"; + password_policy.zxcvbn = { + enable = true; + min_score = 3; + }; + }; + access_control = { + default_policy = "deny"; + rules = [ + { + domain = "meet.posixlycorrect.com"; + policy = "bypass"; + } + ]; + }; + session = { + cookies = { + name = "posixlycorrect_session"; + domain = "auth.posixlycorrect.com"; + authelia_url = "https://auth.posixlycorrect.com"; + same_site = "lax"; + + # see https://github.com/authelia/authelia/blob/master/config.template.yml#L756 + inactivity = "5 minutes"; + expiration = "1 hour"; + remember_me = "1 month"; + }; + + # see https://github.com/authelia/authelia/blob/master/config.template.yml#L774 + name = "authelia_session"; + same_site = "lax"; + inactivity = "5m"; + expiration = "1h"; + remember_me = "1M"; + }; + + regulation = { + max_retries = 3; + find_time = "2 minutes"; + ban_time = "5 minutes"; + }; + + storage.local.path = "/var/trust/authelia/db.sqlite3"; #TODO: + + # TODO: + #notifier.smtp = { + # + #}; + + # TODO: voy por acá: https://github.com/authelia/authelia/blob/master/config.template.yml#L714 + }; + }; + }; +} From 12cb13952a2b5b43c2436b175b9073db49144d5f Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Sat, 24 Aug 2024 03:51:56 -0600 Subject: [PATCH 02/24] add secrets generation --- sys/srv/authelia.nix | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/sys/srv/authelia.nix b/sys/srv/authelia.nix index 914ff47..a4e5455 100644 --- a/sys/srv/authelia.nix +++ b/sys/srv/authelia.nix @@ -4,7 +4,36 @@ ... }: with lib; { - systemd.services.authelia.serviceConfig.LoadCredential = ["storageEncryptionKeyFile.txt:/var/trust/authelia/storageEncryptionKeyFile.csv" "jwtSecretFile.txt:/var/trust/authelia/jwtSecretFile.csv"]; + #TODO: no poner authelia-main en todo lado, usar config (o let o no sé) + systemd.services.authelia-main = { + preStart = '' + mkdir -p /var/trust/authelia-main/ + chown authelia-main:authelia-main /var/trust/authelia-main/ + chmod 700 /var/trust/authelia-main/ + + [ -f /var/trust/authelia-main/jwt-secret ] || { + "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/trust/authelia-main/jwt-secret + chown authelia-main:authelia-main /var/trust/authelia-main/jwt-secret + chmod 600 /var/trust/authelia-main/jwt-secret + } + [ -f /var/trust/authelia-main/storage-encryption-file ] || { + "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/trust/authelia-main/storage-encryption-file + chown authelia-main:authelia-main /var/trust/authelia-main/storage-encryption-file + chmod 600 /var/trust/authelia-main/storage-encryption-file + } + [ -f /var/trust/authelia-main/session-secret-file ] || { + "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/trust/authelia-main/session-secret-file + chown authelia-main:authelia-main /var/trust/authelia-main/session-secret-file + chmod 600 /var/trust/authelia-main/session-secret-file + } + ''; + + serviceConfig.LoadCredential = [ + "jwt-secret:/var/trust/authelia-main/jwt-secret" + "storage-encryption-file:/var/trust/authelia-main/storage-encryption-file" + "session-secret-file:/var/trust/authelia-main/session-secret-file" + ]; + }; services = { nginx = { @@ -19,8 +48,9 @@ with lib; { # config based on https://github.com/authelia/authelia/blob/master/config.template.yml settings = { secrets = { - jwtSecretFile = "TODO:"; - storageEncryptionKeyFile = "TODO:"; + jwtSecretFile = "/var/trust/authelia-main/jwt-secret"; + storageEncryptionKeyFile = "/var/trust/authelia-main/storage-encryption-file"; + sessionSecretFile = "/var/trust/authelia-main/session-secret-file"; }; theme = "dark"; @@ -49,7 +79,7 @@ with lib; { duo_api.disable = true; # identity_validation default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L266 authentication_backend.file = { - path = "/var/trust/authelia/users_database.yml"; #TODO: + path = "/var/trust/authelia-main/users_database.yml"; #TODO: password.algorithm = "argon2"; password_policy.zxcvbn = { enable = true; @@ -92,11 +122,11 @@ with lib; { ban_time = "5 minutes"; }; - storage.local.path = "/var/trust/authelia/db.sqlite3"; #TODO: + storage.local.path = "/var/trust/authelia-main/db.sqlite3"; #TODO: # TODO: #notifier.smtp = { - # + # #}; # TODO: voy por acá: https://github.com/authelia/authelia/blob/master/config.template.yml#L714 From e8b3f321edb0dab19bcd0bd014ab043f71734aa3 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Sat, 24 Aug 2024 03:54:20 -0600 Subject: [PATCH 03/24] fix typo --- sys/srv/authelia.nix | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sys/srv/authelia.nix b/sys/srv/authelia.nix index a4e5455..90f3c3b 100644 --- a/sys/srv/authelia.nix +++ b/sys/srv/authelia.nix @@ -89,6 +89,10 @@ with lib; { access_control = { default_policy = "deny"; rules = [ + { + domain = "auth.posixlycorrect.com"; + policy = "bypass"; + } { domain = "meet.posixlycorrect.com"; policy = "bypass"; @@ -128,8 +132,6 @@ with lib; { #notifier.smtp = { # #}; - - # TODO: voy por acá: https://github.com/authelia/authelia/blob/master/config.template.yml#L714 }; }; }; From d6f40dd4fdd71570be6983e04021d919a8819cc8 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Sat, 24 Aug 2024 18:50:57 -0600 Subject: [PATCH 04/24] still wip --- sys/srv/authelia.nix | 138 ---------------- sys/srv/authelia/authelia-authrequest.conf | 32 ++++ sys/srv/authelia/authelia-location.conf | 20 +++ sys/srv/authelia/default.nix | 174 +++++++++++++++++++++ sys/srv/bepasty.nix | 4 - sys/srv/default.nix | 1 + sys/srv/forgejo.nix | 4 - sys/srv/jellyfin.nix | 4 - sys/srv/jitsi.nix | 15 +- sys/srv/kuma.nix | 4 - sys/srv/mediawiki.nix | 5 +- sys/srv/net.nix | 4 + sys/srv/vaultwarden.nix | 4 - 13 files changed, 238 insertions(+), 171 deletions(-) delete mode 100644 sys/srv/authelia.nix create mode 100644 sys/srv/authelia/authelia-authrequest.conf create mode 100644 sys/srv/authelia/authelia-location.conf create mode 100644 sys/srv/authelia/default.nix diff --git a/sys/srv/authelia.nix b/sys/srv/authelia.nix deleted file mode 100644 index 90f3c3b..0000000 --- a/sys/srv/authelia.nix +++ /dev/null @@ -1,138 +0,0 @@ -{ - lib, - pkgs, - ... -}: -with lib; { - #TODO: no poner authelia-main en todo lado, usar config (o let o no sé) - systemd.services.authelia-main = { - preStart = '' - mkdir -p /var/trust/authelia-main/ - chown authelia-main:authelia-main /var/trust/authelia-main/ - chmod 700 /var/trust/authelia-main/ - - [ -f /var/trust/authelia-main/jwt-secret ] || { - "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/trust/authelia-main/jwt-secret - chown authelia-main:authelia-main /var/trust/authelia-main/jwt-secret - chmod 600 /var/trust/authelia-main/jwt-secret - } - [ -f /var/trust/authelia-main/storage-encryption-file ] || { - "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/trust/authelia-main/storage-encryption-file - chown authelia-main:authelia-main /var/trust/authelia-main/storage-encryption-file - chmod 600 /var/trust/authelia-main/storage-encryption-file - } - [ -f /var/trust/authelia-main/session-secret-file ] || { - "${pkgs.openssl}/bin/openssl" rand -base64 32 > /var/trust/authelia-main/session-secret-file - chown authelia-main:authelia-main /var/trust/authelia-main/session-secret-file - chmod 600 /var/trust/authelia-main/session-secret-file - } - ''; - - serviceConfig.LoadCredential = [ - "jwt-secret:/var/trust/authelia-main/jwt-secret" - "storage-encryption-file:/var/trust/authelia-main/storage-encryption-file" - "session-secret-file:/var/trust/authelia-main/session-secret-file" - ]; - }; - - services = { - nginx = { - virtualHosts."auth.posixlycorrect.com" = { - enableACME = true; - forceSSL = true; - }; - }; - - authelia.instances.main = { - enable = true; - # config based on https://github.com/authelia/authelia/blob/master/config.template.yml - settings = { - secrets = { - jwtSecretFile = "/var/trust/authelia-main/jwt-secret"; - storageEncryptionKeyFile = "/var/trust/authelia-main/storage-encryption-file"; - sessionSecretFile = "/var/trust/authelia-main/session-secret-file"; - }; - - theme = "dark"; - default_2fa_method = "totp"; - server = { - disable_healthcheck = true; - port = 9091; - host = "localhost"; - address = "tcp://:9091/"; - }; - # tls settings not modified https://github.com/authelia/authelia/blob/master/config.template.yml#L53 - log = { - level = "info"; - format = "text"; - }; - telemetry.enabled = false; - totp = { - disable = false; - issuer = "https://getaegis.app/ or whatever you prefer"; - # default values assumed https://github.com/authelia/authelia/blob/master/config.template.yml#L181 - }; - webauthn = { - disable = false; - # default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L231 - }; - duo_api.disable = true; - # identity_validation default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L266 - authentication_backend.file = { - path = "/var/trust/authelia-main/users_database.yml"; #TODO: - password.algorithm = "argon2"; - password_policy.zxcvbn = { - enable = true; - min_score = 3; - }; - }; - access_control = { - default_policy = "deny"; - rules = [ - { - domain = "auth.posixlycorrect.com"; - policy = "bypass"; - } - { - domain = "meet.posixlycorrect.com"; - policy = "bypass"; - } - ]; - }; - session = { - cookies = { - name = "posixlycorrect_session"; - domain = "auth.posixlycorrect.com"; - authelia_url = "https://auth.posixlycorrect.com"; - same_site = "lax"; - - # see https://github.com/authelia/authelia/blob/master/config.template.yml#L756 - inactivity = "5 minutes"; - expiration = "1 hour"; - remember_me = "1 month"; - }; - - # see https://github.com/authelia/authelia/blob/master/config.template.yml#L774 - name = "authelia_session"; - same_site = "lax"; - inactivity = "5m"; - expiration = "1h"; - remember_me = "1M"; - }; - - regulation = { - max_retries = 3; - find_time = "2 minutes"; - ban_time = "5 minutes"; - }; - - storage.local.path = "/var/trust/authelia-main/db.sqlite3"; #TODO: - - # TODO: - #notifier.smtp = { - # - #}; - }; - }; - }; -} diff --git a/sys/srv/authelia/authelia-authrequest.conf b/sys/srv/authelia/authelia-authrequest.conf new file mode 100644 index 0000000..858815e --- /dev/null +++ b/sys/srv/authelia/authelia-authrequest.conf @@ -0,0 +1,32 @@ +## Send a subrequest to Authelia to verify if the user is authenticated and has permission to access the resource. +auth_request /internal/authelia/authz; + +## Save the upstream metadata response headers from Authelia to variables. +auth_request_set $user $upstream_http_remote_user; +auth_request_set $groups $upstream_http_remote_groups; +auth_request_set $name $upstream_http_remote_name; +auth_request_set $email $upstream_http_remote_email; + +## Inject the metadata response headers from the variables into the request made to the backend. +proxy_set_header Remote-User $user; +proxy_set_header Remote-Groups $groups; +proxy_set_header Remote-Email $email; +proxy_set_header Remote-Name $name; + +## Configure the redirection when the authz failure occurs. Lines starting with 'Modern Method' and 'Legacy Method' +## should be commented / uncommented as pairs. The modern method uses the session cookies configuration's authelia_url +## value to determine the redirection URL here. It's much simpler and compatible with the mutli-cookie domain easily. + +## Modern Method: Set the $redirection_url to the Location header of the response to the Authz endpoint. +auth_request_set $redirection_url $upstream_http_location; + +## Modern Method: When there is a 401 response code from the authz endpoint redirect to the $redirection_url. +error_page 401 =302 $redirection_url; + +## Legacy Method: Set $target_url to the original requested URL. +## This requires http_set_misc module, replace 'set_escape_uri' with 'set' if you don't have this module. +# set_escape_uri $target_url $scheme://$http_host$request_uri; + +## Legacy Method: When there is a 401 response code from the authz endpoint redirect to the portal with the 'rd' +## URL parameter set to $target_url. This requires users update 'auth.posixlycorrect.com/' with their external authelia URL. +# error_page 401 =302 https://auth.posixlycorrect.com/?rd=$target_url; \ No newline at end of file diff --git a/sys/srv/authelia/authelia-location.conf b/sys/srv/authelia/authelia-location.conf new file mode 100644 index 0000000..e8052c4 --- /dev/null +++ b/sys/srv/authelia/authelia-location.conf @@ -0,0 +1,20 @@ +## Virtual endpoint created by nginx to forward auth requests. +location /internal/authelia/authz { + ## Essential Proxy Configuration + internal; + proxy_pass http://localhost:9091/api/authz/auth-request; + + ## Headers + ## The headers starting with X-* are required. + proxy_set_header X-Original-Method $request_method; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Content-Length ""; + proxy_set_header Connection ""; + + ## Basic Proxy Configuration + proxy_pass_request_body off; + + ## Advanced Proxy Configuration TODO: maybe reducir estos timeouts? + send_timeout 5m; +} \ No newline at end of file diff --git a/sys/srv/authelia/default.nix b/sys/srv/authelia/default.nix new file mode 100644 index 0000000..1eb2f37 --- /dev/null +++ b/sys/srv/authelia/default.nix @@ -0,0 +1,174 @@ +{ + lib, + pkgs, + ... +}: +with lib; { + options = { + services.nginx.virtualHosts = mkOption { + type = with lib.types; + attrsOf ( + submodule + ( + {config, ...}: { + options = { + enableAuthelia = mkOption { + default = false; + type = bool; + }; + }; + config = mkIf config.enableAuthelia { + extraConfig = '' + include ${./authelia-authrequest.conf}; + include ${./authelia-location.conf}; + ''; + }; + } + ) + ); + }; + }; + + config = { + systemd.services.authelia-main.before = [ "nginx.service" ]; + + services = { + nginx = { + recommendedProxySettings = true; + recommendedTlsSettings = true; + commonHttpConfig = '' + ## Headers + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + proxy_set_header X-Forwarded-URI $request_uri; + proxy_set_header X-Forwarded-Ssl on; + + ## Basic Proxy Configuration + client_body_buffer_size 128k; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; ## Timeout if the real server is dead. + # proxy_redirect http:// $scheme://; + proxy_cache_bypass $cookie_session; + proxy_no_cache $cookie_session; + proxy_buffers 64 256k; + + ## Trusted Proxies Configuration + ## Please read the following documentation before configuring this: + ## https://www.authelia.com/integration/proxies/nginx/#trusted-proxies + # set_real_ip_from 10.0.0.0/8; + # set_real_ip_from 172.16.0.0/12; + # set_real_ip_from 192.168.0.0/16; + # set_real_ip_from fc00::/7; + real_ip_header X-Forwarded-For; + real_ip_recursive on; + ''; + virtualHosts."auth.posixlycorrect.com" = { + enableACME = true; + forceSSL = true; + locations = { + "/" = { + proxyPass = "http://localhost:9091"; #TODO: hacer que eso esté en alguna config o en algún let + }; + "= /api/verify" = { + proxyPass = "http://localhost:9091"; + }; + "= /api/authz/" = { + proxyPass = "http://localhost:9091"; + }; + }; + }; + }; + + authelia.instances.main = { + enable = true; + # config based on https://github.com/authelia/authelia/blob/master/config.template.yml + secrets = { + jwtSecretFile = "/var/trust/authelia-main/jwt-secret"; + storageEncryptionKeyFile = "/var/trust/authelia-main/storage-encryption-file"; + sessionSecretFile = "/var/trust/authelia-main/session-secret-file"; + }; + settings = { + theme = "dark"; + default_2fa_method = "totp"; + server = { + disable_healthcheck = true; + port = 9091; + host = "localhost"; + address = "tcp://localhost:9091/"; #TODO: user unix socket + endpoints.authz.auth-request.implementation = "AuthRequest"; + }; + # tls settings not modified https://github.com/authelia/authelia/blob/master/config.template.yml#L53 + log = { + level = "info"; + format = "text"; + }; + telemetry.enabled = false; + totp = { + disable = false; + issuer = "https://getaegis.app/ or whatever you prefer"; + # default values assumed https://github.com/authelia/authelia/blob/master/config.template.yml#L181 + }; + webauthn = { + disable = false; + # default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L231 + }; + duo_api.disable = true; + # identity_validation default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L266 + authentication_backend.file = { + path = "/var/trust/authelia-main/users_database.yml"; #TODO: + password.algorithm = "argon2"; + password_policy.zxcvbn = { + enable = true; + min_score = 3; + }; + }; + access_control = { + default_policy = "deny"; + rules = [ + { + domain = "auth.posixlycorrect.com"; + policy = "bypass"; + } + { + domain = "meet.posixlycorrect.com"; + policy = "bypass"; + } + ]; + }; + session = { + cookies = { + name = "posixlycorrect_session"; + domain = "auth.posixlycorrect.com"; + authelia_url = "https://auth.posixlycorrect.com"; + default_redirection_url = "https://posixlycorrect.com"; + same_site = "lax"; + + # see https://github.com/authelia/authelia/blob/master/config.template.yml#L756 + inactivity = "5 minutes"; + expiration = "1 hour"; + remember_me = "1 month"; + }; + + # see https://github.com/authelia/authelia/blob/master/config.template.yml#L774 + name = "authelia_session"; + same_site = "lax"; + inactivity = "5m"; + expiration = "1h"; + remember_me = "1M"; + }; + + regulation = { + max_retries = 3; + find_time = "2 minutes"; + ban_time = "5 minutes"; + }; + + storage.local.path = "/var/trust/authelia-main/db.sqlite3"; #TODO: + + # TODO: + #notifier.smtp = { + # + #}; + }; + }; + }; + }; +} diff --git a/sys/srv/bepasty.nix b/sys/srv/bepasty.nix index 964dbec..cfcc88b 100644 --- a/sys/srv/bepasty.nix +++ b/sys/srv/bepasty.nix @@ -9,10 +9,6 @@ with lib; { virtualHosts."send.posixlycorrect.com" = { enableACME = true; forceSSL = true; - extraConfig = '' - proxy_headers_hash_max_size 512; - proxy_headers_hash_bucket_size 128; - ''; locations."/" = { proxyPass = "http://127.0.0.1:8989"; }; diff --git a/sys/srv/default.nix b/sys/srv/default.nix index 61ccd14..de92f8d 100644 --- a/sys/srv/default.nix +++ b/sys/srv/default.nix @@ -17,5 +17,6 @@ with lib; { ./jellyfin.nix ./msmtp.nix ./kuma.nix + ./authelia ]; } diff --git a/sys/srv/forgejo.nix b/sys/srv/forgejo.nix index 4651285..2464514 100644 --- a/sys/srv/forgejo.nix +++ b/sys/srv/forgejo.nix @@ -16,10 +16,6 @@ with lib; { virtualHosts."git.posixlycorrect.com" = { enableACME = true; forceSSL = true; - extraConfig = '' - proxy_headers_hash_max_size 512; - proxy_headers_hash_bucket_size 128; - ''; locations."/".proxyPass = "http://localhost:9170"; }; }; diff --git a/sys/srv/jellyfin.nix b/sys/srv/jellyfin.nix index 07c8896..3a607b3 100644 --- a/sys/srv/jellyfin.nix +++ b/sys/srv/jellyfin.nix @@ -9,10 +9,6 @@ with lib; { virtualHosts."stream.posixlycorrect.com" = { enableACME = true; forceSSL = true; - extraConfig = '' - proxy_headers_hash_max_size 512; - proxy_headers_hash_bucket_size 128; - ''; locations."/" = { proxyPass = "http://localhost:8096"; }; diff --git a/sys/srv/jitsi.nix b/sys/srv/jitsi.nix index 42c62e6..c4a011d 100644 --- a/sys/srv/jitsi.nix +++ b/sys/srv/jitsi.nix @@ -10,15 +10,12 @@ with lib; { enableACME = true; forceSSL = true; extraConfig = '' - proxy_headers_hash_max_size 512; - proxy_headers_hash_bucket_size 128; - - ssl_verify_depth 1; - ssl_verify_client on; - ssl_client_certificate ${../../pki/gatekeeper_ca.pem}; - if ($ssl_client_verify != "SUCCESS") { - return 403; - } + ssl_verify_depth 1; + ssl_verify_client on; + ssl_client_certificate ${../../pki/gatekeeper_ca.pem}; + if ($ssl_client_verify != "SUCCESS") { + return 403; + } ''; }; }; diff --git a/sys/srv/kuma.nix b/sys/srv/kuma.nix index e698c04..60594c8 100644 --- a/sys/srv/kuma.nix +++ b/sys/srv/kuma.nix @@ -9,10 +9,6 @@ with lib; { virtualHosts."status.posixlycorrect.com" = { enableACME = true; forceSSL = true; - extraConfig = '' - proxy_headers_hash_max_size 512; - proxy_headers_hash_bucket_size 128; - ''; locations."/" = { proxyPass = "http://127.0.0.1:4456"; }; diff --git a/sys/srv/mediawiki.nix b/sys/srv/mediawiki.nix index d07bd80..d976d40 100644 --- a/sys/srv/mediawiki.nix +++ b/sys/srv/mediawiki.nix @@ -10,10 +10,7 @@ with lib; { virtualHosts."wiki.posixlycorrect.com" = { enableACME = true; forceSSL = true; - extraConfig = '' - proxy_headers_hash_max_size 512; - proxy_headers_hash_bucket_size 128; - ''; + enableAuthelia = true; }; }; mediawiki = { diff --git a/sys/srv/net.nix b/sys/srv/net.nix index 9d22700..f49edaf 100644 --- a/sys/srv/net.nix +++ b/sys/srv/net.nix @@ -26,6 +26,10 @@ with lib; { recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; + commonHttpConfig = '' + proxy_headers_hash_max_size 512; + proxy_headers_hash_bucket_size 128; + ''; logError = "/var/log/nginx/error.log"; clientMaxBodySize = "99M"; virtualHosts = { diff --git a/sys/srv/vaultwarden.nix b/sys/srv/vaultwarden.nix index 2b8dc91..0d81ee7 100644 --- a/sys/srv/vaultwarden.nix +++ b/sys/srv/vaultwarden.nix @@ -9,10 +9,6 @@ with lib; { virtualHosts."vault.posixlycorrect.com" = { enableACME = true; forceSSL = true; - extraConfig = '' - proxy_headers_hash_max_size 512; - proxy_headers_hash_bucket_size 128; - ''; locations."/".proxyPass = "http://127.0.0.1:${toString config.services.vaultwarden.config.ROCKET_PORT}"; }; }; From 7d3100c3d339743dd71a74259e9e4d2c867dd18c Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Sun, 25 Aug 2024 02:09:29 -0600 Subject: [PATCH 05/24] works? --- sys/srv/authelia/default.nix | 57 ++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/sys/srv/authelia/default.nix b/sys/srv/authelia/default.nix index 1eb2f37..f30386e 100644 --- a/sys/srv/authelia/default.nix +++ b/sys/srv/authelia/default.nix @@ -30,7 +30,7 @@ with lib; { }; config = { - systemd.services.authelia-main.before = [ "nginx.service" ]; + systemd.services.authelia-main.before = ["nginx.service"]; services = { nginx = { @@ -79,6 +79,7 @@ with lib; { authelia.instances.main = { enable = true; + package = pkgs.unstable.authelia; # config based on https://github.com/authelia/authelia/blob/master/config.template.yml secrets = { jwtSecretFile = "/var/trust/authelia-main/jwt-secret"; @@ -92,7 +93,6 @@ with lib; { disable_healthcheck = true; port = 9091; host = "localhost"; - address = "tcp://localhost:9091/"; #TODO: user unix socket endpoints.authz.auth-request.implementation = "AuthRequest"; }; # tls settings not modified https://github.com/authelia/authelia/blob/master/config.template.yml#L53 @@ -100,25 +100,22 @@ with lib; { level = "info"; format = "text"; }; - telemetry.enabled = false; + telemetry.metrics.enabled = false; totp = { disable = false; issuer = "https://getaegis.app/ or whatever you prefer"; - # default values assumed https://github.com/authelia/authelia/blob/master/config.template.yml#L181 }; webauthn = { disable = false; - # default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L231 }; duo_api.disable = true; - # identity_validation default values assumed: https://github.com/authelia/authelia/blob/master/config.template.yml#L266 authentication_backend.file = { - path = "/var/trust/authelia-main/users_database.yml"; #TODO: + path = "/var/lib/authelia-main/users_database.yml"; password.algorithm = "argon2"; - password_policy.zxcvbn = { - enable = true; - min_score = 3; - }; + }; + password_policy.zxcvbn = { + enabled = true; + min_score = 3; }; access_control = { default_policy = "deny"; @@ -134,25 +131,23 @@ with lib; { ]; }; session = { - cookies = { - name = "posixlycorrect_session"; - domain = "auth.posixlycorrect.com"; - authelia_url = "https://auth.posixlycorrect.com"; - default_redirection_url = "https://posixlycorrect.com"; - same_site = "lax"; - - # see https://github.com/authelia/authelia/blob/master/config.template.yml#L756 - inactivity = "5 minutes"; - expiration = "1 hour"; - remember_me = "1 month"; - }; - - # see https://github.com/authelia/authelia/blob/master/config.template.yml#L774 - name = "authelia_session"; + name = "posixlycorrect_session"; same_site = "lax"; inactivity = "5m"; expiration = "1h"; remember_me = "1M"; + cookies = [ + { + name = "posixlycorrect_session"; + domain = "posixlycorrect.com"; + authelia_url = "https://auth.posixlycorrect.com"; + default_redirection_url = "https://posixlycorrect.com"; + same_site = "lax"; + inactivity = "5 minutes"; + expiration = "1 hour"; + remember_me = "1 month"; + } + ]; }; regulation = { @@ -161,12 +156,12 @@ with lib; { ban_time = "5 minutes"; }; - storage.local.path = "/var/trust/authelia-main/db.sqlite3"; #TODO: + storage.local.path = "/var/lib/authelia-main/db.sqlite3"; - # TODO: - #notifier.smtp = { - # - #}; + # TODO: usar smtp + notifier.filesystem = { + filename = "/tmp/trash.txt"; + }; }; }; }; From 222ce4c296be816f0b697488616b9e0fdc921072 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Tue, 27 Aug 2024 18:35:58 -0600 Subject: [PATCH 06/24] add mediawiki extensions --- sys/srv/mediawiki.nix | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/sys/srv/mediawiki.nix b/sys/srv/mediawiki.nix index d07bd80..e898357 100644 --- a/sys/srv/mediawiki.nix +++ b/sys/srv/mediawiki.nix @@ -53,6 +53,17 @@ with lib; { extensions = { # some extensions are included and can enabled by passing null VisualEditor = null; + CategoryTree = null; + CiteThisPage = null; + Scribunto = null; + Cite = null; + CodeEditor = null; + Math = null; + MultimediaViewer = null; + PdfHandler = null; + Poem = null; + SecureLinkFixer = null; + WikiEditor = null; }; }; }; From 8ee952b958835b66aca0bfdd7e717ea496485a96 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Tue, 27 Aug 2024 19:12:09 -0600 Subject: [PATCH 07/24] add authentik --- flake.lock | 290 ++++++++++++++++++++++++++++++++++++++---- flake.nix | 6 + pki/gatekeeper_ca.pem | 21 --- sys/srv/authentik.nix | 110 ++++++++++++++++ sys/srv/default.nix | 1 + sys/srv/jitsi.nix | 8 +- 6 files changed, 380 insertions(+), 56 deletions(-) delete mode 100644 pki/gatekeeper_ca.pem create mode 100644 sys/srv/authentik.nix diff --git a/flake.lock b/flake.lock index 2c903d7..3fd9fa3 100644 --- a/flake.lock +++ b/flake.lock @@ -3,8 +3,8 @@ "attic": { "inputs": { "crane": "crane", - "flake-compat": "flake-compat", - "flake-utils": "flake-utils", + "flake-compat": "flake-compat_2", + "flake-utils": "flake-utils_2", "nixpkgs": "nixpkgs", "nixpkgs-stable": "nixpkgs-stable" }, @@ -23,10 +23,53 @@ "type": "github" } }, + "authentik-nix": { + "inputs": { + "authentik-src": "authentik-src", + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "flake-utils": "flake-utils", + "napalm": "napalm", + "nixpkgs": [ + "nixpkgs" + ], + "poetry2nix": "poetry2nix" + }, + "locked": { + "lastModified": 1724362025, + "narHash": "sha256-/fzIU/Hjgksy7A4ji09zK6cH7ATQV5rAEYb/wgBw8x8=", + "owner": "nix-community", + "repo": "authentik-nix", + "rev": "39cf62b92149800dd2a436f8b18acd471c9180dd", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "authentik-nix", + "type": "github" + } + }, + "authentik-src": { + "flake": false, + "locked": { + "lastModified": 1724339964, + "narHash": "sha256-QwK/auMLCJEHHtyexFnO+adCq/u0fezHQ90fXW9J4c4=", + "owner": "goauthentik", + "repo": "authentik", + "rev": "8a0b31b9227ca33b96c5448f185419f17090ed38", + "type": "github" + }, + "original": { + "owner": "goauthentik", + "ref": "version/2024.6.4", + "repo": "authentik", + "type": "github" + } + }, "cachix": { "inputs": { "devenv": "devenv", - "flake-compat": "flake-compat_3", + "flake-compat": "flake-compat_4", "nixpkgs": "nixpkgs_3", "pre-commit-hooks": "pre-commit-hooks" }, @@ -105,8 +148,8 @@ "complement": "complement", "crane": "crane_2", "fenix": "fenix", - "flake-compat": "flake-compat_5", - "flake-utils": "flake-utils_3", + "flake-compat": "flake-compat_6", + "flake-utils": "flake-utils_4", "liburing": "liburing", "nix-filter": "nix-filter", "nixpkgs": [ @@ -218,7 +261,7 @@ ], "nix": "nix", "nixpkgs": "nixpkgs_2", - "poetry2nix": "poetry2nix", + "poetry2nix": "poetry2nix_2", "pre-commit-hooks": [ "conduwuit", "cachix", @@ -268,11 +311,11 @@ "flake-compat": { "flake": false, "locked": { - "lastModified": 1673956053, - "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", "owner": "edolstra", "repo": "flake-compat", - "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", "type": "github" }, "original": { @@ -300,11 +343,11 @@ "flake-compat_3": { "flake": false, "locked": { - "lastModified": 1696426674, - "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "lastModified": 1673956053, + "narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=", "owner": "edolstra", "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9", "type": "github" }, "original": { @@ -330,6 +373,22 @@ } }, "flake-compat_5": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_6": { "flake": false, "locked": { "lastModified": 1696426674, @@ -346,7 +405,43 @@ "type": "github" } }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1722555600, + "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "8471fe90ad337a8074e957b69ca4d0089218391d", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1710146030, + "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { "locked": { "lastModified": 1667395993, "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", @@ -361,9 +456,9 @@ "type": "github" } }, - "flake-utils_2": { + "flake-utils_3": { "inputs": { - "systems": "systems" + "systems": "systems_3" }, "locked": { "lastModified": 1689068808, @@ -379,9 +474,9 @@ "type": "github" } }, - "flake-utils_3": { + "flake-utils_4": { "inputs": { - "systems": "systems_2" + "systems": "systems_4" }, "locked": { "lastModified": 1710146030, @@ -398,9 +493,9 @@ "type": "github" } }, - "flake-utils_4": { + "flake-utils_5": { "inputs": { - "systems": "systems_3" + "systems": "systems_5" }, "locked": { "lastModified": 1710146030, @@ -416,9 +511,9 @@ "type": "github" } }, - "flake-utils_5": { + "flake-utils_6": { "inputs": { - "systems": "systems_4" + "systems": "systems_6" }, "locked": { "lastModified": 1710146030, @@ -480,7 +575,7 @@ }, "homepage": { "inputs": { - "flake-utils": "flake-utils_5", + "flake-utils": "flake-utils_6", "nixpkgs": "nixpkgs_4" }, "locked": { @@ -547,9 +642,34 @@ "type": "github" } }, + "napalm": { + "inputs": { + "flake-utils": [ + "authentik-nix", + "flake-utils" + ], + "nixpkgs": [ + "authentik-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1717929455, + "narHash": "sha256-BiI5xWygriOJuNISnGAeL0KYxrEMnjgpg+7wDskVBhI=", + "owner": "nix-community", + "repo": "napalm", + "rev": "e1babff744cd278b56abe8478008b4a9e23036cf", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "napalm", + "type": "github" + } + }, "nix": { "inputs": { - "flake-compat": "flake-compat_2", + "flake-compat": "flake-compat_3", "nixpkgs": [ "conduwuit", "cachix", @@ -592,6 +712,28 @@ } }, "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "authentik-nix", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1703863825, + "narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "5163432afc817cf8bd1f031418d1869e4c9d5547", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, + "nix-github-actions_2": { "inputs": { "nixpkgs": [ "conduwuit", @@ -664,6 +806,18 @@ "type": "github" } }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1722555339, + "narHash": "sha256-uFf2QeW7eAHlYXuDktm9c25OxOyCoUOQmh5SZ9amE5Q=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" + } + }, "nixpkgs-regression": { "locked": { "lastModified": 1643052045, @@ -791,8 +945,36 @@ }, "poetry2nix": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": [ + "authentik-nix", + "flake-utils" + ], "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "authentik-nix", + "nixpkgs" + ], + "systems": "systems_2", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1724208502, + "narHash": "sha256-TCRcEPSfgAw/t7kClmlr23s591N06mQCrhzlAO7cyFw=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "884b66152b0c625b8220b570a31dc7acc36749a3", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, + "poetry2nix_2": { + "inputs": { + "flake-utils": "flake-utils_3", + "nix-github-actions": "nix-github-actions_2", "nixpkgs": [ "conduwuit", "cachix", @@ -818,7 +1000,7 @@ }, "pre-commit-hooks": { "inputs": { - "flake-compat": "flake-compat_4", + "flake-compat": "flake-compat_5", "gitignore": "gitignore", "nixpkgs": [ "conduwuit", @@ -860,8 +1042,9 @@ }, "root": { "inputs": { + "authentik-nix": "authentik-nix", "conduwuit": "conduwuit", - "flake-utils": "flake-utils_4", + "flake-utils": "flake-utils_5", "home-manager": "home-manager", "homepage": "homepage", "impermanence": "impermanence", @@ -913,9 +1096,8 @@ "type": "github" }, "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" + "id": "systems", + "type": "indirect" } }, "systems_3": { @@ -948,6 +1130,58 @@ "type": "github" } }, + "systems_5": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_6": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "authentik-nix", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1719749022, + "narHash": "sha256-ddPKHcqaKCIFSFc/cvxS14goUhCOAwsM1PbMr0ZtHMg=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "8df5ff62195d4e67e2264df0b7f5e8c9995fd0bd", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, "unstable": { "locked": { "lastModified": 1722185531, diff --git a/flake.nix b/flake.nix index 4560147..13dac98 100644 --- a/flake.nix +++ b/flake.nix @@ -26,6 +26,11 @@ url = "github:StarCitizenTools/mediawiki-skins-Citizen/v2.27.0"; flake = false; }; + + authentik-nix = { + url = "github:nix-community/authentik-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = flakes @ { @@ -39,6 +44,7 @@ homepage, conduwuit, mediawikiSkinCitizen, + authentik-nix, }: let system = "x86_64-linux"; diff --git a/pki/gatekeeper_ca.pem b/pki/gatekeeper_ca.pem deleted file mode 100644 index 51c2de9..0000000 --- a/pki/gatekeeper_ca.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDijCCAnKgAwIBAgIUQCBAoFSQrYx063PnK3XKiOJSpvQwDQYJKoZIhvcNAQEL -BQAwKzEpMCcGA1UEAwwgcG9zaXhseWNvcnJlY3QuY29tIGdhdGVrZWVwZXIgQ0Ew -HhcNMjQwODAyMDcxNzE4WhcNMzQwNzMxMDcxNzE4WjArMSkwJwYDVQQDDCBwb3Np -eGx5Y29ycmVjdC5jb20gZ2F0ZWtlZXBlciBDQTCCASIwDQYJKoZIhvcNAQEBBQAD -ggEPADCCAQoCggEBAKxjqIpRxIu2yPejUbyMixZACESrbmIGOhhxwUu1ys6aYPOZ -7yQMs5xuJXcgCuD7Oba1eBi+CpLhyvgZlyLrCfxoCzTdAeeXq0EB7YUn8IYEN3dR -e+yds//zkjRzbXAaIbUoAF8XaXgylOSIXLNrh0TTjNscC+TPYvKSbaDhdICOZ1ky -u08w5QdOoi1W8FNJd4LKIKWQZW3dMeNaBbKnt9R4mjL28tE5gP6ZYUvcCIoqYAbE -DSNq29lXsmDzbD914bN5wYoTP3A+k8QG6eYGb10YgaaJ0TBxeLzadVBq7gFylMt3 -1LTNmH/v+l73IYfiDV4O3d33cg0VOKqiD48WCnkCAwEAAaOBpTCBojAMBgNVHRME -BTADAQH/MB0GA1UdDgQWBBStVj4YoMTnD+XZ+doBI7Ao17Gg3DBmBgNVHSMEXzBd -gBStVj4YoMTnD+XZ+doBI7Ao17Gg3KEvpC0wKzEpMCcGA1UEAwwgcG9zaXhseWNv -cnJlY3QuY29tIGdhdGVrZWVwZXIgQ0GCFEAgQKBUkK2MdOtz5yt1yojiUqb0MAsG -A1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAZgbpPdkhAbrbA7Y63WI2Bo26 -tPVCZpsEKiwpyEbDDC+NVrbOit1kQg/j26RuXLDVg19IfXk407FVFVGYVJNE+kXt -KjyKCGyyZUBQRebCN8kzFsCQ/AJSfzNKQhEK68rchSH66mbjtOtItkdVZRnq0pWI -7WXlTIxK8KTcAx2V/ijyalCENUpwRWfM4Qnkqsi82Dx9e8V0TRCLomW7IQok4dre -F6IolUHw9ZuSC10/T8n8+riqWBWEisBGLz79OrdETdHK9A5gpNHRF+sO9JAhVr/t -exBWTEJ33BeI0NX87d0Pneun4nss5FsLst+Ut7Y0F2QF2Iar1iERUalHVIjCtA== ------END CERTIFICATE----- diff --git a/sys/srv/authentik.nix b/sys/srv/authentik.nix new file mode 100644 index 0000000..8b68fe3 --- /dev/null +++ b/sys/srv/authentik.nix @@ -0,0 +1,110 @@ +{ + lib, + pkgs, + flakes, + ... +}: +with lib; { + imports = [flakes.authentik-nix.nixosModules.default]; + + options = { + services.nginx.virtualHosts = mkOption { + type = with lib.types; + attrsOf ( + submodule + ( + {config, ...}: { + options = { + enableAuthentik = mkOption { + default = false; + type = bool; + }; + locations = mkOption { + type = attrsOf ( + submodule { + config = mkIf config.enableAuthentik { + extraConfig = '' + auth_request /outpost.goauthentik.io/auth/nginx; + error_page 401 = @goauthentik_proxy_signin; + auth_request_set $auth_cookie $upstream_http_set_cookie; + add_header Set-Cookie $auth_cookie; + + # translate headers from the outposts back to the actual upstream + auth_request_set $authentik_username $upstream_http_x_authentik_username; + auth_request_set $authentik_groups $upstream_http_x_authentik_groups; + auth_request_set $authentik_email $upstream_http_x_authentik_email; + auth_request_set $authentik_name $upstream_http_x_authentik_name; + auth_request_set $authentik_uid $upstream_http_x_authentik_uid; + + proxy_set_header X-authentik-username $authentik_username; + proxy_set_header X-authentik-groups $authentik_groups; + proxy_set_header X-authentik-email $authentik_email; + proxy_set_header X-authentik-name $authentik_name; + proxy_set_header X-authentik-uid $authentik_uid; + ''; + }; + } + ); + }; + }; + config = mkIf config.enableAuthentik { + extraConfig = '' + proxy_buffers 8 16k; + proxy_buffer_size 32k; + + location /outpost.goauthentik.io { + proxy_pass http://localhost:9000/outpost.goauthentik.io; + # ensure the host of this vserver matches your external URL you've configured + # in authentik + proxy_set_header Host $host; + proxy_redirect http://localhost:9000 https://auth.posixlycorrect.com; + proxy_set_header X-Original-URL $scheme://$http_host$request_uri; + add_header Set-Cookie $auth_cookie; + auth_request_set $auth_cookie $upstream_http_set_cookie; + + # required for POST requests to work + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + } + + location @goauthentik_proxy_signin { + internal; + add_header Set-Cookie $auth_cookie; + return 302 /outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri; + # For domain level, use the below error_page to redirect to your authentik server with the full redirect path + # return 302 https://authentik.company/outpost.goauthentik.io/start?rd=$scheme://$http_host$request_uri; + } + ''; + }; + } + ) + ); + }; + }; + + config = { + services = { + authentik = { + enable = true; + environmentFile = "/var/trust/authentik/authentik-env"; + nginx = { + enable = true; + enableACME = true; + host = "auth.posixlycorrect.com"; + }; + settings = { + email = { + host = "smtp.fastmail.com"; + port = 587; + username = "fabianmontero@fastmail.com"; + use_tls = true; + use_ssl = false; + from = "auth@posixlycorrect.com"; + }; + disable_startup_analytics = true; + avatars = "initials"; + }; + }; + }; + }; +} diff --git a/sys/srv/default.nix b/sys/srv/default.nix index 61ccd14..4b02f44 100644 --- a/sys/srv/default.nix +++ b/sys/srv/default.nix @@ -17,5 +17,6 @@ with lib; { ./jellyfin.nix ./msmtp.nix ./kuma.nix + ./authentik.nix ]; } diff --git a/sys/srv/jitsi.nix b/sys/srv/jitsi.nix index 42c62e6..86a6358 100644 --- a/sys/srv/jitsi.nix +++ b/sys/srv/jitsi.nix @@ -9,16 +9,10 @@ with lib; { virtualHosts."meet.posixlycorrect.com" = { enableACME = true; forceSSL = true; + enableAuthentik = false; extraConfig = '' proxy_headers_hash_max_size 512; proxy_headers_hash_bucket_size 128; - - ssl_verify_depth 1; - ssl_verify_client on; - ssl_client_certificate ${../../pki/gatekeeper_ca.pem}; - if ($ssl_client_verify != "SUCCESS") { - return 403; - } ''; }; }; From f8324e96e65590bd1ae95d86673a9965619ac4d5 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 28 Aug 2024 11:32:21 -0600 Subject: [PATCH 08/24] add TemplateStyles extension to mediawiki --- sys/srv/mediawiki.nix | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sys/srv/mediawiki.nix b/sys/srv/mediawiki.nix index e898357..d806a18 100644 --- a/sys/srv/mediawiki.nix +++ b/sys/srv/mediawiki.nix @@ -64,6 +64,13 @@ with lib; { Poem = null; SecureLinkFixer = null; WikiEditor = null; + ParserFunctions = null; + + TemplateStyles = pkgs.fetchzip { + url = "https://gerrit.wikimedia.org/r/plugins/gitiles/mediawiki/extensions/TemplateStyles/+archive/refs/heads/wmf/1.42.0-wmf.9.tar.gz"; + sha256 = "sha256-+EOwkDU8L0qQ4Wo3WDqNug4Pyz/PUhOiHKmNcFJO4G0="; + stripRoot = false; + }; }; }; }; From 0cafd83313ab8d7dea98bc936e55cb3dc1f3286d Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 28 Aug 2024 12:24:17 -0600 Subject: [PATCH 09/24] add paperless --- sys/srv/default.nix | 1 + sys/srv/paperless.nix | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 sys/srv/paperless.nix diff --git a/sys/srv/default.nix b/sys/srv/default.nix index 4b02f44..ab547c1 100644 --- a/sys/srv/default.nix +++ b/sys/srv/default.nix @@ -18,5 +18,6 @@ with lib; { ./msmtp.nix ./kuma.nix ./authentik.nix + ./paperless.nix ]; } diff --git a/sys/srv/paperless.nix b/sys/srv/paperless.nix new file mode 100644 index 0000000..8a2a137 --- /dev/null +++ b/sys/srv/paperless.nix @@ -0,0 +1,36 @@ +{ + lib, + pkgs, + ... +}: +with lib; { + services = { + nginx = { + virtualHosts."docs.posixlycorrect.com" = { + enableACME = true; + forceSSL = true; + extraConfig = '' + proxy_headers_hash_max_size 512; + proxy_headers_hash_bucket_size 128; + ''; + locations."/" = { + proxyPass = "http://127.0.0.1:28981"; + }; + }; + }; + + paperless = { + enable = true; + user = "paperless"; + passwordFile = "/var/trust/paperless/passwordFile"; + openMPThreadingWorkaround = true; # see https://github.com/NixOS/nixpkgs/issues/240591 + address = "127.0.0.1"; + port = 28981; + settings = { + PAPERLESS_URL = "docs.posixlycorrect.com"; + PAPERLESS_OCR_LANGUAGE = "eng+spa"; + PAPERLESS_APP_TITLE = "posixlycorrect"; + }; + }; + }; +} From f14f11be005d79e626c7b37ddc9293f5daf1939c Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 28 Aug 2024 12:27:58 -0600 Subject: [PATCH 10/24] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'homepage': 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=18b56328eda94579fb4727ba886888f6596f7d0a' (2024-08-23) → 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=4fd192a71d19b79684ae544f4f8470aa777b968d' (2024-08-28) --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 3fd9fa3..01e9394 100644 --- a/flake.lock +++ b/flake.lock @@ -579,11 +579,11 @@ "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1724455559, - "narHash": "sha256-suDqHUBghYgS79MqOOBtxu28MVbiQpbB01JGnvvhN0E=", + "lastModified": 1724869651, + "narHash": "sha256-9DCEtAImTlEAyrCqIMm9S3nMfNzW1MOLJkGqpge6at8=", "ref": "master", - "rev": "18b56328eda94579fb4727ba886888f6596f7d0a", - "revCount": 15, + "rev": "4fd192a71d19b79684ae544f4f8470aa777b968d", + "revCount": 18, "type": "git", "url": "https://git.posixlycorrect.com/fabian/homepage.git" }, From c8057ed52cffabade2e5433659248b100fadbac3 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 28 Aug 2024 13:47:35 -0600 Subject: [PATCH 11/24] deactivate authentik --- sys/srv/default.nix | 2 +- sys/srv/jitsi.nix | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sys/srv/default.nix b/sys/srv/default.nix index ab547c1..c41577a 100644 --- a/sys/srv/default.nix +++ b/sys/srv/default.nix @@ -17,7 +17,7 @@ with lib; { ./jellyfin.nix ./msmtp.nix ./kuma.nix - ./authentik.nix + # ./authentik.nix consumes too much RAM and serves no purpose for now ./paperless.nix ]; } diff --git a/sys/srv/jitsi.nix b/sys/srv/jitsi.nix index 86a6358..8fa1ccb 100644 --- a/sys/srv/jitsi.nix +++ b/sys/srv/jitsi.nix @@ -9,7 +9,6 @@ with lib; { virtualHosts."meet.posixlycorrect.com" = { enableACME = true; forceSSL = true; - enableAuthentik = false; extraConfig = '' proxy_headers_hash_max_size 512; proxy_headers_hash_bucket_size 128; From 34b1a8e289f3bce92b535e3e2787bf5d62c29de9 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 4 Sep 2024 00:22:55 -0600 Subject: [PATCH 12/24] make forgejo default theme dark --- sys/srv/forgejo.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/sys/srv/forgejo.nix b/sys/srv/forgejo.nix index 4651285..25ff959 100644 --- a/sys/srv/forgejo.nix +++ b/sys/srv/forgejo.nix @@ -39,6 +39,7 @@ with lib; { useWizard = false; settings = { general.APP_NAME = "posixlycorrect"; + ui.DEFAULT_THEME = "forgejo-dark"; server = { DOMAIN = "git.posixlycorrect.com"; ROOT_URL = "https://git.posixlycorrect.com"; From 5bd11b2bd4957fb3e1256e5c941490e52e9de613 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 4 Sep 2024 01:47:49 -0600 Subject: [PATCH 13/24] disable matrix --- sys/srv/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/srv/default.nix b/sys/srv/default.nix index c41577a..38cddaa 100644 --- a/sys/srv/default.nix +++ b/sys/srv/default.nix @@ -10,7 +10,7 @@ with lib; { ./net.nix ./mediawiki.nix ./jitsi.nix - ./matrix.nix + # ./matrix.nix currently not being used ./forgejo.nix ./vaultwarden.nix ./bepasty.nix From ced4592c1a103cba6512c9b4c05c00ca37ae1c1a Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 4 Sep 2024 02:18:22 -0600 Subject: [PATCH 14/24] add trilium --- sys/srv/default.nix | 1 + sys/srv/trilium.nix | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 sys/srv/trilium.nix diff --git a/sys/srv/default.nix b/sys/srv/default.nix index 38cddaa..911ad81 100644 --- a/sys/srv/default.nix +++ b/sys/srv/default.nix @@ -19,5 +19,6 @@ with lib; { ./kuma.nix # ./authentik.nix consumes too much RAM and serves no purpose for now ./paperless.nix + ./trilium.nix ]; } diff --git a/sys/srv/trilium.nix b/sys/srv/trilium.nix new file mode 100644 index 0000000..e129eba --- /dev/null +++ b/sys/srv/trilium.nix @@ -0,0 +1,32 @@ +{ + lib, + pkgs, + ... +}: +with lib; { + services = { + nginx = { + virtualHosts."notes.posixlycorrect.com" = { + enableACME = true; + forceSSL = true; + extraConfig = '' + proxy_headers_hash_max_size 512; + proxy_headers_hash_bucket_size 128; + ''; + }; + }; + + trilium-server = { + enable = true; + host = "127.0.0.1"; + port = 8458; + noAuthentication = false; + instanceName = "posixlycorrect"; + dataDir = "/var/lib/trilium"; + nginx = { + enable = true; + hostName = "notes.posixlycorrect.com"; + }; + }; + }; +} From bf34e2fe8e16469272e5c755f64274be1b2c61ef Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 4 Sep 2024 02:20:09 -0600 Subject: [PATCH 15/24] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'homepage': 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=4fd192a71d19b79684ae544f4f8470aa777b968d' (2024-08-28) → 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=a49523cc42d61e0dac0d3dcb01cc1ca3fad7070c' (2024-09-04) --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 01e9394..7d7e63b 100644 --- a/flake.lock +++ b/flake.lock @@ -579,11 +579,11 @@ "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1724869651, - "narHash": "sha256-9DCEtAImTlEAyrCqIMm9S3nMfNzW1MOLJkGqpge6at8=", + "lastModified": 1725437989, + "narHash": "sha256-wxBIg9A4X3nvWpgpiG/MjkEIOH3Oxy4Qdhq50BF42jk=", "ref": "master", - "rev": "4fd192a71d19b79684ae544f4f8470aa777b968d", - "revCount": 18, + "rev": "a49523cc42d61e0dac0d3dcb01cc1ca3fad7070c", + "revCount": 19, "type": "git", "url": "https://git.posixlycorrect.com/fabian/homepage.git" }, From e536c096ce55dd7b0db6f452651b7c958fab8aea Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 4 Sep 2024 14:14:42 -0600 Subject: [PATCH 16/24] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'conduwuit/complement': 'github:matrix-org/complement/6e4426a9e63233f9821a4d2382bfed145244183f' (2024-07-30) → 'github:matrix-org/complement/0d14432e010482ea9e13a6f7c47c1533c0c9d62f' (2024-07-10) • Updated input 'impermanence': 'github:nix-community/impermanence/23c1f06316b67cb5dabdfe2973da3785cfe9c34a' (2024-06-22) → 'github:nix-community/impermanence/c7f5b394397398c023000cf843986ee2571a1fd7' (2024-08-24) • Updated input 'nixpkgs': 'github:nixos/nixpkgs/12bf09802d77264e441f48e25459c10c93eada2e' (2024-07-29) → 'github:nixos/nixpkgs/6e99f2a27d600612004fbd2c3282d614bfee6421' (2024-08-30) • Updated input 'unstable': 'github:nixos/nixpkgs/52ec9ac3b12395ad677e8b62106f0b98c1f8569d' (2024-07-28) → 'github:nixos/nixpkgs/12228ff1752d7b7624a54e9c1af4b222b3c1073b' (2024-08-31) • Updated input 'vpsadminos': 'github:vpsfreecz/vpsadminos/2c8ff8462a6f4aefb7bd2663d6ddbedd9d161f2c' (2024-07-27) → 'github:vpsfreecz/vpsadminos/605f2f6c56cb79eb66b2b7d3bec050342d7f43b7' (2024-09-03) --- flake.lock | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/flake.lock b/flake.lock index 7d7e63b..30e6333 100644 --- a/flake.lock +++ b/flake.lock @@ -127,11 +127,11 @@ "complement": { "flake": false, "locked": { - "lastModified": 1722323564, - "narHash": "sha256-6w6/N8walz4Ayc9zu7iySqJRmGFukhkaICLn4dweAcA=", + "lastModified": 1720637557, + "narHash": "sha256-oZz6nCmFmdJZpC+K1iOG2KkzTI6rlAmndxANPDVU7X0=", "owner": "matrix-org", "repo": "complement", - "rev": "6e4426a9e63233f9821a4d2382bfed145244183f", + "rev": "0d14432e010482ea9e13a6f7c47c1533c0c9d62f", "type": "github" }, "original": { @@ -595,11 +595,11 @@ }, "impermanence": { "locked": { - "lastModified": 1719091691, - "narHash": "sha256-AxaLX5cBEcGtE02PeGsfscSb/fWMnyS7zMWBXQWDKbE=", + "lastModified": 1724489415, + "narHash": "sha256-ey8vhwY/6XCKoh7fyTn3aIQs7WeYSYtLbYEG87VCzX4=", "owner": "nix-community", "repo": "impermanence", - "rev": "23c1f06316b67cb5dabdfe2973da3785cfe9c34a", + "rev": "c7f5b394397398c023000cf843986ee2571a1fd7", "type": "github" }, "original": { @@ -929,11 +929,11 @@ }, "nixpkgs_5": { "locked": { - "lastModified": 1722221733, - "narHash": "sha256-sga9SrrPb+pQJxG1ttJfMPheZvDOxApFfwXCFO0H9xw=", + "lastModified": 1725001927, + "narHash": "sha256-eV+63gK0Mp7ygCR0Oy4yIYSNcum2VQwnZamHxYTNi+M=", "owner": "nixos", "repo": "nixpkgs", - "rev": "12bf09802d77264e441f48e25459c10c93eada2e", + "rev": "6e99f2a27d600612004fbd2c3282d614bfee6421", "type": "github" }, "original": { @@ -1184,11 +1184,11 @@ }, "unstable": { "locked": { - "lastModified": 1722185531, - "narHash": "sha256-veKR07psFoJjINLC8RK4DiLniGGMgF3QMlS4tb74S6k=", + "lastModified": 1725103162, + "narHash": "sha256-Ym04C5+qovuQDYL/rKWSR+WESseQBbNAe5DsXNx5trY=", "owner": "nixos", "repo": "nixpkgs", - "rev": "52ec9ac3b12395ad677e8b62106f0b98c1f8569d", + "rev": "12228ff1752d7b7624a54e9c1af4b222b3c1073b", "type": "github" }, "original": { @@ -1200,11 +1200,11 @@ }, "vpsadminos": { "locked": { - "lastModified": 1722101851, - "narHash": "sha256-fM5Z8Qhk9/AbGYJ4VrJilGlFK9btBEF+ROtbYYJZJ1I=", + "lastModified": 1725379879, + "narHash": "sha256-RXSlp6OS9BNCio8kKajk4yEpntNc2AyozQeDSQa6f3w=", "owner": "vpsfreecz", "repo": "vpsadminos", - "rev": "2c8ff8462a6f4aefb7bd2663d6ddbedd9d161f2c", + "rev": "605f2f6c56cb79eb66b2b7d3bec050342d7f43b7", "type": "github" }, "original": { From 9aa997637ff016c922ff3c43e8147378f78feb00 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 18 Sep 2024 18:03:38 -0600 Subject: [PATCH 17/24] invalidate_digital_signatures in paperless --- sys/srv/paperless.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sys/srv/paperless.nix b/sys/srv/paperless.nix index 8a2a137..d9fcaa5 100644 --- a/sys/srv/paperless.nix +++ b/sys/srv/paperless.nix @@ -30,6 +30,9 @@ with lib; { PAPERLESS_URL = "docs.posixlycorrect.com"; PAPERLESS_OCR_LANGUAGE = "eng+spa"; PAPERLESS_APP_TITLE = "posixlycorrect"; + PAPERLESS_OCR_USER_ARGS = { + "invalidate_digital_signatures" = true; + }; }; }; }; From eda3ab9aab48dbcf3d3c92f154a6fb25c04989dd Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 18 Sep 2024 20:51:09 -0600 Subject: [PATCH 18/24] add index of pki --- pki/{fabian.pub => fabian.ssh} | 0 pki/fabian_primary.gpg | 25 +++++++++++++++++++++++++ pki/fabian_yubikey.gpg | 19 +++++++++++++++++++ sys/default.nix | 2 +- sys/srv/net.nix | 14 +++++++++++++- 5 files changed, 58 insertions(+), 2 deletions(-) rename pki/{fabian.pub => fabian.ssh} (100%) create mode 100644 pki/fabian_primary.gpg create mode 100644 pki/fabian_yubikey.gpg diff --git a/pki/fabian.pub b/pki/fabian.ssh similarity index 100% rename from pki/fabian.pub rename to pki/fabian.ssh diff --git a/pki/fabian_primary.gpg b/pki/fabian_primary.gpg new file mode 100644 index 0000000..a84bcab --- /dev/null +++ b/pki/fabian_primary.gpg @@ -0,0 +1,25 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEZHlROBYJKwYBBAHaRw8BAQdAhzA1JCghQ6KoHOuf6JPQhEmchHLVXFVye4I2 +pRUOUMO0KkZhYmlhbiBNb250ZXJvIDxmYWJpYW5AcG9zaXhseWNvcnJlY3QuY29t +PoiUBBMWCgA8FiEEeqJ35gSkFzkWu7TpH/rDXheYF08FAmR5UTgCGwMFCQlmAYAE +CwkIBwQVCgkIBRYCAwEAAh4FAheAAAoJEB/6w14XmBdPP2EA/i9ugFxpIFF6oOQs +clMfr+sNj6Il0OUTJK0dqpp4mGorAP0awa6nfhU8T1Ju7UWr6cfSmnL4bM6M/4Z3 +D+AF/L5PBokCMwQQAQoAHRYhBOd6gIv5qVXWaO7qZHP6nJy18CSbBQJkeVKDAAoJ +EHP6nJy18CSbzTkP/Reio0ObRrRW+QSw62ZXrUG0mFcNeeoM9amldCToFRyGnSDu +wtZ9nqwLiTJ01VPBOsEZLsl4VonO3rdadqnMTZ3XqKK9VHBl6UNot3DQ8INDAcko +GW1zvEdxNkpMxhtAja0JkcBdG7+zxc2aEGeKfEna2qDXA+xtYw5+pssOWYMip7hm +jQ2NzYMYav2KYRBC7eXTkAIIIJi/l9pR1IwHtY3a0gfbkQymgCyt5wVG6LneYFIR ++ycNVCObwyP8gFASdId0bWnA23rkilc9ZBOCps/cGfDLM+KQ+sLAWBFBQyQeEjcv +tU+pLXncAEvWy/SFmprVSLDQMMooFaEJMZChojGcCkwAPG1twsihqIA3E44Q3/+G +K0gZN57jGMnfvuQiuLuttOMdu27KwEu++t3YUt0P6S4kARpx51zZJ7A2Yj2u22aM +7EL8qq6KTNdNoS7FgwQkrWbokdDZIl0HV+5TeMQfylPqOPhuFK/1A9qztqknBPVY +QUx2t6FZUgH9sT7uD+5gXxyeqmEIFo2i6D8G/4TEPbKtWivJfeOqDEBn4QEY2nvE +zgJLLU5XCv9xPz5rizRCa+h+kg+i4mH6fLCBCCAPXsbAAo0gUlGJvX4slPh7uPOa +T2r7A/7uezResBzP/L/vostlmjO5c8cOl9Wc6D1kRZq17/AjMUgy6+KR3iVnuDgE +ZHlROBIKKwYBBAGXVQEFAQEHQPRbCS2p8xpt3fRxfyRnDOdH9pULY4NtGmZUS0ve +ZGkTAwEIB4h+BBgWCgAmFiEEeqJ35gSkFzkWu7TpH/rDXheYF08FAmR5UTgCGwwF +CQlmAYAACgkQH/rDXheYF0/65AD+LtDeedCYv9zs+1Ia3DvejVZM256WEH+dRH5h +Pm3RzQ8A/2+bXRnfsgGqacj/kKEL3spuos95ngRNRkrQ39nc1koP +=PAxr +-----END PGP PUBLIC KEY BLOCK----- diff --git a/pki/fabian_yubikey.gpg b/pki/fabian_yubikey.gpg new file mode 100644 index 0000000..15555b9 --- /dev/null +++ b/pki/fabian_yubikey.gpg @@ -0,0 +1,19 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEZukhMBYJKwYBBAHaRw8BAQdAC/Gy2p7RPFw3k+ROFnKpJvCVqQb+BUYboE2u +CP1kz/C0KkZhYmlhbiBNb250ZXJvIDxmYWJpYW5AcG9zaXhseWNvcnJlY3QuY29t +PoiTBBMWCgA7FiEEcgbY7iR0898Y6odvDsFpH/jBqB8FAmbpITACGwMFCwkIBwIC +IgIGFQoJCAsCBBYCAwECHgcCF4AACgkQDsFpH/jBqB+oGwEAhmegCZJAt8Opv/9+ +HBbL51f2035qymHPgkV/SyFM1GEBAOVQY6A5U+NrLNiaQTN5Z7jcfQuBobzk4ksn +RzROhTcAiHUEEBYKAB0WIQR6onfmBKQXORa7tOkf+sNeF5gXTwUCZutnFQAKCRAf ++sNeF5gXT1juAQDsH/lDorfMdWxuP87eV9OP8jQvibuTuZ9n2jUllXsLcQEA5gDJ +05NW5Tw2g9mvlrocWr7N2/PC5UvFct4akwDXtA+4MwRm6SEwFgkrBgEEAdpHDwEB +B0AHSmncE+krtL9ZGe4eq865vjaLiUAVnZQaVObKm11CBYh4BBgWCgAgFiEEcgbY +7iR0898Y6odvDsFpH/jBqB8FAmbpITACGyAACgkQDsFpH/jBqB+hBwD/Y9vAcbPG +CTmZvtgYlZW5Oey5T3hHoANv1THOZwv9G58BALEBZRvDztmYPjRaMyAMonrpc2P0 +GPHYLcqCPVbjkaAKuDgEZukhMBIKKwYBBAGXVQEFAQEHQC2+QJcHEJjdZikBYeMj +ks53MjfeawAXU31KtAU60KACAwEIB4h4BBgWCgAgFiEEcgbY7iR0898Y6odvDsFp +H/jBqB8FAmbpITACGwwACgkQDsFpH/jBqB+0TwD+K4IcFstNGLrijlgH2zuQaI+p +8QT8AInjSpGfC4zcMlEBAIVYvdTYw4IXPSQOs0qPyR0nhfGIeoBMeWrAAfoxQ0oB +=wpc0 +-----END PGP PUBLIC KEY BLOCK----- \ No newline at end of file diff --git a/sys/default.nix b/sys/default.nix index 37f91ea..14867c4 100644 --- a/sys/default.nix +++ b/sys/default.nix @@ -62,7 +62,7 @@ with lib; { group = "fabian"; shell = pkgs.zsh; extraGroups = ["users" "wheel" "networkmanager" "dialout" "libvirtd"]; - openssh.authorizedKeys.keyFiles = [../pki/fabian.pub]; + openssh.authorizedKeys.keyFiles = [../pki/fabian.ssh]; }; groups.fabian.gid = 1000; }; diff --git a/sys/srv/net.nix b/sys/srv/net.nix index 9d22700..30a92be 100644 --- a/sys/srv/net.nix +++ b/sys/srv/net.nix @@ -32,7 +32,19 @@ with lib; { "posixlycorrect.com" = { forceSSL = true; enableACME = true; - root = "${pkgs.local.homepage}"; + locations = { + "/".root = "${pkgs.local.homepage}"; + + "~ ^/pki(?:/(.*))?$" = { # https://serverfault.com/a/476368 + alias = "${../../pki}/$1"; + extraConfig = '' + autoindex on; + autoindex_exact_size on; + autoindex_localtime on; + autoindex_format html; + ''; + }; + }; }; }; }; From 7fb08352479dd73707fff5bc5ec5b75b041754ef Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 18 Sep 2024 20:55:05 -0600 Subject: [PATCH 19/24] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'homepage': 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=a49523cc42d61e0dac0d3dcb01cc1ca3fad7070c' (2024-09-04) → 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=d26219c00d1f6070b85278c5efb3cd44ce6cc4eb' (2024-09-19) --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 30e6333..94924a5 100644 --- a/flake.lock +++ b/flake.lock @@ -579,11 +579,11 @@ "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1725437989, - "narHash": "sha256-wxBIg9A4X3nvWpgpiG/MjkEIOH3Oxy4Qdhq50BF42jk=", + "lastModified": 1726714434, + "narHash": "sha256-+CXSWo4HrF+6T6xD7wQX7ckVRuljXuWTGOdNWI0mfsw=", "ref": "master", - "rev": "a49523cc42d61e0dac0d3dcb01cc1ca3fad7070c", - "revCount": 19, + "rev": "d26219c00d1f6070b85278c5efb3cd44ce6cc4eb", + "revCount": 20, "type": "git", "url": "https://git.posixlycorrect.com/fabian/homepage.git" }, From a462a2df0a46682728aff070a96da595fc7514ed Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Wed, 18 Sep 2024 20:59:41 -0600 Subject: [PATCH 20/24] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'homepage': 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=d26219c00d1f6070b85278c5efb3cd44ce6cc4eb' (2024-09-19) → 'git+https://git.posixlycorrect.com/fabian/homepage.git?ref=master&rev=c5ba6530fb371d09faf933a08efb288b037705f8' (2024-09-19) --- flake.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 94924a5..917a1d3 100644 --- a/flake.lock +++ b/flake.lock @@ -579,11 +579,11 @@ "nixpkgs": "nixpkgs_4" }, "locked": { - "lastModified": 1726714434, - "narHash": "sha256-+CXSWo4HrF+6T6xD7wQX7ckVRuljXuWTGOdNWI0mfsw=", + "lastModified": 1726714659, + "narHash": "sha256-DCngitzTqzhGjoykt7npvuGxc9aWDgZq3Pn+S6++5EM=", "ref": "master", - "rev": "d26219c00d1f6070b85278c5efb3cd44ce6cc4eb", - "revCount": 20, + "rev": "c5ba6530fb371d09faf933a08efb288b037705f8", + "revCount": 21, "type": "git", "url": "https://git.posixlycorrect.com/fabian/homepage.git" }, From e46d1dfef717ae57f9b89bdeda3e70023e32c092 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Tue, 29 Oct 2024 01:25:23 -0600 Subject: [PATCH 21/24] add cdn and factorio_blueprints --- cdn/factorio_blueprints/red_circuits.txt | 1 + sys/srv/net.nix | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 cdn/factorio_blueprints/red_circuits.txt diff --git a/cdn/factorio_blueprints/red_circuits.txt b/cdn/factorio_blueprints/red_circuits.txt new file mode 100644 index 0000000..1e9e840 --- /dev/null +++ b/cdn/factorio_blueprints/red_circuits.txt @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/sys/srv/net.nix b/sys/srv/net.nix index 30a92be..ab69cf6 100644 --- a/sys/srv/net.nix +++ b/sys/srv/net.nix @@ -44,6 +44,16 @@ with lib; { autoindex_format html; ''; }; + + "~ ^/factorio_blueprints(?:/(.*))?$" = { # https://serverfault.com/a/476368 + alias = "${../../cdn/factorio_blueprints}/$1"; + extraConfig = '' + autoindex on; + autoindex_exact_size on; + autoindex_localtime on; + autoindex_format html; + ''; + }; }; }; }; From b460ed6e57d74167461a658b8f2299690a2c54a6 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Fri, 15 Nov 2024 16:03:36 -0600 Subject: [PATCH 22/24] update factorio blueprints --- cdn/factorio_blueprints/nauvis_science | 1 + cdn/factorio_blueprints/{red_circuits.txt => red_circuits} | 0 2 files changed, 1 insertion(+) create mode 100644 cdn/factorio_blueprints/nauvis_science rename cdn/factorio_blueprints/{red_circuits.txt => red_circuits} (100%) diff --git a/cdn/factorio_blueprints/nauvis_science b/cdn/factorio_blueprints/nauvis_science new file mode 100644 index 0000000..2027858 --- /dev/null +++ b/cdn/factorio_blueprints/nauvis_science @@ -0,0 +1 @@ +0eNrcvdtuI0uyJfgriXyWGn6/FHA+YYAB+rGwUVAqWbuEo5Q0knJX1xTq34cRpMSQkotctjy4G9PIh1RQooW5udvFzZeb/fvrt/ufm6fnu4fXv317fPzvr3/59+GTl69/+evicfrd983L7fPd0+vd48PXv3wNX35/3mwevtw8fP/yvPn+5eX2bvNwu/nytHn+8rK5fXz4/vXq6932/x2ll7vfH27uJzIPNz822+/f/Hx9/HEzEbvef/X66eb2v7/+Z/uth++b//X1L/4/V0e+d//4+93L690t+lb4z29XXzcPr3evd5vdq+eHf/3t4eePb5vnLdmrN1KvzzcPL0+Pz6/X3zb3r1t2nx5f7nbD+/fXiYFS/0e++vqvr3+5bul/5O07vt89b253f5Em7j6RDgbSzUY6Gkh3G+nEk67ORjobSHsb6WIgHWykq4F0tJFuBtLJRrobSGcbae8MtIuRtkEfq1EfvUEhq1EhvUEjq1EjvUElm1ElvUEn2wmdbMdoH5Ty7zcvr9d3Dy+b59ftb06a1kiRPijlzcvL5se3+7uH369/3Nz+4+5hcx1Ov8HPb9jSv3vCLuTtD/72//y8ud++evuHD4/PP7bO5xg7B0X+sfl+9/PH9eZ+y/7zlujT4/3mtFWeBnyMZrcOcWGO1x9icPRkLvigJjN4nnQ0kg5mIcZLCjFa18nC7IN1EpJ5iOWSQ8z8ZBbjZBbJVgWKdpVoc3w3ibajaHeJtmdoR6dbtcnHHVut0SuR6+SNP/LrwzHiUsTNEo+8N2sfxHBe0EkJjFm+sxLQs8SL4BVIoVQlpGf5bkpQzxLvgj/jhJKc7kCQSiavbBVIWaSgbHFY4rxKLhjnBG33qgelr6t71SSF6eRQJbf66xQdpV15o3mw9oWb/SZZ+wK0wB5u+08Mv084SmaZpjw7xYoUKg/jJaUEkstBsh+IWpSoVUAtCdHoXn/Prb/MR7qHXTlLW9PJyuhklkLdX1fWUdpNSadO80jQ7hJtKlVRRkLddHztFS/ZJ0RNi20zoHbQsvvHrZ37x83D98130jxnKiGbBuxpvIA9LdkcOsWzk1IkY4UmpUpmGfEmJZchb1I+GfFWnWKWE2U6qx+I3NLqkVsN1mW3cBZgMmpUPA8pviR5B8qCVy2KpSx4LZJ3oBI4tUq0qcRTbUqEHLm57JLPCMdXXXMSNZC2bH7AAwXqcC0oAXSkSEfJtiLBJokaEmyWLDXiTfNwiLc6YJvXz1U3KTHL2YwmJWY5m9GdZI+opG+XABGVSlZ3LYZ1xxdTjxI1D6glxQ47yg73PBALuwvEwr0optFRuAMtiEVzrAWxaI61IBbw5p2TyHlEzitBsadWoHdBMkeUyfAuSsQdRzwpwS4rlqxYu9I5zqWQtDSOeNUzFvMrjhKVUqqlI3JS/Am5W+COzCHjr1N2HH3kdUtd6gUstfdBT1tgSUrxKyYnBbBw2XgpgsXcSSEs5m4ght3r9qrQI98Et1G4Aza/ACGZsxdQgsEp7oI0usFLxDmjG4Lgi1hZhyi5i8JxniTilSOeJTtf0PooErmKyClnkKWSk9YGfFLhUKsKnOBX/o+jVp1kuZGoowQlgAshSuABTE46WsSDHYAIlLy+I4hSdpW0H1E6kCTtR5Tyq4UDIUfpSLJkjrgW4YJjEZ+kFGvJiJxXLB93TuBTGAiV0yVCZQscKOLhHofgayEunBktxIXkisQdXIZV4g6SkyLUTC5DKc9KqnfWIlXOMGWvBJOkWCygnIXVCxznWqTK3exYQHbsiQ1wiuGzFqFCclqEim56LBA59iAyctd82oC19pew1rkPJDbQxBQpJQsnpkhAOUxOQsrhwWpZHEhOwcr9ajGO26OSB4LlsH6wvEDu2BMbcH4lZB1pF4t0WEla9NIVX0TOfZWOKwt39lCl88rCnT1U6cCyoAOjKp1YFnRgVJUjy0KejCywOnafRJ0U+qqcQv7K/3Ha0jEkFrV0DokXgnQQCblrmtdD3LUBBF3uF7hcK51dkvajSWeXpP1oUtY1c8noJp1dZi6N3qQIN6OUf6sSOXSk0xTQXCbz8G3gJkhulwiVu3IV5NfhHjWUXQpx4cx0KWUL102XUraYuySRg9wpd51/VcDjy7BLGVfSdnQpUiVtR29CMEmLRboFkqlEdHBSpJoLR9zriY0MzjSCkyJUTE6KUHNF5JIeRGbqBCu4AWxdzhew1sEVPbGBJ0aKZzE5KZ7F8yzFs5A7L8WzkDs/Es+W9Stk+KC4De5SbPBRT2xgCUqXQki7qJUgIi26oQbRQg6srKVzy5w5zqVzy5w44tK5ZQbnTyFI55Y5IXIDd0MyV5rPgORZ0OYOX0JQDiJz5hjXQlgo6iw5AkhOOojE60o6iMTk2oAjiOs7Aq14D2k/onR2SdqPKGVdM1cuKUpnl5mr8xS1CBcV37KU7lmQC4hcVswSl4cPCwyPPVQOlwiVY1UMJXX7L5hK/OTzM6OFuLBomwS8w+S0LA4abJIiVO5SakhSxpW0HUmLVDnbkZSKH7RYpNsimasSl7RI1XPEB6pfZoeWoBahInJZi1A9IjcSoVInWCEP4OtSv4S1znEgsQEnRotn4cRIwDrMnRbPQnJaFgcOVgHWZe7Oash9IFh26wfL9hI9CxuMJFik2yKk0S3SuSVpdItSA4Sd+yKdW6bOcS6dW6bGEZfOLVND60M6t0wdkVPOLVMnJ63rPilRh4WhKgeRqXO0pbsjcOaqdBAJZ65KB5GYnAQnx4MdQNel9atVhiqdXZL2o0pnl6T9qFLWNXHJ6CqdXSYuja6V50noDKZJ1esSOkFoSr41kXn4BYbHHipfonZnaEkxlNR9wNCklC2eGel6NF43UsoWcycdVGLuuhAxJ+4uaOhSxpW0HV2KVEnb0ZV7zbRYpNsiiUtEdy1S5VLoPeuJjYSOSLoWoUJyWoSKjkj6wH3mxJ1g9QF8XbpEZdDonJ7YQBMTnZSSxeS0eDYjclo8C7mTsjiYu5F4dv0antEVxW1wF2mjvZLPwgZDCSoYPJpj6dySM7rRa140ccSlc8sUOeLSuWUKHPGoBNDc2UP0Azi9RB3HRS/dwEwBtZHRvGhE5JSDyBS5kUsHkZjVLjkCRC5IWDs4L0HzepBcUNoBpkC2C4pKI0OaelLaDdLUs9JwkKZelJaDNHUtg8NZYa3bFmnFTIidYCRuQuxEo//QEDuJaxSmIXaS44hLns+RTb0k/E4CB3wxal7OI3IDiJ10icKxUULsJMetfy3XA+dCc5RoLpLmKBF3aQCU/nlqf+HHMqMS1odVr2TuM7J4hyffoRSIpQcggdNp1jU3C5eo5lfhEm2Ss2PH3iVvxzmkrLlSziFZ2mct5ILErJXqiVwTRa1UT2wc8YFSPbEhcQwUHojUUXPUyvdgjqUUbEQdUkdK9cRL1CCOWcK+QnkVCfuKyUlbTih+rUgPJmcHzZXzRJPuViPb2XUgB/t5GS4Ys6y7kSI9WHZVsd549UlOEnMneUXSGVTJK5LOQCvEEwtHXPORlSOubDAjd/oZ60BqNVKAgFilTWcER+6xat6xIHLKjjFWbuTSjhGzKu0YoSC1sjyQuyYB5DB3yr6PXfVaVR3Mq3SrA0tSucdBLskFnIbU98UrCindKtlxztSammJFo6ltUv4UTqQJcRPOLjOt91Xkjh675sK4Q1OtF1ZEx/ldyopGdBg90v8qfjrOv3ve7mV+39w8X//zH5vNvTGi7GbtXPgkCt4Su+TvyJN3rR8WnmdtYwfIJadt7DIipzk8SC4MbJq4m//JxYFNU1pj05ScUsaVXH/J5YEdGZwYCS2OV6GUBcXcKUiaSFWhSE7b7VE+IXltt5c44lIOFM6ZBTqzIIfmzGtZz8ANXYKcxsgR1/ZyAQlC28tFRK4OOHK/oiNPvumQTTy8PhAdUGf8SYPbQI6D5iLRcgkSyBRzJxUox9xpu0DInXS0h7kb2fhxOL0UtI0fZ9eClsmE4tV8G2cmo1SoMXqOuLYNdBxxqWBjBIeHSStnEz0ip9xbityJb4rSxSU8dOniEiYnXVzCktR2apBcV4CQkSo1kUzQlnpWkqZiNN3Ka1BQlSxxLW2JJs1UjMZZec2SfeWslAmYEo32VStGEzpHXLrAGxpHXCpKE8DZYdKK0oSOyA00Lw5tzeg8B8GNBO5gOuWoR+mBAoikLF3Px/MsFaXB8ywVpcHkJMeHB9sUZ4K5kxwf5M6EPelG21Mkx0faHlM1GYc5P65URfJ8NPWkuBOaelY2LjR1qS5bKNykaq6wcsSb5F4KUh3N+YHDtrQAo9i9VV7TW1Wv55Lw8MKAl6JwH0mrSQPnt0p3eLEApN0e5k5zepC7KrkVSE5zenCwXXIknFlomgvkDFqTcieBO3Ro0hF64I5LmpRJCehEo0lH6AGdaBggKws7Qp5aNk23IK9aQAklKd2fxdxpASXirku5E8hd10JIbombmjN1o3JqZV4Cd2yilXkJXDK5S2duASW+TQVeulUQ0l0DlniTOCcPL0xgE49ZPzaH2QQ9cUbWswmJ4s3Ug8Q7NafZVOglmFm3xIzxA+tHyWWJHMusdGCAmdXcXETktBASktPcHBqs14JGTnm95vQiR/ygXT+3W7Dn358ft/8T2vtrpvzq6+u/9tCsp5+vX4++LUqWwnND0bTNoznNJsnET5LZy+Lx5ysUhqZwkN9q4jfb+dVUEPLbTfxWM79BU0pusS2gJQz3fUxvgqilvuG3nZLcQU1vHx9eXm8eXq9vH398u3u4eX18Pv3GfuSNWyKvz4/3f/u2+cfNH3dbCtuvvex+//Lx57/+eyuF75uJ5tXXv9/db/dwnz99y4rBu5u/ZLUmBn483TzPzP/l63/NH/x8eN2S+89v239Hl+cCTmNS/73Iz09ptso4/ukyvn18eto8Xz/d37xu1hNs0ewULdhqFWz+0wU7Z2RXFmvTzCkt1m4Va/3TxbpLTD8+3N1e39493/68e11NvAtIlcneixY4equ0+58ubVQ6ciWBByVU9FSSN1twYQu7C/LbOUpnA5hcVgItTK4ocdAxSf529fWf2+dpPfx1Gw3mq22gkH+72v281ZDp5+mjq7T7efrow89l93Oaf86Hn2uYfy6Lz+ef/XYXOT/k6cGH5UOfH6Zvvj/Mf/7+d/unnHZPfv7L3JdPpeyf+vJp+sbhL+enqT317qnPT2X55PdSmL7//jR/4/0v90+p7Z/mv8xx+bSXzfz9w1Nqy7/cPfWdhOZPr6byvMunncDm7x+epm8c/nL3tJfL/qnE/SzN39tLYv7+4WmWxIQtn59KXP5ufjr8rswT/zbDefG7+f+r6VQx/7ZdT3evmx/bhfnt/ufm6fnuYVqTf2wtzrzgcgk99Z5Tcinmsl2NexvkpmV++Mp27X7fvNw+3z3tFurX8GX65Ze9XfqyjWG+bA3c48P3LfW72zcz93L3+8PWOm2//WZp/7H5cXd7c//RoB1e6ycFmLXrbrMj8bn9uoAS8GiDpNg/z6W9opBR8zCjKxHj0nOClSZJFyHvR5JWEl8kaQU1S5LuQrFPkrRXDoFY2l4AvLK0gxTz+SOpt/MBtik11vFAjsU7UoNyqPBSR3KPcqfeXMSxHJTmE9Bl8/D79KWfD3fGMn+L3BlbhqR+YuLcWrJ3DjisVu76qalref/A/jH3Y9rwLJjN1H7SdDXLnWU2SNRQ1wj7NeWCluTxmMLWLsdezqobl04wV5Wrzbb+jVmfjqkz++dgyoUvjFTmcstSFWW83rqAXYW6sMhUsDftApY2qIhvVZCWLqgg0dCfJ2DNOF51d8A7tZW8k+Ha2cItcdWx7D18Dm9AhWLKgKtj64ZJrg4WUJKowbI7ouMsnO1Jhi6THsv1KMTFDvX158SRNNeMoKTa1hXxlsyOPq6u3SkPRBttdWOaykC0wWlvqmIsUIR9VTJ0gW4247m478aqSzu3wLPde3vM9XGkjxeDo0qeFEnRDMxeS9SAwuc0ELisr2s5K4ELZcqzvThsOCu9kV0y1ULZ0LJ9QZq6tZhVt9w5t1zU/TJ3/mq5PLeIUcC9QcttuQU1cG2w2K+cerwujtosoaSzw+vj+CtseC93fAJPLJAysMemtKeofrULfrU08WXSgXjpihenDEMd8bjc0qqqxyWXVtVcLjAOVXO5wDjYKzwvHBFnHOz93Q+b9M91t+QwvhbdOXI1LWrV99WRa+hSpZ0wqvBRpYQ0KpzSRAe7F+45e9a87sTIEj+WmtIez9zRg8GoOa+PwsEWpiWRvuOEn/WN+Goa3Iq+Ef/MxAqbgyZ68yNlZpgJbvq2nzQuresBEGchu9P8LKsFXfTjpBZ0yY0j69slN46sbx/YOV9AObqyc+ZMqb0I9uINnCPodSBgSSuZu67stbk6nr3rpwqoYqK33GFcRBOQnLShRvUtvb189iJC4W7oeRfFCChw5s1bimN7zP1xDFDWzxaw1IueFoiBlHoVQ59IGX3v2kDss5Yx8IsLkfbgJ61u3713YvQTFOyV9wPRD6m9PggpjEiC4KJ+EgEtpL3tffNW5bJdsmzeqly+SEEQFEmVyCHz5dtAUHUJpetKVMXZ/wWezHwgAQW4QJEZYhgOsBfCQEInca+IUgySkDSSGB+QqCcfsviCxGlrKJI8MpJHHYgOOCSUN167c8dFckrmfSAvRQJHo+psk5Jq8NEPJAI4zYoidDtmCbodFdfOmaGYJJeDdCLmAadO6kQsolNndSJqbhjZzdgGdvysivWBLX9dK8pPbsCnUbgDn7R9NYB/+BREl8OBVXyKA/t2Dm/jLYXOFyIpSCRZ2aUXbvaK6M4qqbqpDrizSspb9cmFXDN9YMe+mi5nN7Bjr+tvHvKIV+dsSw4D23RSWXMUI4cqxUI5ib6SXKuW4urNnbU9WdtPI+uexXsatLnJI66dNDe5D+ziL6CIxSm7eM4/FK+HMcmtZfpKULb9jRthHDi76OiOoxYBQHLqPpzEE/mibcQb4ncEucJBrHxRnX7nDGnpA8kEDsfkqxs4I0HCr14JFynonF8Az8yR0HrmoA7c1/zMxRoGeAF5s2fjkc7XLMYlTcloLNBshowGZ2HtOLbardbAAmRr7rzwpRuaUCWbilMhbZUdy9a81VYtwGz2fD4UTFRCF85WtQEEyyWsRMt6LiY5bshFiJOS52hXLQZJJNbKtya+wJFKIqFTE0Bb+S7BU5JD5LwWziSyOqrvQU/EJEcWpIh6zJQ8+Y6kpx1INeqi601ecb1dcb2k0nYRU5qclNzokhfGOtF1t0Yup2BBmTV3zioEJyJGWTUOdtzZwXGSahzcQBGEFFeK8oNLA/6SwigEJ+6rE4dGCU7aVqeIFtfAtjoFcu6lGyEpIJa7sBlNFAgqGCFj7hP58xWLBm6IJA4kFowlx9zxFXjCXvg4sGNfTZd9Gtixx/UrLPmsb0lZTfJiBaQUpQpI9pJmtRnNpW+ic6MXaxdfQGp00Jw9sseWmmbNnbWVYcS1k/bGXupssSm+gCKGJCQASP8QBq6JprKW6QvSnjxxI6z62UWCpfUGKhemTC5DbS+OWI7aXhyWA/RiWEjimUIMA/tkssKfBaPm8fwdXXcx6ecWWOpiPYZEFqCMZSASWs0cxDoQCZX1DXAcuAfKantUijmQJjA5/ewF2pPkxdAtCQmgkMJAmoO0Bkm6HIoFJIFUoeon8VYIq/qpDEQ9F1C6BSjOEPVwtnkBhjOf0+AJ6gO5GAppErJT4qTK0ZYwqgmgmEKWqimlgsiJ1zwTCYoKWbwnkjjMWch5IFFSyILFAzc/UyXfId78TIWdiDawRyfVSPK1nBoV8dpIqopbLKoTLlL+pIx4YXKBFc0LIztUNC+M7FBRvTC7/MtApQXWTpSBUguprxXllzbgLzunjH1gm85hPkLV9tUAVROq5oYbIideFUkcqibUgTKHqZMSViowJAp3Faq6oSYrYIYqXh5JjZyAOrBjX02XaxvYsff1Nw+1i36xS36xuYEEAWln2sBVEtJctiA6N1YZbBXZmrcqQ9OcPbLFTbonAm1xG9lhX0BJWh0INUjb3Zqyi+dsdxu4PprDWqavK3vyTIGsQvf62UVG8Jsu7cwxOaleQ3aIXNJDtkzimboIacksAKkPbMQzCUDq4kY8c6U/g6EU2iHqyp5b110/G0ErJzqnR0KrmYPovB4JfeZijTZATiz6kJ2Qj4gu6oEQqb3RUpCt2QxuFAqytXMWMtoLsjVvtAbRiZdGSWsQnYRaxSKR7o5A1fdOj6wuoXTeC1EPZzujH7hjggUYlSAmcgwPYFQz17rX0n1zEYNEJA0JkpoDIifeCskkJCx68VZI5iBh0Q+UW8ocEjAGNxAyRfId4v2RTNYKjUF1tkpz3BjEqgw5KEmOGCS/y9mIkV6bpI0II16YXWCqF6YXmOaGkaHTmmxCQzfSZZO1E3Gg2EJeqzVyjAN1EHPmmmxq+2rUADVK1RZyQuTywDY9kVNdRLfGIV5irMoOl2yR2gZcJtlw1tZUc+HOyNKWMYmXRzJX2jImP7BjX02XUxjYsV+gcW9S3brUFTqmgU7arCanEffOmcsk1lfklUH17awyaK4d2fukuXZk7/PIDvsCSpKlHTZnu/PAHRPWdueB66N5tR7aWWminckm2gNdtDNqSp21nTkkJ7XMzqjJdR64FZLJJt9qy85MApBiUVppZwocF8tAL20o9TJwUSRziKlYxFZimau4GstA0+31zEEZ6Lqd1+8EHIt4OzQrPbFjGSjBxGpvURpvkwa3DHTehhZypBEoq1xqJ1BWubROoFgkEkAVmq86UILpEkpXlS5ipP2vAw24sQCrEsR0juEBjGpu3Cuka54ZYJZik+CouSFy4jXPTELCYhMBqpmDhMU2AFDNHDQvtoFG3LmT7xCBqrmxE6E6W6VRdlQbeWapU3Zskt/lbMRIC0/SRvQRL0wuMLWPJ73AtE6e0NBprTyhoesDLblZO9EHii2UtTr6xj7QlLtwGIUu7asLQot0qd5SQWCHPnArpHB4nOTExtyFw+MkpxQwLhQIKrmBKojFk/IRN9SFrJSZnNicuzhyAga6c6+my8kNtOcu63cgTk5060Xqz53cQGEGWpMH3DtnLpMXSx/TyuBF384qg5dcO7L3yUuuHdn75Ad22JdQEq/ssEnb7Qeuj7K22w9cHy1rNedNXmnVXQInxYFe3QWAbVKQduaYnHRRtAREbqBXd+HgUSmIRRwKCY9KQbkpWiiIWgoDvbqx1AcuipRASl28KFK4Aq4pDPTqXs8chIFe3WX9tsFJbR9alF7dKQ706ma1Nyq9ukmDGwd6dUMLGQd6dbPKFcV6EKxyRam3GBaJ1CQUmq840Kv7Ikqn9Oom7X8a6NUNBZiUXt0lcwwPYFRL4l4hYVRLRtKQMKolIXKWWyHtPHciHLVwALA00gW0cEC8lNpAvJHJd4i1F4rSZjpl1c9KbbqTAXdWm1FhhU6ezaiwOQ64RHL+1e6dhawMm7T2nVCvtfad0OrkgaoKrBpnLSFeEMvSEXThMC+pOMkMI2aLl8hVRM6QulrY20KOPUrUIbMGB7kw3CyzWaLOLoORVPX6HWFTUVPVUk/jVEZS1ewEjqSqKQRPqmqqmqzDmVQwWOHqcCYNDAY1UgODQeM2Aga7hJJIYLBSuKU0kqomjU61HEQfJNnR9BhyzvkDNYZXezmj+ukd73P/NP1nm+pmqGPUrWNrXvKDAKyRmua00bS2KDk+SE7z0nCwA6jsun6PzqQCxYrSdDe1AVQ2vToVdFihoFupDaCy4QobwYMVDqyUVDxY4SqHJg0OhkWiOWKkdH3AEV9C6brkiCkAY+oDqGwsQMnzVgQJ6OaK/QcHjIl2iUeAM8j2AmQHB17DqAPPzl4ssJ8TUTaWD/MfCBLxfnbSDhnPgeR7MTlpS4ylOdBep35Cotw9Pz5c/765eb7+5z82m3vrYhnohFcpKEq2lAyr/dMwl1HCUeJikrlKTXuzd0KEUCn0V/YDjekrB9nJGkALrmMNoAW1zA9gr6sjJZCFrVsNJPEiOZKA5KH5zojINWFnRw9daV5bqSPXHJSryDVwtL1k2dGUhSCRQ1MWBjrS1rSmo7BAqrJ1DrJCm1w7BpVc7JfhhFSJHFwuUrEPzJ1U7ANyF51iK7njwRz9QCSfEMdBspiQXJTIZUQuDWwM8vDGIGbF/rPTWQZ2HVD+VbKmUP5N2mNAcl3cE3FAkJycNHokzGQvunFe4VKQ7CESqQVItCAHuZP6QGDuJMAB5s4SLR6mgjvyyEkLHgtitknkKiJnSblU69izBWpQzNQlxD1NPSi4Bpq6lmahDoWzDfGzIE/WJMoWxM8iECa5t0SKwUrc4smylbjFryUr8S6ZZKT4FhTQghwySxYU0MIkQ+60/Ajk7qBtL0/bAA1BK/dkGiKTJKWF5DLFld+T6YiMtrOiziJysehLtRK36EuzEu9SupMjbmkyuFifaAqrpj1oYS0wNcRybygNWCU0eUNJyip6pcZdwc81K3qA2ZXUCgtTKsHQUEqg2loMHAiSPQyypQzSYq4Qv82Jk8/ya0K05A/8nld3W1GkBXma+6iY2UbmhJtN86qdfU314GI5qN7t48PL683D6/Xt449vdw83r4+n0yTtV9z91UTk9fnx/m/fNv+4+eNuS2H7tZfd718+/vzXf28NzPfNRPPq69/v7reW8/One8bmLO7T/c3rtGH/Je0zvfPH083zzO9fvv7X/MHPh9cthf/8tv13fNhV1GmuvnpewGo4sS7U8M8S68vrZnO/tlzF/BAr1wX6h5Rr/tPlevP9j5uH283369u759uf823edYRrgyUtRs4KN1iFW//8Rfvz/u8/n9cTaRTNNStS6VpfQ5urnqVIAZIrkiOH5KQNzI7cb1df/7ldPNOs/zXmq3yV/FX+7Wr3c+/zz9NHV2nxs3d597D97CqXw8/ex/lh+uzKBzc/9L74yu6h7P5s/vD9S/unuvvW/Ok7jf3TNr6en6ZPr7bOdfdU4vJ781MIdfdU3fJ781OIb09pSWV+CmlPZfp0+9Tmp5na+/f2T30nqPnT9+/tn/aCmz89UJmf4l4Q86dXU2u1+Wmidvje/DSVM9899eX3dk9lP02zzN6o7J/Kjsr86dVUAHU3oXn5vbyb6/1fFr/83vw0FZ/YPfUllflpujs/P02fXqX92Gdq79/bP/Xd2OdP3783/3/43u6p7RfYLKUJIDg/tf7LU94v0Zn21YRBWzzF3dP86dV0UjQ/xY9P5Z3KdvnfvW5+bDXn2/3PzdPz3cOkNH9szeCsM7mEnnrPW6ZSzGVred4M46SHh69slev75uX2+e5pp2tfw5cfd1szefP8ry97BOaXp83zl63lfXz4vn3D3e2b/X25+/1ha0W3FN4OTPZf/AjdXL56y/RsAu42OxKf7IFhl5DfcosBtdpVaKFeTRaTf6BGBujm8870ZvbDp+PO4xNgO/+0Hn/lN6cRwAmO+eLKgSJ1E9jgQnJcUj5Cq2kTzbl2832zwwuo+8oG2F3OkPLRTaoddXd4A3c0bsHc5XRmyXmbwqaj84gV1l4iLdfLaaw333iJb9na8Kki+u/Pm4eb70bEhAXOl95VG5wteL48eXJLWue1o+lmtq0/aTwQ8GAOuYutlsppB4MIInQL8O9ADEyureHnwfqRB58h6gaWWkILdB/rHPM5+WbBZnOn2PZqaQdDSN1JtZVKOxDnGlHYC6UdjOz6+hrMF9MO5gnV5DYl3Q+Wk60gbnbZh1eQRdDNFVgOMuEquZvceIqQfabGviHtksJyGEf7TinE0DoZCKDJphqCL2IbMSjuA1adV4ihK5BO80WNrPGrUe9s6U49HCcvtEbdeXD3KJPmPBpb9kgOiqNfISi2lT97t7yRrVFdNfJkheomG/bI1fDu9ig/kvfoJJcRvXbRzSynCEdz/HA4CI4kItBEVIghyIQ5Fk7pHEmzzqayps5ms6M9DIm8WVjlPejnEa6R6mtyrg9OYZdjFc5yFGVzi7gtyuYWaVfRNreRw08VfW/LGc6S7BtR0oiVLEcrpF7ZWl/mZPS2Rdvokt626BvdCxiF0vXAKa1ghO0tNA/RDQe4stVMO1DnalDXIIQ21CXNqu2Go1IivSY9suEKpFdlixzB+ZwFDXogBu6H1qqHIatoAH8B/RB/UEhJe820Q/iRVrc0hhJq2ajiTXLsYHFZyqfleGZxNe0oOZI9Pey9NXMwGaGW5RQ4lG8RIg/OyNjLoWWbRrWmRQacL2ldjwzW19fu5BR4BMftXXTFZO3rHvRYgju17lHPlFBn+j1pTl+q196z9jKlFH2XXDY477fACA/E0KJsehqAQ1P0Lnj4zEFAnL4BJ0EmXnDbJAbESa4WgUAsxdJyPLMqvK1FZg5HbRVUB++yRp6FrLiib8JJjJATt8mJHULTvTmpPQOb37oGlMZrZ8KRK+ftvehvyXLk3iubXwpr4P2Ap+XwQX5gz1tIFJ3oYKUi+t5LLhYAVbyXfCyCefmmHx9ADru+cV9Fe4PTI4dKoiS9voWv66PYFogu8xECmkYBxuVtmh6SEhhAfrNCDSmGgNoKNktqhG2Fo04A+5jQhO08aT9D14MYUsFsqKycjB44eo0864EXmCxzyuAC9iFGOaBKbg2TbO9qeYh6GrlishZUdXLFFCGmoiA4PlYtHFFaE/jY9PCqkzPRlRAFoM28pbDcgVpH1LwcnKyjCSkISQcKP+hTlIOSz2Nbw+ikJGQoSGVPkrOHS6wo1OASEx17Y2+9ND004QxS6vrpApJxFm5FsQbHDgDLRtXKQYsXSOeSoxwuXEJzBVDZm8tLHs2/5p6TI7VCQI35Jc/MMqty7iM5bpk1KRJIUn8An7v2Nq/EHUVx4wkgxrwFMnaghtZmEXxyonBy3g4YO7yBg3X5kuSNOrksS7Z7clapiuJ78bpQbiHjdaHdQ04c4MyXrpEn4XLejuF697zs2qvaPpq26jXInp1U0DqwNY5rbAhsFf8OTitwi6yKfjeyMyTsi1PgpmbA30buDaK/jZK/rV3eeicOcOWb5GUBIsg3yctGRC3IZw2Yw6hv51fRXjvS6zCoSM5p1rf1cf3NQSvyWQOexqqHMJymN+UGJF7KyhVIOPqu3YFMHHrNdy/nC0hD3fV7kKwSLBBedPqANZpduwNJu0gbnisno4fvRU8eXMA+dO1OZMrkaJu+zycBNJYOmwcPTUFbgnMK7cS0FwxOctcAaBWccucxJUTNcukxG2WahO174khbrkckI9sWXEg10ragRIqRtsGVHiIRkrZF9ZqNthcuOpAmI3jLTQdv5NuCxnRG2go2Eyq5VwAd0AD5LJQOxLwVhRopxSqfl2B+dZQladt818ISzlEHS/2rg4tG9ZksBbAO1GABrKB4Ya44VVCu92NOlXo4WIpZ34JDmkXx7KQsq+J+SdpNcb8k7a64X452dIr7JWl7xf2StHWMIlx7lpaX2Rv5TYrbJWkr8AWWtuToSNqW4xWs68djKFORqnTOcJqqVJ01cklyZg1Rk5xZR9SCnlbu1MYy2a68h4/UzxeMTJKTg9LNikPigEchFWGvCWdOcm8sp4b76/ksp5JDIzm1NMA8eGKWuL04VLFpR7brXze+ISounxVQUnw+SzwrDpolbrix7s6tcEvPywM1ltMmpB4gp11x8CSnxXYWEa2mXqr1RDMf9JMOThNLVAIg5KksrTLzWRtdshLxUIjQUJTi4tkhTqtCDTWYsBdueo9/sv/cp37zfDt9e171L1siv9/8v1sqxiLFRb8BdyGOFlAg6xnypTgyA/HfdfVSHCmtD+Aat/QFPVBDa7zaS56XsxyacQW5gRl4eX3cfuWfN/f3Vpnbr9l90pSzxdElWxOQzJpCLSJqXdpX5UhWbnf2HUCOlB9s3r4NYknbYULlnKBbtMdfLLvJHoSypO1FnsJZSRQpvqOXnJIggtpmAu3ks0NXMkKQt+4Uaoi3bqjmUuAqOh4V96Db+bSSnbfAd8pS9Mz4kmKT0bmbpVHjgRo6w5TKK2FqSu0HPFJ73JyXHC7Wxd+3c3Tz/EONvLq9wJq7CCfRKXWN0XxFp2x20XxFU1WmfJaaspPFI02KNYS8ZT3ahRwORJrUeXp0UqRZEL9SpFkRNeVKNqTmFZQ5HKk3xJJlydrZCCp6eyzZzg6ed2WHPTTJroKfwXJVDhnxsItiLyBvUpwIebPEiRXOyfHWOd4SNhYjcQkkk1FjnqDVFctk8jYGBRKKuY0CCCc3UrBJOFqjiSsnjDRxBRZKE1dwoTRxBRhKE1eQoSxxC6bmEHqyxG13JJ1VK6NSrRNqZdQqY/PcJuH0KpN96rSLFjzvRYly2WVSFScGp9F2dbmaRXFQx6kR+evNw+v17eOPb3cPN6+PJ29hlN3d3+23Xp8f7//2bfOPmz/utl/Z/t3LTkIvH3/+67/fG5dfbfd399tY6/On75zcTImJX3Z609t+PN08z6z95et/zR/8nLqu+//8tv13VIJJqwFauEYyMXmjAN8NwwUFePf8+HD9dH/zullPjEGyfrQYo1WM4c9Yh09Pm+e1BakVPqYFma2CTJcX5MvrZnO/thy1JkW0HKtVjvXPkOOUt/223ff+93py1DwMLccu7IxKQI1glQAPU/NCDIOpKefOmFoUwogdtd+uvv5zG6VMa+iv+SpfbfdQ+ber+ceW5x+nT65y2/3cp5/T4efudn+++Jv556nI8PzQDoTmn6c6Y9PD9NnVVMN2epiovH9l97B/yfzh+9/tn9r+afr0neDuabqWMz9Nn15N99bnpx1Pb99rYfm7+Wm6JbF7Kksqu6e4+9786dV0LD8/hbz83e5p/4b508NfTv9fhTdx7t734WnKWe2eJipTKnR6mv/f/247TXevmx/bCf52/3Pz9Hz3MM3tH1vln6c2l9BT7zkll2IuW13bm4M56jx8ZbsGvm9ebp/vnnZL4mv48vTz+el+82V/+ffL1od92Vqbx4fvW/p3t2825+Xu94et0dh+f7/Onp4fv/+cjdLHe8OHV/tpbc0r9W6zI/L5zi2/aOPbhvqavOdkIF1tpA2qFouNtGGXFLuNtCF58V7qhiStoMRI0pbEhbORbkIeiiStpN1J0qYkvFFnLNdZ37NnLO0g5LdY2lFIb7G0k5Ddukb3Oy3J+WTUQlPDgQOnqONKlWwzLPUiUUOFWMyFShdahrAYWuvq60T2hgtesgkIhxJEbklAj16+8Josv7LI1FvBsm+vOCBBQSRigyNkO7btmqxjEzTVhHBEntNmnZYmcQoBTpLaO3ScLVHz6PjQakQWwRziMMhVBa/3RYPXXdSLtL61pC8epF7U/5qrPCrW9L9mS2TGIlpPrsJnrJKpR+LWK/dfk9VYoxavAsVKTrfsF1GC5BXLzpVCTTrUBM54ipINRtS0ABZNblZsMCoPb6nAv6AGrkIl3i/Gzyvu3L68yTVJ2Td0zeax/QMMhfgXrFMHsNmLrHNl8rN+0f2abCyRleItcFXnJFEDqzprXes+SffEwihycRgsgarvH8juD1kKVKGQuxBSk5wWJ3EKRFuknClqeFaCRA3g+0pUDDDVN62kgci6XCCoWFy7NUfBXKO8UgZ8DifUKhpurt1aaZIdREtVClLRUq1iuofsw2crkL8gXzijXYXWFddkE746kPwhWwnWgeTPRbS5ZslGo8VVFG9Ciq5KnAKlqlJeFvX8rlK6B/X8XtxjNSdoEIfND7iReIGFJ1x7dWcHGQdcE3d0lpTNBFVVs4m5H7YVeyuSG0GirgN7k0wpfNO8KFKqLjqmRPm97hS/xFXb7X7AaVxCd/tA7gctqC7lfiA1KfeD1k7Xcj/gFKNruR9w0tCl3A/VRKI3xdhRLRR6HwjxuQ4Yzon2lGwz4dTkD3lu6qWC9HDVeaeletBJtEsDDoBsVOHUDBDbqcKNpICgoEdyQGR7EKclgSDLXSKH1oah8nxq1qF7LQ+EOuh5LRGEWuh5KRPEtSX0I6kgd4E4wPs8YMbJQZeBmJ5riefVbBDZ99BrgSxcsVo+CK1YFf8TOWC7D2pGiO2ZGMKAvSX7PoaohPdkS9ARRNBl9DpoWSG0YjUUEF6xCgyInmkpMRRQc3QNCBRQV/E4kBrCRAdyQ6FeYv3FgeQQHmYUtjOB6yA/Ag0KXEt2FRsUyONQH6UEEVz5GhgIz94AGihw55U+ijmi0DhXmJQkUeBO8n0ayBJdRotHIEJwHWgYIbhKNZAQ5k7KFIWCyEmpolAROSVXFCp3W0BJFoXC0R7IFpHsZzFbFLhjUa9ChQJ5LuqzlC2CK08DBsGVlweyRYE7H/QqXujjFJ4S8UC2CAt6IFsUKikZKVuEWZayRXBtFCVbxA5dQw0FdItJgw0FdNVIwg0F8lLUQLYopEvEAyPIoZC5QQ9Ah1i5itmiwB0keg08hJeYlC2CCqDChz6O/oSRVQFEgeynLAGIAndi7UcQRIHs1jwCIbqMXmsYIrhiq5QtwitWyRbRk9GEOhtHllM7SrwLzYTotdqcxDrVmts3pRIwz3oQ6pHw1KO5OvNBiQHc4o/tG65/bH++N1Zo9k3pmcOPVemhw1Mvcl1jrM9NqRvHs9yE6qc8dYtGNyt1U4n+dlbQXQud4dV1LXRGR9Y9DmTCIdGRmNlfwrf2PJAJh8MsSq6Gg930OhDkB+4VTYzAWVhI12JmWGDBSeTQJXjnB3Ip5LV9J5ZZCIErs+CU89RA3uR3IxHyJbQ42Av8L0JRuA60OBmuUglfj7nTImOuU5DTImPEq9dC4UDx6r3c1QhPlud3sTlY9cdHKcKC0k32XjikKwh2ANLiFaQtNHUCaOenrkrkoHQ1vAJqkuc1vALq4xeckuDkOt0Fr0QxjqMdBvKIJPtRjGI43FUISaRP4q6CCSQUzq68oMEP4MobuKASOKxQCE2Mkjwr4j5w4oQEvcAQ2ZOUHKQtRC8FE2gyY1ByeCyvGqIAijdJsQkcepZiE0/FJqYC//780KvEq+N4bUrIw66BPpDzcyvn/EJyUgCGllDySgDGebEUJFbRCkpxIJ4jrbYF8pPbeelmiRyUgAT58ahJepKqWXrUwd2A8jnEc75xS6nrybf9K9YujOj0KJAcdPZ6usxzvexz0AJBz6EagwYVgitWKyIEV6yKCvKdHL1YUs+T5atCrkKqzHOI15CbHgv6Rr6j6+m4y+i1VpgILrHiheiUlZ4FcbTgFWlXiUrEh4eelIjv17EfjfhKlniFQy8Sr53jteoBpK9rB5ALDJH54BXPdVdCPUiuSkEunN3qlTAMcxckcpC7KIVhBZFLErmKyGX9LBXzWAbCuXwJs79AApnPUvEwFdy7p0DpofaB4JCC1ocm4t49CZoOTSr/DsXdJJg7XPlCxaCIJxEUFk9ihMgVmwtNqd/uC8l8GQjeLqLFrepnqXhZSQh5TE5CyMNVagL2+LPcWYA92eEVczQQssB8sj8/9CjxWjlek340iznOQp6SVUdL7aBF0ARXgoSlw0NvQqKRdFT2ikGLV5DdyZ0EoEPSjU4LSVHXdycB6HxG5JS7J566hhFdUhpj+YRYzUqMxbU0cwM3RlhpiDdGPHelITrpxgiWtoR+g+vMizdGPFnXMPoBPJzncP7RB/0gFgraD9wW8ZlkXLrfjCczK6kullfpNBLzKp1GeupuRvQSvM0njrgEb4PrzADCycE6acEPJL7SyomvGKTjSLiEDGV/stVHhjQQ0JBmywLRWYgDLiQJCYelKyHhMHdNCjoiIvepM8LL03b5AVMX9rRQk+IoIcAhayZ0zcHXQe5EsLfnKmVGE8Amf2CXWOMWvM3Cf7LUs9K9k6ZelP6dNHUJ0U1Tb0pHT5q65gLREk8SwptlNnmJWaTeJkyN+6SN52KLNHC70fu1/XVKAwdVcLI1rwfJaTkXOLua14PcNYkc5O6T1zufaTisDtTH73MHLkv2wnNtE73ONfmGYH1Dtb4hWt9QrG9I1jc06xuy9Q3d+gYb3MZ9WJxErPIZbWNovs6OoFnf4D+84ShN+0Fh+CSZs06uWLV4ESiS3TiLVY0Xo0CiKebOtIcQ9FNPzuebu3ujfytWpU7ZLDSrVqdkfoX9+mI96xVKsfJdzXyblbmYX2HW5nZeMl2nSbJdtRNFxHHVThQhOe0MEZmAqp0hQnIjp4aQqHRqSJruqkWwcHq0U0M49DaQCGPXe1cSeVzP7qadGsKu19qpIZJuC3Jo3BDJKJPsiKS98Mb7wqrDXrrZ8W/9rJCKko2E1KpCDUp7oKlz43Sia2E6Was6WtptRcg66An/KQplBhA+voMYwEBv506OIw6Mg7v9ELuhH1618p/lMAipUS8ySaRLXTplhAw2JfKBvHWFN9Rk3kkxY0PUBs4N28ppyOSUchrcMk5OqqYBJyEp1OAkDJTPaOTwixB5URfbkpMyqVCyUiIVSlbPowI4WTJ01TokUCmgefJ6/rQibnmVOgRThePWjJs5vIGUh4Rfg6LICjW4DMQMKFlIPhm7YbmPkj0XMSRvvpp0CHyggLseTHHA2/QZQ2MKpjggfwpez+JWchgD2dAyus9Kli5a1TpBSQ7tkKYFPQBFKzVIdxAhtapEZHC4EqQNUpMO8NFIFwAac7SY144Wo9cPrZG4ogRcg9SkmBMKXyqYAXmT6mVA3swlhg+xUUY0qxBoUWjzFJscaCXErR5pIgEkp2fj0rCXSF4P77hZsABsDgEZlFZUqKHpTEkLv7juEikNdGzNnHCLHsVwsNZk6GN1CPQySbsNBHrklYVkL3VzCMPisIJlpx/nomVrRuAcYiWkV2bIzYEk5FKqfgEZlIpfQGpStQs4UinQhNSqfuQJx6vUcyMNRJZKVSBOi9OzZKTVsbSpymeVsQQh58a5TlP9mLMqXqTIEg47y5FQRCSLTDIgklUPrvyw7bdXhjkEV3BEXUj1Ud0EkgWnsmjMDhg19pZyH3k979arFFcisQrNpNySJiHdga6MXPHs9BnXYgqnuPslqRYhHAwk/3WA/8CumybkxdgJ0MFkSI2ak0mitd6kGxSQmnSBAlKTgkYoPClohNTyQN3atfNirQgRHbmMxa5PSGwDkDPScDQpBEXzbMC7HDjlXGyX8GZIsl2qmwaHHfXsnkM0kxzSQZJZSBh6bnb0ANQjbqsQrjmO26an7kh5dCXEAhOXTZ2Z3FlqXrqAjKgF8aYLFTRlF/VzWMjyQDzJQZmzG4knHSmagQymJ4dR9QSgG90EZqfEm+wE6fEm0iuvx5topXop3oQMSvEmpKaV6EXUtAq9iJoeb67dJSH7ge6iUPZSmAmpNemiBKImNQ9FvAXt1gKi5uWk1qdtyN3zVB7y9c5aFzIHk798jzvIVjw5WCr49g9r/kxMk4OCNoMzoYDN4CIpQnwEiVX1dicca7Mnfkg3FrrKLBq+HcLyfhvxk4q8m7m//3x+uLm12k07fOU9CIBjs99m+Kh/51QkKj4RLZuouERITDm2g3JUTu0gMf3QDpIUzuzIiDgq+RI0KUlIl3ALMSkHdUicKchpKNKMJeW4DkpVOa2DY9fv3AVEstgTG5GbdeX6XURsNmljzx2G5KQkSJBEBxogcWnSnJVSZkiydsRIOEcxqhShSJO9WnskZWlrddSPLawTEXAu9tqfnHple6/OZlxmyr06uCiUa3WIWFFu1aHFVZQ6DJBYkPf6ce29fon2wINcGkW5UQdnU79QRyp5UWo5wCmu9jiJghbkotymg1JVMh9ozFUHN+eVUhU2HMp7rMKVA89VuHlHgb9yVZDOGc1DkmMLDlSXq5IKSYhd7dpdIp1rlZMjUL5NiKzg6OV0CKJoqZryzh4aa/NyeXZIMsjpmrxqukZoUWTTamN/IqM1almO7Ug1b0rZeLgslXIOkJgSdcIFqUSdiFjX79OVtWO7rl+ng8NTbtOhWezKZTrImZJDgZwpV+kgZ0WOi9pKcVGvUlxEtqLLluIq78QLEpeSZwHEinNScMHdKy8SLqUiVjVYCjlHxVIt5T0sgGJNatQCKWaBPSjKorIHKQq9orn79WWBGbHGQ23NeKi4bh8jVx2heCe3FkQzIjQn6ojpdPQFQYreyGogxUd70q9wjCchOIJizkJwBIkpASWyGFIXIkisyUd6kGS3Z9ZIdQpKh2c0KcHbU1WcBkk9g5A4Q5QTgKQhDkoECaWqRJBw7EU+0muIpIBV7tysK92COmJTK3fJFVksUbkEhyQavZx24yq+FUspk/cYCUk2ygdwkGIS2IPSzCp7kGKR/DlZOLUYapu8+3NOoWKTGG+kDnQ5jUQuW6lFEFpkUkcgtCSSUg4dcqYUQ4ecJTmN1FdOI5UkVFBnl4Zy5gZlJpy5UUWXS1LgxnCd6P2WucKoJSsIZCTVrNxiQ2PPQU6FfW6RpebCSo72yIcrWF9y0pDS3M2ikpVjN1QOv4gNfz72+znhELMC7ULV9kvWK6uTrQyKBX3yHr9A8dq7+oSzJBVIF5RokTFdmGSUTwsxzSSnxz6bjMH8WNEP3NglWIoO9+ZMVKlSMMmaqKKUusQLXil1CalJrXngupQ682BqOiTMr11uoNQonxviASpgMDyVSiNKzJvSfRnzphRPx7wpR2uop2WpXaEG0GOlKekTyFvTagj5wFmmppQQwkOPwv0tTE3JnGBBKkdpmLdiPxUi2/uWVnXfnlb17a0Jo4zkKLt8+AVnxdKmp8FZORohdK9FCGRNptIHrrRFbgTSnTakTl261AapKbfa8DJQrrVhavq9Njxe5WIbqVhdutkGOK1OL0ZJ2rvqlDtuaLqqE4pRchpUnXS7DUpWOVjDw85KDJMRtaJQS4haVcICyJtykoZ56wpviJqXYj80Ui9lNiBvyjkZ5i1q/pCrG1590rMKXNHeamqTc1ZjvHBbzVMVzqtX2m7gZSDlIiA1KReBhBiUMzFMTW/55tdu4lGD0PKNXclBQQzDKQ1JcKAU9L8GKUEB57fooUkmJStlLaBklUtqePgH1bt9fHh5vXl4vb59/PHt7uHm9fH0uc0OqLT91uvz4/3fvm3+cfPH3fYr27972cnj5ePPf/331lR/30xErr7+/e5+K93Pn+45eXndbO6vn+5vXicF+UUzppf+eLp5njn8y9f/mj/4+fC6JfGf37b/jg40Ou38iMQc1gVEhRPkwXNfUpCPDyuKMFiH6C4/xPmscuWlYotKvHmpaN1SePrZOk/x/6c6bTtmjWZBVqsg+5+k09ffnnen8ysJUoNB8YK0epn8JxjHm+9/3Dzcbn397d3z7c+719WkmUyuJpvtR9LvnnkAg63JatsPkdXlZmg3rMeH7cBWnyOTjT8Mlp4jEa7CIQtrypqLYsmL+BWWfNXsNktetGYs+a6pN0k+O21lHiP/29XXf253J5N6/XW7yc5X2yg1/3a1/zkefs5l/nn69VVzu5+3v77amoX3n/efTx9debf7wvS9t1/MP7/9YvrsqoXDzz7u/qotv757iLs/68vf7B72r58/vPJ7JmdK79/aP/W8fwof/nJ+6vuBpg+/2z21/dOO+Tcq81PY7o3mpzY/ubx88n75VNpelHFJZX4K9e0pL6nsnmqdn+ZP39+3f2offtfT7ml67+Evd09vf7l7evvL6W8Obwi72d/JbOb38L3d09v35qeY9k/1A5/T/1ex7cYwf/9Ac/dU99+bqB1+t3va/27+9CqWvHza05zfe/jL+SntF+38jcPv5qepM/P8VOe/zDs+Z2qH3+2eYlk+7Wds/purqbnc4WmqMr542r995uL9DbunqZrv7mlaBWm/znZP71Qm2ofv7Z7e3j59enjD/mn/l/M8vNMsHzgrHzib19lUm27WQvfhyZcFzd1T2csl78bw9pfz0+F3My/dL56mm4bz0/SNq6l8xeFpukYzPzW//MvdU9lxPVM7vGH3VHe/m7/x/rv908fftb5/msY+nafNT6Es3jD/f/jLGpd/OT9NsdP8NP3N4Xfz0+53W5N597r5sbWh3+5/bp6e7x4ms/vHNkaZrW4u28Xce07JpZjL1uLuo5Y42fLDV7bm+fvm5fb57mlnrb+GL//a3N8//vPLy+3dZht2fnnaPH/ZBkWPD9+39O9u30Kjl7vfH7ZBzfb7b07g9W6Kd67337t+utkG/of3+snIzz7kbrOj8MmhSEXDfaEgbxaMfzTStqQjg5G25dAsGWlbspPZSNtyJF2MtKUi4iRtS8qyG2lLBcZJ2paTuOJOEG/HiHsZoXM9D2V5tvD3+39N335+/Pb4ev3354ms6Whhca5nBdJcz3N2bJfl9SpAe6Lns+sDZ3zvUjy3CrIU8L+TP7tblO5unxB7lbonZHBNxdv7ToUTEj4+i8KF7mNL5KiT0ssGra9nwUsW5deRHrMolkvhxZ2Yo6PE44i5yiuLMY1YFu7Sesj2w/jr2TcSa1K7MPtO/qxJCebqtEvDwtVKCE21i1wNoNA1OwbqBkSnkQMpU3tHgqXlQjwGyQ5SxUtiHLGDKyuw5UJ7cdaRGmLw4q3Ei8Z5ZYxsNLjuEk9wfpS4IQwv5tXVR+IwCsOUnGSQuR7hXjXIXEnJFFT6ZDHWFEcMPtmiPqkGP5ODyJqJhs3VNXKo83sdCYQz2YJVsy5IAl0jh+otOs08JcY8WW7DL4lnirghNO7pvCCiRg4VxUwjsXVY1zXnPJIKgOXQR9wDV769juwJyEr2TTXj3FW6LIa86IqIUw02e+PIa/yiazJB5TeSFXlGLDh58y5JITx3/SqPhPAr2wmpqQOrzEVLR/8qxnb02qCUj87s3SkpI01SX9y0f3nazhFYWUvjydwOYIhO1uSkuali/gldR4paQBCYNWC5NL8kTi0wyx36ZXiABFE0cmia6kC0kfq6VqS2Ea/NdZSrXfXaZKPVpu1Mqe59zY9s7LjiKC1obhzUaWhRdeNcs/OmtYfOoBBEyyOZPES0DLjqtZWsVSkm4c52tX7R5OLvGnGwMLvWP5o0M91rYQVYQV30pohc1MghUYr+0zP+03KTf0mcAwxYErjJStySwM1W4pbkULUSt6SKipG4d5bMUTNTt6SOupm6QRGrN1M36GV1ZuoGNa3BTN2gpzWaqRsUtWYzdYOm1mSmblDVatcmg65WqyHwFtRTNeuqpR5BNeuqpT5BM2uTN+hqM1sCS3OJZtZVS6WCZtZVC4SpmXXVgmhqZl21FDNodm0y6GozWwJLsYNm1iYLWqmZLYEFrtTN2mSpZ9DNlsDS0KKf0tWjyNAg5o9A6O+DmEByiF4dOM1JnZOwetSSWNRlUNNCieuB4aOUFkocKDWO5IUSCcuM6oFMIns7+BilXE5CYNWo5YYShDDngSOjRGKYF5giJv+Oma1SBgILs0n5EsyfdjQC+UsaPh/TM6GAFnb9V31qhH2w9Mjop1bVUSeSNIwCnLyUNHpQ2HnkGKKsfP8hlQHUQ6pojCOYhFTJGxBtxBtT6D6fZF/JYX19VqEKqZIv8OoLyDv/PmunKAkAjH0WXSNajDmNuDIONO9zVo4aUuUu4gwdqqxtMnLVvBmcb9HbwvnuWjSA+CtOo4f4K9pdGHYlliChwGny2nkKlkbS2CWdRMkS+JsmXzTyrLA1XDxNvmnkWeF06cSJJW9pvlGSWTiWbhyLIy2a+6CRZ7mP0rEWTT5JR3K0cLLGPUu+aNyzwqnSsRxNvklnijT5rnFPyr5pJ6I0eS8dWtLkg3RqSZPXDkXZqbUAiKo9NLB0Cal2Z9iKdOpKy75q3LPkm3SqS5Pv0rEuS96CIKp2e2+BEFW7vbdAiqrdpFkgRtVu0iyQo2Y3aRbQUbObNAvsqNm11gI8anattUCPmqBWXTo+JskHC/qoFTt5r5EHG+3gzB3rWodpjqP1o2zFFpz52kz3xgRjcObkVA/2icpqfr/g/P6JIgwWBFOPxMIwdxHqmaBqzh938y4yOFMCuSeQ3z0hbM+ftvZszDwGe7GmXi+pkj6MHJ7EtYvajBR6Stzl8+CTegSR2RUkVXxJmVtBZeS8PpMyquohB9dSJ0iNX/b8H6WnXXhN4CJ1WOCh7Hc5IJcDTWAuoG1BKhKTqDoYIUTtEAJOSNLowakwX9ZZJg0hl8XYsHuZbINE+Vs3y+QaaQ4X+ChyTS6TVJ/W5P3jP6+/bx5eZq/0+vzz9vXns3lZdi1vgGbaUq+phvPTEc1KvEw/XEBg0dytszarOlvgVY2wrxZ4VSN0xFKqaUkPLpoysnWKq8dp0R6xe0JqfOfP7q2Bir2SUw9m62XrkdHDiUEQSKuQvLYRQ8vMhNyK5yfU1o5iuTsiy0MFW+2m5Ru4AlchmYGSy10YGd+mIu3xOFuZ6sgeb33bMYbrityYZVwXV3El2HBdyxeQJWjCAthl2bVRZUhCDiO7tkAWGlXvy3+chFMyElHRoCBFyFqhthQQvTICTYukmEW8FhSCiNeCQjDp4hLJwaqKBcG13DYhjosIDUESLWZtK9W8DOxFoJabPVKlP1eBYia02PW68Bmr6u2S4r3t8pyZ8zxFPGaGa7Fp9OBa5EuSLw96ObeygGyxW79qFXD15iVYm92mVPFMGc2jBbBV+/l5tCC0GuH6qnhMDMdbtB0wpFc1enC8beTwj1yqXdrPcrrW5K1mULaaTb5DFKUzxiZuRdF8W6BXS3poPTZ548mVzAwtjxxfkq6wlZHdLRk0tKHCbG7lY4YFUEu4EeXRcpA3nI5sGuBGds1c26vuR847uZpsoct3bz0pKXnb6cjYoIvbTnDvPHRx24kWYx+6T7S2wnWpSlvy3JId6eKTHLlku/n0tZ+dpei0qm2YHp8wyt1oGqKlWFRuZ5d8dOauHcXDJbrCqVVcALXYA9hIzInZiS+pklNT1PwK53qi04q/YaE0jR5cS+aTnaUQKDsTP6OwjIkPznVF74feQvqv6IN0gs85+GhHTS1f4siXpBGYwAXshzcDOKo/ryq+SIkwVohirgpy26TEGmfmvIjDQFbD3j+v5ouuoGDuvFXr+TkJYSQlx01NiCOID84AWwBXtRPTnzV6UM5lKC1JuuJgAkI2Z/cNoWl5QCgXPgfWvNnXRPOuuNnNpB1h1eJFLUU0d7VtRFi2wFSdnalsF6KIsEL6qyKs4OiHEFZubZREjHUkP83Z7djUnK5TcrrRUierx/NrILkRSBdpYlSMFVpoKYxcdoGikJFWZC+ImNJIPpq0EilLQCguhEhlBAi1voqnkbx4rGt3LlULU8bOrqA+kF6OXGnHmKXilLFzDVjVYluxcfGdWGsrguJ2MY+0z4ydFLmWDo8NMT3SuASLoihp6Ni4hVEHMu6rq7KI4MKi0+pbwgkubiD5+1laawTUhU+dL/KzpNEoWiUgLL2o0UOzW5KYP6YNf8kDCVpSA4u50OUi64hlI911Yn1VaQOQPdY6fwZ82XLKrOOqbiAfewmVtpT3qoT7MOHBwnktrnEg/XgRgSUFGEjawKpl27D0ykDGkbQoFsRZ7cQKaiMZQtrYVvNhdfPnmTe0AmzebAht4LLmzOapmbPgzZktbYsDecJLqHTTcm54EWg5N6jFbSTn9llgK2zI28itRjxK6VYjaVibllKDU2wpBLakhwbfVdjor+MnUKqxh4GMIGutuppri1yDjdiTkgUj3VrPKvdkA5LYR0ClrLHtI7caL2A7upw+q+SiUBGmkSz0ntwIxDRSBYeSk241xsIRH7nVGLmKT8lp5esjKJCdXFJzipWdVw1eGgvieORWY6ykmLVbjVjMYk4MCqEraEtSS7wbgA2y79ByXpwmejHnhWbPizkvNHteznlx1jr5rL6Atdb2wlvLtA5p7HwdSh6xFsq3Acgga1F8V7B0LPWglfWBKz6I+Su04g3VtarZlggAsGp+h5af4uyViAbD0i4aPbga6lDuiLUpYSxFRdrG0AdAW6w+RqemlFijZe9U2JzZAMeggLJoIUUtoYOWqQjygmpk71LYvdWuxCKlZzi7Yulc2CMh4KbRgwLuanqmCOmZJJfH+nUuGcBZSn4As8QqUQoj6Q7SDsj4rsg1qkspjYCR0roIhpTywCXdCMqbpVRGEhxUta001BoxZnI1yMmmRK6GriYluLJqKTstJwEqzaXsNXpoqQgFssKJpXJ8GnMcQQ2trXM5SQApqvpiEjBdnZiloiV14CoSk06QvyYliThLs0BlCSiqtPpxYypu4AotlGHxI7kwTpRCga5k1QAVtoXWqqmxYibkLGesSJ9SykiShzSpImCL9LulDaXDyKKmaRCyRbrgMcjWBexH9QNXaOG6rkFK+5HrzVTWKxDcJo0eshI1S2k/zmzWMoJhu8QKqgNXaPGctJHsJinKPgJo4zyQpTVj7efXlqkXIxHNtTCUfSTdUIsj2UfSLLQkweVIN9SymtskXUMr6gtYF2evCdbiRU2HvSxYI4Kq1qX0LbnKutb/DSp01xq+wdH3kYZvnyd5HKOT+kjDN9KQW2qDdWL7Y6kN1iMxx2UEIUcaqF7VPG+S8ry9DdypxaJSe7tFsjNXtiOuerJaiWyAXPVsjCmyvadjrxdU8WxBZy2Tu4EbrUG5l1lXUEQ0W5BZS3oR0SsSui5yg69aihUyq/Vcw8LsI+g/rmBq9iON2KAovNfyjpCeVq0PitaPVOuLfvVoLfskgde4he6zllmD0isaPTi7dSRbyVk639RsIFnjP/s+cmETySYM1emLXG3mHPwI9o40NUGq0hcDST2OZP8uoNJBzHzBlZA1ekiLw1Cy6xICqxIgjrOBljJglYhMTF0UicgpuqFcEWuk7Bivag4qhWpe/rzALdW8vNl6xDSCfSMNYJTTXKQZF2p+xYuqdNSaXOBF0DR6UOv6SELHr77bS27kwiYaZfISIpAzrGKLRcys1tcCLhmhzFcwm4+U1fxQFGCHORU1kUN2C8qpqm/g+g1me9PEns0GN3UpU8S5uexGMkXr2w4LYiwtFAdU4MuW0l3pFzdyVnqWvFYyU7fktbKZuiXLVc3UDbvrJWSVpG6v0XcYQThyl3mxiN991ebh94naz4e7V+sitjez6cRS7loSFZS8zEVtlhr9MQGeN8dFrtN36oXYOhdbTxv3+X3EiOyF/NzHiSbsvwVStkxrepJ81sijZVpE9CdcpiL6E/KnoT85w1T6CCySe0d1UpbVccS1Jqtw9qp45RjNXo1qBpRr9pGrfAeZrOWeP4O/jMlQ1jbVoZvIpG2qdQQ9Slqo2iSsIEtd62ABV3wTrxyjFd+8hBXkbEkLUraSsyVt6P4xOQCtAQWePfHKMZy9oQYUrNFqYxeRWcvV2ghIj9RHW8/GJkRt9qaNzR61dS9hzEgh9aClENEy7eKVY6RGllpZ3mpX+tD9Y86u9KIl8KBAxCvHcMLUJhG/jr9ROiNfSXZCbrAIEKxsVdHihu4he/IlQc1Bcs2HiglbFT9mQY7SSxq9hugdtPVpyrCczF1hroqFCuRl5BpwoGo/FsdHq0vijSNuqfnuz4vVO40eErD3YsolcEUYi1dzOoGsk1gWqCoWS0ZogdeSOJielrXBC6EM3ATGVLXcDR61Vi4O8yeViyN1NYz0U9i/Y81z7GJvZVgIf2FvZViiWZTaLV3Ms3ZLF67LoN7SDVyl7BLKALiQdFxhqKoca8BDU/Bzgas/W+xFrJYv4SoNlziEZqQdkb3BYekXtR92SFQlQhADJKp6+1xp+EWo6VHDL+LRFyW7R5rNWAfAkRdZQW3gJjCWYR/IM5KiTNotXbiOknZLF8rAXu6qNquDSHEky8i6upTE/B9tWA3tDJs3uyB7OatmN2tJ7TjMuukFsskOwryE6Uh94CYwVBtDX8KWzbOUtZu70GhkLeuLRx8HgKOfJ3kc/FVyGkjskoY8azd38ZxoiWI8J3UA6cnaqKxmj38VMpM9LrkP3ASGoi9OAUaSzs4GVuoJWNgTQrGXt+rJbIJKHMB3XkDFi5hdLmgNZI1eRfRMeWZIpVqowLG1EZRjuTDKsZSRxsGBqtRbqpifRhNjgTct6aEpqmEAABi4UrbFhnlavoCrMluqmJyGUuYD7BxPiOP4kjBdG1iyS9ZbL3ZQU44n9e7oS8zKnfMp7VlXtxegqMmAXb8+Xu/kfIyvemIK2zHqC4gUMI+5nte9pl3Ph6u2adfzMX8j1/NDXn8L1aTr+aRaNu16Pp4N7Xo+no2qpujJzgPFjo5avoXzh23kej6UtR0Qtcxnk17sMyDKmDUnXVmXruezRruPXM+/hEp3Mb2NtKSL6W24skau519EYNL1fNIGdu16Ppaedj0fzW51Q9fzWUNY3cj1fM4QVjdyPR8JvDrpej5pPaobuZ5Pmtnq1Ov5pIWtbuR6/gVUujrtej5eBNr1fKx1I9fzPwtsPAVT/cj1fDhKL13P5wxr9dr1fDjFXruejwef1HxqFdCx1eeRHDFprbx6PT9wDceqvWBWz2Zz6JuUI+ackFdLUbKpiBpGrudfwHYE7Xp+AHVUa9Cu54eE6EVL4hVSSRYqcGx5JH0bL5y+raEMXFLHoqsS+pkqa1ot5a+W2VvIrIimRjNu6264TNSSpWmrvfLV8i1cadpq6G6Y4wnqR+cwRjV9y1WSr/YiWMuXZFJEeSR7Gy+bva2xWPKrSDtitVCBOiFCtiFXXaOH+EtOgoBzBiuNdEli3xGkrC6nrUkEXkNpi8BrtBqSDLzmei5UW5Gq5QvIngvV3ppwmRYlTXoaaeXNGsU01CCJ9oEGzFb15kFkrcM3XKEWzFYN5zUoRwkwzNkSOwCrVvM7spSB5exV1jp8Y2lXjR5cDUOtvGmbkvvQa0jbWEbu0bOWy95osNmV3lYpqgmBe4kS0JTlX+vwDZe9BVXVyvllb28y2L3Vrhh6DHZvtStF6/CNBdw1ekjAVW3hHZKSgKxefV1W8KO1DkElSSWqajNvdmda00jCk7SXVQREBrSyikYvInomaCTkqlmoQF66lKyiKqvW5kbgkZF7hwhnRAIxQaD8+WlqMnKRK8BbW1JfQNYQri2PlAOAgpFBjJHlewjEyJUmrnbI03IogXxJt+ShkMS7CXOIFKT7kTIJkKqIPIRjjRo9yF+ScmScnex5BCYZ1scT9DJSJgHKsI6kAklRNi27BtdR1+gBGTTn1GQa1zqi2ZFHy5dQPre5MJJK42xec3EolUY6t+bS0GsiOStZwmRGUlRlBJO5vv1oro6USYC6IxVBpdebVgQVWY7mtSKocPReKoLKmc3mwwhI9QIryF6CqlZChkPJXVKUWvlUzLOYz4XrcqhQKuuGfBsBwHJuyKtlUmnnEJz6BtIvBC+hbUm/YK9L1ex2096vr8WLmo4FdEkok4DUMGQpe80KsWjZZsitCAhGRiO0EQBvWBuE1+xFrrq3GvLotAQ1kmH0Gj00xzGMQGBJE2LDKvVTqQ0mzd1iGimTAEWfR5LnpA5HGS1MJrRarBKSl/OmsY3gbNdXcQvKaZl1B+Wnm6V81ZKeQ/S8Jf8OqQQLFTi2OIKzdRfG2TZ7677lOQBVEb2lrOXt4cQUjR6cojoCW+UqbbfU1LMArtJ2S11N2pMNFlp2I0l7rux5y16C91J181sOqoy4VhfNXrMq51PqtK6y52Q5ZUDql7OFClK6rDXiwlyJxZwhf20g8e/7+nun3CUkLacYxWm5dDQbRWvUBWfDXo1qmTrn3FRRm3cFsrVLK2mkPgKUTR6B6JLuqxQpS04a/TJW3Jn0kPaKVYtc/CVUuoh5baR1Vcxro5VV/UDq+RICq1JDMNIG1qhlc+FsaM2/8Gzkoewwa6Tsnflqs5raWkfqI0ABNTUlTBoQAyKrebMRbEOAZdKONz+QEr6ESjexaixaBE3rFQa1eIHhsqdXPwtshdyLHfHViS11KxI8mTOsTesuhpkV4c5wyfSRbC2p3V3GQHsBA926JaOdzsu8hxF0MGmcuoxxJrfnXavv6huSigZn9h3Rs9R3xVxZQMyYl5H6rr5eOnHZ+0CBACS67pyCufZU0ebuNDw0mqHuNDw0HvxIv3jPlXzuTsVEe7JydbfVmFok+TzXA6K7oqQofeMWSR0ALftOTsJIeddfdXvdNGV3Fkg11A5vgVRDnfBaGVfMlQamxvxFBfxMGiwvlWQlF7q9TFSJ5gFoZVqxtKtGD66GJqYcPdlNptuAWMs3cK1Yehipzso6jeAHUM2sUQxhJAlJu6cgdRSjB6GVXIUrPmglV+GKD1JHMVLdQx3AkLLvaEoKkrSJQSupCqUdtb5gcDVEP5KCpI1WDEOvIS1XjAMQTFYf40hVVdY8RrWqKm20DI0AW7YLSYNE4mWq1UjFatSV7Bip88kN4CVJo5U0fCMUSLJUPA0nJNKOUtfqn8LlkNT6p79KlwFK9nS+p/xiBgviWrvajulVjV5F9BrfhCOFj/wRNiF1SxILMZmdgcl0gsmjapUtOEM4MTkMQPB85TiNUl6LFEPS8lBQIBpeEC8CC9TIEfxVNYXF1R7uuQ3c6sds9wH4nucqGnd71aVstw3FW1I7aFmUYKGCpFriwJ17zFvS0kSQXtbowVEXKe3E2ZNSR6B3ZfUz6l7awJ17PCd9JAHGibJquD7Ic9VwfXAd1aCmp7h+EL3GAeAg6VztlZNKNdu8Kl1TZ812LUO5L9Kv1SGYnyfL0vc6hPO7gP2ofeDOPdTFJlUaZddb0yqNYm61SqPQcjSp0ihpNu2gn5ovuoLsqJ9KRECtjORLSVFqNUrxvGtdrLAMhoqRsm7I3sOuNqsb6tKFddZDdLUIKesc+lA6lrRqPamjYJ2PvWBUixc1HfaCUY0IBA2d6lq2T5OYwIXcdo0eMELeOe0COmJwS1DM0GIOgyHztVCkBAlGS1YzQzIiBA8TFDF4eKBFS2xyhVy39C2J2MQw3DSCVOXiLXnLbe9sJu/NTaTSQkPjR4Mpg462fFiaRxX7MC29pKqdvDkNlRqxtLxFW5uda4vudjv5MpJZT6Q+W0BBmTGRvmn5akxQ6ySFl4W98VtOl9DZ4A2N4IN5/QRDq6lwYuEA6tHAfLT7mWC57Y0XT8gGNu12MWj3wE+sTe0i+AkBDN0Ej6tH9FuOpKvg7IxEMWcMZySKSWM4I1HOGpMNMbavGMobkxYgjtwHPyGekQvhtHmJ0o1w2qvGsVwx1/Rg+5qhXPEllDtql8Kx+iXtVjheX2noWvglZJake+GsQUzaxfATM6LdDD8xI3kkvUhaq1SGMqW06U0jl8NPyKhJ6VHWXiW14iltqvLI/XDarOehC+KXUO6s3RDHKyFrV8SxPlsAUJ1JQVkQUJ1JkmURTBggQRFNGCFBMYmFCXaNIBxyMdwNbR/pEda1mJpWLfMUgTWs9iJKy3FEchxRS17AeTRBoRwzj7b7ob/s5RhJmxNPy9cE0lQXs6NcZimwfEba5vjIMq91SsbrxAJ1yo2QQ/USxo3Ukyo1RmatiQB7ivYhaO2ST0g8awTxmlD7I/NGtVb1FZGM++pId2RaH+tQe2TeNLah+6KsaWxewkaxwlLBTHDlW6oW1UCs/JYkeBSp+S2PAIfYlxRpU09aSBWXhCUuApPwmhhDJtEWrLuh97BmrI+0SqY1016nqDm7ebEVKmpOsJOGrnYtC3LSeijj1dq1NhlYn7pWNewEQa1s2Ikha2XwPaixtf2FVgffe0jQa3tgzGEYAWu4tQ5+vYvawLCkRurge66+2fYtWd3kcxUqt39XRvb4VPXO7Z9VbUuOl1VTt+SelUvXWIYLxjuVZbLc/vYVXoIfeG4S7X3lcrqEKvs4km5wpOb5NHJND68C8V4d1AQvwiEwh1XKYpCWwA9hI9z6pwXe95G7elCMQpmjaJZmEIEScDUFGSjB+pswhJMgTVUQE014NvNQsoN1OmHsVh3tKEKVoBhs1BKGElCshV6AmgQkxiVMyQIIJVzbg4svarkpVo4xSJkf0kRFMVGFpSEWLIM2L+YRdMpF1lEZubyHJTdU7Yyd7zaUHGLdSBQLn0HhJLHyGVxWyY9AbEhHZ8AxNW835ElOW7Eez95OrgkmLsn1zmiXmsoIDOYSVkSARTGhkAUWlYWpEm/eQX6z0whCxc7izTvMYdAIYg6jdJXPdaba2pZ80sg3yK92I+8EQQ295DokqF3BO0FQQy+dGHIfSLS6ulp2priBe2V4eDLayXXWgpegwLVc5zx1iQP5YtdI61nSAI7IdfYtKiDKNTIsKFoFNqxvRctAn1iQTcm1ukaulj6Qa11Rm0WMFBZb1crj44mtYSCh+FlSq8RdNSpALdaOiBiqEzOSxZQfb1mrVlX/xKTXgSQiq4O1DVy2OsH7EG6KtqCGYk9LtllH0/wAKot2NC0MpPguotwi7gqrX9PSWXh9tZF01mVkJuGyWIMo4rJOzIiGyzoxI30gE8RaqzFQFm/LF6gs+2UrLCO5WhRtEIVyUc5usSwoLG83u0PFoi6i3CKM68RK0Gr7Y30WYVwnCHaNIBpyEGFcrkKCXiNYIMGgpSswhxoe6wSHSU0QcOXmtm/IA0gpR5Xk276kSEmIQlKvqpDIanbbV2i1aE6sFA2IhVeKDMT6uFJOCcH7kTQMV/Nu+5YwcJ3rhHxG8FWussxrBctPsK0hq/DC81LJclbRDTCrEs2K7tsA+ogeQte29VDiQSskg9dE8Gpug7Z3MmKK9jsCYqra9TGkobQEbRrDSK0Z2jRausZ5QVhV27Tjhdo0gliVugLqYTU/ugEkCf0SL6UNSAsZg7bLhxKPWtEXvCZiGtrRs+Yl5qHX0IYylgGkB62Zsap5BNqCxTaSSGAtmKGFXMt2OSUNFYGXv6VjXCvE8k8aKuIEh1qXuBMcapWJXYYERRxEggSLtsvGBEUcBB5yG4EtpLUOOkPqI8fzZK2kkJ26/yZrPoXsR5IUXGGvYAEsLbfkcFllrQYMXlY5qXv8zApaxkAk1tHkMgICWE83cpWgDplcTCPVY1xiNa8PXOfC66yI+AioCUXER2AOg5TFIC3BAtUkoC/S+ucRoaSB61wnxJhHEiqsNEWcBOa6agTx8mxqtoN1YEKTu2S2OdUNJTtoC26oCLXM2bDhRA1Dw2BdXR1KQLEWuqYRrMclTEnNA9e5sFJWLTdFy1HMTUGdr2JuCgtAy02RRrS5EfzLJdZR8wPXubAYWxhJwrHSFLNacDU1rZTxCTGMlDJmHUYbKmVMO78mZ69ol9Skqsa0S2pqVWPaG9k74zXBivaRqsYXsSI9DFznwurTo5RnpOWYtLQg5lerQ4UNkgXA1Jmkm1iH6sSQm5YWDJCgVofKoUpZ0QRgSgxBrQ4VHHIcqkPl/Fq5lOhG2m6dGJ6MfmLry0UB/tQ/ck7Yiyjin7gKkVGsQ3VinYpoJzyRfQQ5RBbzizoEKnBeOmqlqBxXizMOlaJaUZu9dtWHXK1evOoDV6vXyiXj1WopPlUYM21pjVcYR+KHLvFgsn0ExcKqafiUpjovknpCldrxd/ihHBJrDz53xjs/FMF5hGh9SRNekowvqV54Sba+xAkvKdaX2C3150pT598R7e9o1ndk+zu69R3J/I7oJMAT6U0+w6nOj6DYR2DV8lrt7xAzUtCWRzEjBZ1YNCsvE+LHMkAVD36kd9YJskMYKdY/RjnZxLqtpLVtx4JJWvEYvCwsMKnlXt5DglEj6CDBpO3lMYdZI4g5HKmB7LhSXTHJd288u1ibtHd2JP9dar2NpW5vT7fciJL1pKKlWtNyhw5Xnwp+wnKII9d4MNk0gqvxrHjFLSVmW9xSYoLilhIvgKYNGRPsA9s8dqKKeS9ZCNaLH9gMwSn7jFl6ebq/ewWBcDjPYxzYgnhuF13SwFYKyyEPcM4ayCIcbabPryHyx6UO7KDoVS7WbsBToNUZxavRUlGpMe7DUlGpMQ6uisB7zKEIvMccSgUIe+N0uUoo/N4gt1Ixwt4hPVsgmT6Nn1DVKhUnPMGxJXSsH+gRgWmzHD4WvBoAdS/xDleDpRPcIYzGsrUAdA5RfycLjkQLXGdBnp06y51tj6kj5qUqgidkbTk+JCyDpdJQjvbhWyonBDP5Lt3WxtLtXgnUsXR7kPjD9KLEHx6vfpBwgsmsE8WcFjkOZS1Br3zIH88KQT8QYIOErp8HkCJJzumj4Co5J+cHYv9OVt5KTrpqDZdjctIJAFwuySUlgj7BX5boYf4sJbaieZlViTrm1uDUml0pLOXhs5W6l25F09QtO7Vqpm7QstbM1A0617qZukEDuzdTN+hjd2bqFvxoMFOXwKTYNi3wMJatc4X0JCgpphecjtPs+SOwaxqgEdGVbBWDUv4wok9RM7PXTrb6QYvddiG9b5Aq7XWykEQK5vuWi10yXgaZP8oqmOfjUc8C92I6iTs5x6dmoJrXdEdr+u758eH6983N8/U//7HZ3JuXt3JESMtVqtRHr7TopGQBTd5Lu2VUHSRZCgwtNveYXpT4o4efJHahBscs7ZYxPelu9Al60rHgiemRTgVP0OvmMzA8WFNzM3+eOQuKpRJrOxkO/NLZwUol2k8wl/R9OGk5U9azCZjvovNNVqlKSSq+fmLupPO7EzLo0lYc8pel0zvMnwWd0girawGnNEIxsxY8ZkhPwoL1BOkdFOeEzcjxLJ0ieT88zio5a0xPrLvRM3nmlxYglBOSXFBOzPa1aGcEUA5FaniN570EyTFi/kwNMxcU2fvbqZhu+i2cL/8GU2WrhQfl31Ck8AFLXSp5cYKe5oXwKpNAJJg/DUNygp4EIcHjrZoXwvxFiR7mT8OPcDeqkr1szCKNFCHPUinHHiA9qZLjCf6ahJMg7yolQ82YRUIocjMmIkhY3ht/F3YhGZZ3pWslTVwDl9CCSRIWhiZvSCJ2s2jMPdoXKS+oRU2LGzG9ZoqPobUwQUkiluXxKNGCJMnJTN2S2Mtm6pY0XzFTtyT9qpm6JefXzdSlhhw0dUs+0JmpW7KD3kzdkiu0a5OlLUcwUs/OiTtR8spddtoWj2XfAgo74eoBdQtErJqpJ4k6K5ksSYalblHXZpZMlaizvFvUtZupd4k6KRmvZf5Z6pZzAGemHiTqpNwtiJbqzdSltq60ZLKUQGGpa+kZVjJasoalbkndJLNkukSd5N3S/qqaPV/wEnVSMsGiq2bfZMGwVLNvCkmizkomS5JhqVt01ez5gna8h7aj2dTmyhwFBC3NSlKPWtIVbalz1JKuULZRS7pielrSFY93kXT9+ePpdKrVAxr21OqBMw850y7oOXLdaIlWzK12Oc9BehYEZ8ajP56EyxboySILB4dvgZ4s6MHhW+qnLDJumD8NpoX5S9S57FJ1iEVpKaGyyJ6QS97Sdqp8lClDvUrZE5Z6k3hnJdMl3knqFnRKIUxN1m7ksdxq9/NY6lFKZ2BZJIke1Gtb/6jFBpSsBpQtkJYFecxwFWEBNMNNRDbQL+jSvhZKxAJuqYSpLxoYDC7ZokWEmL+oHJu3DukdVOr28eHl9ebh9fr28ce3u4eb18fn00TbMSj+lsrr8+P9375t/nHzx92WxPZ7L7s/ePn481//vV0o3zcT0auvf7+733rVz5/u19Pf73/eTQN8K6X089s22txyuv3oF8j9xMGPp5vnmf2/fP2v+YOf27/9i//Pb9t/QAzZKob4J4phz9m3myny+NeKo7ZdwogflhODMspFCrxPLNdmnaf858/Tbj/0+LDdEd3ePd/+vFtzoXbtbhQ/ZQtgEyni/ueLeL6C83R/87pZT7TVa1eSDKINRtEeNid/nmhfXjeb+9Vla8JkLobNy9bqyA5bqj9PtlupvrxuzcK3m+cVZWuKYhfD5mVbjLKt/s+X7e3j09PmefWFW7UtgkG4VpdWw/8xwu3Wocf/U4benLaT49dV89pWzvAGqztr/xum7+n58Xbz8jLd9t13F1lrBk0urSnylSDSjbvvllsWg/9KbvVbEUNV+gViNWf+BU2MWugXdNF1sy/oTnRf9Au8aMfoFwTRjNEvUPX42At+u/r6z63iTbbor1uLlq+iv8q/Xe1+3mrc9PP00VXe/Tz99/b5/HMIbn6YPrvyqey+Pf3//qvdU9xTCK5Ov4t18TQVyZufpm9cTe0mF0+975+mN0xNyxZPfk8zzlRiWD6l/dNE7fD2+WlCOM1PE+0Dzd3T/i/nT6+mSreHp/ThdxOyYyefmZfgl09v35ufposT89P0N1dTacvD03SRZn6KYfm73dNeLruntJfLPLLD7+an6chsfponZbobvHh643ri6Wq6Xrd4env79N6rvJfgTPtqgpxOTzO1d5ntnoqPu6fdG/Y0d0/vfzl9+i6l3VPxZfnU9r+rfiGl3dP79+anEve8TH/zzufuqXx4qm7/tJvp+OFpL6XdU0n7N/QPv5uf6n4M81iupjTz4eltDDOHV2U/7/un/fvm975zPdO+Krnv9aYtJLh7qmFHc/70/Q27p7rXt/nT9/fN/79LcPdU+/J3rezWdfnAy/7p7XvzU9vzMv/NuwR3T83tZmWW1uF3u6e9lHZPLezflz/8bn5qcf+7Nv+ul8XT2xtm2ldtvwrm71+1/dhn+bxLYvfU9pZh/vR97Lunvp+x+dP3983/v8tl99RLXDx5t2d0ZupdMPunsvxd3zMz/80727unvlfj3ZN3af/LSUKHP909vZGZn/qe01leh9+V+XelLZ/eXlE/MDPbsLfR7568249i/vh9wLsn78qOm/nj93fM/x+ksX/0/uNj3f/xbDzeWNg9Hb66e/RxN7C+cxRvEul7qX989PvHHecHHt+e/d7e7F4y8dU/Pse330+Ets/7tbEjdBjH23Pwu1W9+8WC3v457Cd+94vDwN+eQ+4fnqcOcrvniZHD4N+f68ffT92+l8+L75cP/O+fpy7zy+e496Y7wS3/fvc89QHePRf3cby756nD6O65to/j3T+/v29WpwO/M6HF+PfPU3uK3XPuH+jNPyzGNxNe0ts9H37f/IfxzQNZPM+ML943/3A1F5j68Nze4pJZyebrlrvn3fsOv989T5ih/Ns2Nrp73fyYDjLuf26enu/mA5w/tju3Ob7KJfTUe07JpZjLNrTa7+Xms+XDV7aB2PfNy+3z3dMuLvta3Jfnzfcv//P//r+25O5u3/aHL3e/P2w3d9s/f6v79PP18cfN9KXrl9u7zcPt5vrp5va/vx7e5Kc3/fK9TwcXhz8PU7g3x5N3m907PweXyl2BTB2uBwVsz5GOChaeI50UMDlHOisn7RxpCYrNkZZw2BzppkCNOdISApsjbborcUJnjuY8vIIxJvkOCqqWpC3V2iVpS3V3SdqWGrxGnbTcj2hGzfFSNV6StlSZl6Qt1eUl/Y1UlZekLdXkJWlLFXlJ2lI9XpJ2UurlkrSzUumXpC1V4iVpS3V4SdoGvexGvbTciehGvbTciOhGvbTcjuhGvbTclOjWANbS68iol4YSncEZ9dJQrjM4o14a7lcEZ9RLw+2K4Ix6abhpEZxRLw23LoIz6qXhykVwRr1M0r4yUdXOF1cxTpRqOez7EuhBYLmCcdigkjwmZYdK0s7M+A+bUzj+omx1SR6rstclaTdls0vS7spul6O9uHZxat7SuXlbXLc4RSefpROU7Tc51qjsv0naSdl/k7SlW7hQwoWaqY/6f4xOVXbukFo7VWfen+awfqwzjxKWpnrziwsXJEOH7fJFGCqUprZwTtKF0tSWz9IJZgHlywoomhlql2UoUZI+qxuF8q3dn6VTrAJa0LyIgKqZoXRZhhol6XRW0p2iU8/Rqc4soHpRAS2w/hxDi83cZRhi4u4lE0jSkaITz9JJZgHFywoomxkql2WoUJIuZyVtNh6LPU1ZsTNNpYxG/WxKz5UfqFrUX5gTnSbd/kwUQrZ5cySXLjIvTSrrk0A/AUs52frRCB+jRoUGtRjXTJNqa6VEnYsWac1wtKXz3JSp9Sgd6JJ8Sye6HO0unegmUDjcUkh2QQ2UNbcUjl0sYm7c0qktSTsZ975o/NIJLcljUU6WSdrSCS1JuyknyyTtbtz7onL8zilHvRyT3lL9tSUr8WDctkMRROXUmOUyKcfdLPGsnBuzxIty4M0Sr8ZMAJy8phxBs1x25eycJO7/v+qubdVtGAh+UcFaybp8Rz+gpIdDG0gItFDoQ/+9ieNjmcSyZ6bOQ99MgifK3rXa1XZkEqNFAqYaqXh2laYcw6PgXjnPRsGDchCPgvdkXqTJvKgcjaOrTMqZPgqeyZROkwRFOWUHV8mUGxXWihH1RrNzdhTclAIBFNyTWaIW8ywoR/boKnul1gAFj2SCq0mCpJz+o6uUyhZQ8KLUFoDgviPTWgN91dr+uF3bv1nXf7p8Ow63ajSr+vcr05/+NzShhnDCXWaAvbBiKMkQBOCAAPcCKSBgqsl8gn4mxnarMOGVJ/ODZRoJ4NACXsyjES56MnHgsOpOkBQQWtFHKF08i4p/ng+n0+bNxV2arXy9Mp+RvtSWvrWRjeRtG9PPxYWf+18u5RJ0rkCiEAXkDCGvnufYmuqVHU8NZnH+1uC1Scoz2WUAAxeyxWATuLRWvGhRzPHIBUNWXDwkoExzwYQMCagFVkCde4GAznYJoDH+UEPXuG2V6T2Y9h3OQTRLCjTUlcZ0HlQSYFe/G6Gr/QZ1mU6DSSAx6jKNBhUaoq7HR3NOUt6kgCcl1tkWYsD5M7EeG73pe0ViofG6PsoezvkHC1L/MGE6Zg0HsAtyRrYbkBGiawzx8IX3PSCLg6SREIuDk33EI4uflkYwOpguaQ8lGMtZAm41XhC7gLEyCFISyIYGQkiwZEFUoKFdfUi6/L2A8Vkw05FsiWCDoMaWlJk/Ue0+lKdgRlFUaGhn3pugWpFslsA1K0JKy/RKVPnHSC1pLUbqiEdEniRIYgOkTWkmgmMXODoUBRriXuwEewHtkaOkgtCGk5lUUaGhHed6R8O6Gy+7W/MYBFuDcaeXo8e82eqAWy8sdcGMZqgmBhOlrEBjolT0wGB/UUqdYEsx9iSnmCeIPckUaIg9yQtGxKAkQQoKNJQkWO8tWLVPZvsLlRJWgzRUdB6kYZYV8xU0VJw7RkOm56BCd2TLARw3GJTXyKbuM8z/ex9BVUfodDtLmg7lNWaNBbDvBykseGrD8jxZ0lq/d1NBhcZIXXjfCBJk1lJA7jNa0lwUb4uRuCjeFiNx8YK96MkGA0IFoaxRURLTBmWNip6YHte+pw8qQpYa5I6cpbZWW42QpX5ea6NSRElTY7JEtSpU7IBhmx7R7C9N834H3J6iLAqKjQJZ1CvYIIuUKg5DK5yUM1/Dpq8w/Q8VGytyYtofpnoylChU3VfPgiuVXzA4k99KLLhSrQGDM864sOCMenYsOKGf1Xii4IR+Olb5mXtanbHg0u4UBDdpfwrWTyrpZ1vIHD3PyfF1Ts44WeM+kmac0XK7d74fJ7TkYZhKfR4/H4ZmxL4+53F2SKqfD8/lY5LGMGVhnBZRn29f35/Vqva0VA//6evlcvP5p8OVYNcvPt9DgdfcWb9VE2+Lb52P1zDk8ON36y2/+Nbb9/fz8e1war0VbtQ4XFn/6/3L+FG3QsU/fwHwHHm5 \ No newline at end of file diff --git a/cdn/factorio_blueprints/red_circuits.txt b/cdn/factorio_blueprints/red_circuits similarity index 100% rename from cdn/factorio_blueprints/red_circuits.txt rename to cdn/factorio_blueprints/red_circuits From 75fe6138c07f77ab7e936fdcc5afe7cfedde70f4 Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Fri, 15 Nov 2024 16:06:45 -0600 Subject: [PATCH 23/24] add .txt extension so bps can be opened in browser --- cdn/factorio_blueprints/{nauvis_science => nauvis_science.txt} | 0 cdn/factorio_blueprints/{red_circuits => red_circuits.txt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename cdn/factorio_blueprints/{nauvis_science => nauvis_science.txt} (100%) rename cdn/factorio_blueprints/{red_circuits => red_circuits.txt} (100%) diff --git a/cdn/factorio_blueprints/nauvis_science b/cdn/factorio_blueprints/nauvis_science.txt similarity index 100% rename from cdn/factorio_blueprints/nauvis_science rename to cdn/factorio_blueprints/nauvis_science.txt diff --git a/cdn/factorio_blueprints/red_circuits b/cdn/factorio_blueprints/red_circuits.txt similarity index 100% rename from cdn/factorio_blueprints/red_circuits rename to cdn/factorio_blueprints/red_circuits.txt From b9a00a51e1b85b2c80c6b6b4d7b1655d65c7d9cb Mon Sep 17 00:00:00 2001 From: Fabian Montero Date: Sun, 17 Nov 2024 00:24:20 -0600 Subject: [PATCH 24/24] add firefly --- sys/srv/firefly.nix | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 sys/srv/firefly.nix diff --git a/sys/srv/firefly.nix b/sys/srv/firefly.nix new file mode 100644 index 0000000..2dc636d --- /dev/null +++ b/sys/srv/firefly.nix @@ -0,0 +1,33 @@ +{ + lib, + pkgs, + ... +}: +with lib; { + services = { + nginx = { + virtualHosts."firefly.posixlycorrect.com" = { + enableACME = true; + forceSSL = true; + extraConfig = '' + proxy_headers_hash_max_size 512; + proxy_headers_hash_bucket_size 128; + ''; + }; + }; + + firefly-iii = { + enable = true; + user = "firefly-iii"; + dataDir = "/var/lib/firefly-iii"; + enableNginx = true; + virtualHost = "firefly.posixlycorrect.com"; + settings = { + SITE_OWNER = "fabian@posixlycorrect.com"; + DB_CONNECTION = "sqlite"; + APP_ENV = "local"; + APP_KEY_FILE = /var/trust/firefly/key_file; + }; + }; + }; +}