From 94c201a1ac3036b0a7b5bdd5dc56d667281fdf33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Theodor=20Angerg=C3=A5rd?= Date: Fri, 1 Mar 2024 14:56:03 +0100 Subject: [PATCH] Update --- .github/workflows/gradle.yml | 2 +- app/build.gradle | 5 +- .../it/chalmers/gamma/BootstrapRunner.java | 2 - .../primary/api/info/InfoV1ApiController.java | 2 +- .../primary/web/AllowListController.java | 18 +- .../adapter/primary/web/MeController.java | 48 +- .../adapter/primary/web/UsersController.java | 76 +- .../jpa/apikey/ApiKeyRepositoryAdapter.java | 11 +- .../jpa/client/ClientEntityConverter.java | 2 +- .../jpa/user/UserRepositoryAdapter.java | 4 +- .../AuthorizationRepositoryAdapter.java | 2 +- .../oauth2/AuthorizationTokenMapperValue.java | 2 +- .../gamma/app/apikey/ApiKeyFacade.java | 24 +- .../app/apikey/domain/ApiKeyRepository.java | 4 +- .../gamma/app/apikey/domain/ApiKeyToken.java | 17 +- .../gamma/app/client/ClientFacade.java | 27 +- .../gamma/app/client/domain/ClientId.java | 8 + .../app/client/domain/ClientRedirectUrl.java | 4 +- .../gamma/app/client/domain/ClientSecret.java | 16 +- .../it/chalmers/gamma/app/common/Email.java | 12 +- .../chalmers/gamma/app/common/PrettyName.java | 10 +- .../chalmers/gamma/app/common/TextValue.java | 11 +- .../gamma/app/group/domain/EmailPrefix.java | 9 +- .../app/group/domain/UnofficialPostName.java | 10 + .../domain/GammaAuthorizationToken.java | 2 +- .../it/chalmers/gamma/app/user/MeFacade.java | 11 +- .../gamma/app/user/UserCreationFacade.java | 31 +- .../domain/UserActivationRepository.java | 4 +- .../app/user/allowlist/AllowListFacade.java | 25 +- .../gamma/app/user/domain/FirstName.java | 10 +- .../gamma/app/user/domain/LastName.java | 10 +- .../chalmers/gamma/app/user/domain/Nick.java | 10 +- .../gamma/app/user/domain/Password.java | 2 +- .../domain/PasswordResetToken.java | 10 +- .../gamma/bootstrap/ApiKeyBootstrap.java | 23 +- .../gamma/bootstrap/ClientBootstrap.java | 71 -- .../bootstrap/EnsureAnAdminUserBootstrap.java | 2 +- .../gamma/property/DefaultOAuth2Client.java | 12 - .../it/chalmers/gamma/security/MvcConfig.java | 2 + .../gamma/security/SecurityFiltersConfig.java | 14 +- .../api/ApiAuthenticationProvider.java | 17 +- .../security/api/ApiAuthenticationToken.java | 20 +- app/src/main/resources/application.yml | 9 +- .../main/resources/db/migration/V1__BASE.sql | 2 +- app/src/main/resources/static/css/login.css | 50 ++ app/src/main/resources/static/css/main.css | 102 +++ app/src/main/resources/static/img/bg.webp | Bin 0 -> 150426 bytes app/src/main/resources/static/js/authorize.js | 10 + app/src/main/resources/static/js/main.js | 18 +- app/src/main/resources/static/js/reorder.js | 9 + .../resources/templates/common/alert.html | 2 +- .../resources/templates/common/error.html | 5 + .../resources/templates/common/header.html | 19 - .../resources/templates/common/input.html | 16 +- app/src/main/resources/templates/index.html | 61 +- .../templates/pages/activate-cid.html | 21 +- .../resources/templates/pages/allow-list.html | 23 +- .../templates/pages/api-key-credentials.html | 10 - .../templates/pages/api-key-details.html | 43 +- .../templates/pages/client-credentials.html | 10 - .../templates/pages/client-details.html | 46 +- .../resources/templates/pages/consent.html | 25 +- .../templates/pages/create-api-key.html | 10 - .../templates/pages/create-client.html | 33 - .../templates/pages/create-group.html | 39 +- .../templates/pages/create-super-group.html | 45 +- .../templates/pages/create-user-client.html | 21 +- .../templates/pages/create-user.html | 84 +-- .../pages/finalize-forgot-password.html | 40 +- .../templates/pages/forgot-password.html | 25 +- .../templates/pages/group-details.html | 47 +- .../resources/templates/pages/groups.html | 10 - .../main/resources/templates/pages/home.html | 59 +- .../main/resources/templates/pages/login.html | 30 +- .../main/resources/templates/pages/me.html | 41 -- .../main/resources/templates/pages/posts.html | 17 +- .../templates/pages/register-account.html | 91 ++- .../resources/templates/pages/settings.html | 53 +- .../templates/pages/super-group-details.html | 32 - .../templates/pages/super-groups.html | 10 - .../main/resources/templates/pages/types.html | 57 +- .../templates/pages/user-client-details.html | 16 - .../templates/pages/user-details.html | 51 +- .../partial/add-authority-to-client.html | 9 - .../partial/add-member-to-group.html | 2 +- .../partial/add-restriction-to-client.html | 2 +- .../templates/partial/edit-group.html | 43 +- .../resources/templates/partial/edit-me.html | 1 + .../templates/partial/edit-super-group.html | 2 +- .../templates/partial/edit-user.html | 1 + .../templates/partial/edited-me-password.html | 4 +- .../it/chalmers/gamma/ArchitectureTest.java | 38 - .../primary/AbstractApiControllerTest.java | 35 - .../gamma/adapter/primary/ApiTest.java | 3 - .../AbstractExternalApiControllerTest.java | 14 - .../api/AllowListV1ApiControllerTest.java | 3 - .../api/ClientV1ApiControllerTest.java | 3 - .../api/GoldappsV1ApiControllerTest.java | 3 - .../primary/api/InfoV1ApiControllerTest.java | 91 --- .../primary/oauth2/OAuth2CodeFlowTest.java | 43 -- .../jpa/AbstractEntityIntegrationTests.java | 10 - .../jpa/AllowListEntityIntegrationTests.java | 87 --- .../jpa/ApiKeyEntityIntegrationTests.java | 186 ----- .../jpa/AuthorityEntityIntegrationTests.java | 368 ---------- .../secondary/jpa/EntityIntegrationTest.java | 3 - .../jpa/GroupEntityIntegrationTests.java | 287 -------- .../jpa/PostEntityIntegrationTests.java | 67 -- .../jpa/SettingsEntityIntegrationTests.java | 85 --- .../jpa/SuperGroupEntityIntegrationTests.java | 165 ----- .../SuperGroupTypeEntityIntegrationTests.java | 98 --- .../UserActivationEntityIntegrationTests.java | 181 ----- .../jpa/UserEntityIntegrationTests.java | 312 -------- ...sswordRetrieverEntityIntegrationTests.java | 81 --- .../apikey/ApiKeyFacadeIntegrationTest.java | 119 ---- .../app/apikey/ApiKeyFacadeUnitTest.java | 307 -------- .../app/authentication/AccessGuardTest.java | 672 ------------------ .../ClientAuthorityFacadeIntegrationTest.java | 70 -- .../ClientAuthorityFacadeUnitTest.java | 614 ---------------- .../app/goldapps/GoldappsFacadeUnitTest.java | 117 --- .../app/group/GroupFacadeIntegrationTest.java | 230 ------ .../gamma/app/group/GroupFacadeUnitTest.java | 413 ----------- .../app/post/PostFacadeIntegrationTest.java | 12 - .../gamma/app/post/PostFacadeUnitTest.java | 12 - .../it/chalmers/gamma/utils/DomainUtils.java | 283 -------- .../gamma/utils/FlywayMigrationConfig.java | 23 - .../GammaSecurityContextHolderTestUtils.java | 139 ---- .../PasswordEncoderTestConfiguration.java | 15 - .../resources/application-test-with-mock.yml | 24 - app/src/test/resources/application-test.yml | 24 - .../chalmers/demo/DemoClientApplication.java | 27 - .../it/chalmers/demo/DemoWebSecurity.java | 6 - .../chalmers/demo/GammaAuthoritiesMapper.java | 70 -- .../main/java/it/chalmers/demo/GammaUser.java | 10 - .../java/it/chalmers/demo/MeController.java | 8 - .../src/main/resources/application.yml | 4 +- docker-compose.yml | 2 +- 136 files changed, 840 insertions(+), 6482 deletions(-) delete mode 100644 app/src/main/java/it/chalmers/gamma/bootstrap/ClientBootstrap.java delete mode 100644 app/src/main/java/it/chalmers/gamma/property/DefaultOAuth2Client.java create mode 100644 app/src/main/resources/static/css/login.css create mode 100644 app/src/main/resources/static/css/main.css create mode 100644 app/src/main/resources/static/img/bg.webp create mode 100644 app/src/main/resources/static/js/authorize.js create mode 100644 app/src/main/resources/static/js/reorder.js create mode 100644 app/src/main/resources/templates/common/error.html delete mode 100644 app/src/test/java/it/chalmers/gamma/ArchitectureTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/AbstractApiControllerTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/ApiTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/api/AbstractExternalApiControllerTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/api/AllowListV1ApiControllerTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/api/ClientV1ApiControllerTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/api/GoldappsV1ApiControllerTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/api/InfoV1ApiControllerTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/primary/oauth2/OAuth2CodeFlowTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/AbstractEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/AllowListEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/ApiKeyEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/AuthorityEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/EntityIntegrationTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/GroupEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/PostEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/SettingsEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/SuperGroupEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/SuperGroupTypeEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/UserActivationEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/UserEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/adapter/secondary/jpa/UserPasswordRetrieverEntityIntegrationTests.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/apikey/ApiKeyFacadeIntegrationTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/apikey/ApiKeyFacadeUnitTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/authentication/AccessGuardTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/authority/ClientAuthorityFacadeIntegrationTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/authority/ClientAuthorityFacadeUnitTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/goldapps/GoldappsFacadeUnitTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/group/GroupFacadeIntegrationTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/group/GroupFacadeUnitTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/post/PostFacadeIntegrationTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/app/post/PostFacadeUnitTest.java delete mode 100644 app/src/test/java/it/chalmers/gamma/utils/DomainUtils.java delete mode 100644 app/src/test/java/it/chalmers/gamma/utils/FlywayMigrationConfig.java delete mode 100644 app/src/test/java/it/chalmers/gamma/utils/GammaSecurityContextHolderTestUtils.java delete mode 100644 app/src/test/java/it/chalmers/gamma/utils/PasswordEncoderTestConfiguration.java delete mode 100644 app/src/test/resources/application-test-with-mock.yml delete mode 100644 app/src/test/resources/application-test.yml delete mode 100644 demos/java-client/src/main/java/it/chalmers/demo/GammaAuthoritiesMapper.java delete mode 100644 demos/java-client/src/main/java/it/chalmers/demo/GammaUser.java diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index d2fc3a120..bca0b4dc1 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -34,7 +34,7 @@ jobs: - name: Docker Build-Tag-Push my-app run: | ./gradlew bootBuildImage - docker tag gamma:1.0.0-SNAPSHOT ghcr.io/cthit/gamma:latest + docker tag gamma:2.0.0-SNAPSHOT ghcr.io/cthit/gamma:latest docker push ghcr.io/cthit/gamma:latest working-directory: ./app diff --git a/app/build.gradle b/app/build.gradle index 0de7b90a4..2faa29839 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -74,9 +74,10 @@ dependencies { "org.springframework.boot:spring-boot-starter-thymeleaf:3.1.2", "org.thymeleaf.extras:thymeleaf-extras-springsecurity6:3.1.1.RELEASE", - // htmx and hyperscript + // web dependencies 'org.webjars.npm:htmx.org:1.9.10', - 'org.webjars.npm:hyperscript.org:0.9.12' + 'org.webjars.npm:hyperscript.org:0.9.12', + "org.webjars.npm:picocss__pico:2.0.3" ) testImplementation( diff --git a/app/src/main/java/it/chalmers/gamma/BootstrapRunner.java b/app/src/main/java/it/chalmers/gamma/BootstrapRunner.java index db8741673..633630d75 100644 --- a/app/src/main/java/it/chalmers/gamma/BootstrapRunner.java +++ b/app/src/main/java/it/chalmers/gamma/BootstrapRunner.java @@ -12,7 +12,6 @@ public class BootstrapRunner { @Bean public CommandLineRunner runBootStrap( ApiKeyBootstrap apiKeyBootstrap, - ClientBootstrap clientBootstrap, EnsureAnAdminUserBootstrap ensureAnAdminUserBootstrap, EnsureSettingsBootstrap ensureSettingsBootstrap, GroupBootstrap groupBootstrap, @@ -36,7 +35,6 @@ public CommandLineRunner runBootStrap( superGroupBootstrap.createSuperGroups(); groupBootstrap.createGroups(); - clientBootstrap.runOauthClient(); apiKeyBootstrap.ensureApiKeys(); SecurityContextHolder.clearContext(); diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/info/InfoV1ApiController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/info/InfoV1ApiController.java index dd79a276d..62640fdad 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/primary/api/info/InfoV1ApiController.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/api/info/InfoV1ApiController.java @@ -39,7 +39,7 @@ public GroupsResponse getGroups() { return new GroupsResponse(this.groupFacade.getAllForInfoApi()); } - record GroupsResponse(List groups) {} + public record GroupsResponse(List groups) {} private static class UserNotFoundResponse extends NotFoundResponse {} } diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AllowListController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AllowListController.java index 0f6f672d4..a7fd9e639 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AllowListController.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/AllowListController.java @@ -5,9 +5,7 @@ import jakarta.annotation.Nullable; import java.util.List; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; @Controller @@ -47,7 +45,9 @@ public ModelAndView allow( AllowCidForm request) { try { allowListFacade.allow(request.cid); - } catch (AllowListRepository.AlreadyAllowedException | IllegalArgumentException e) { + } catch (AllowListRepository.AlreadyAllowedException + | IllegalArgumentException + | AllowListFacade.AlreadyAUserException e) { return getAllowList(htmxRequest, e.getMessage()); } @@ -55,4 +55,14 @@ public ModelAndView allow( } public record AllowCidForm(String cid) {} + + @DeleteMapping(value = "/allow-list/{cid}") + public ModelAndView removeCidFromAllowList( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("cid") String cid) { + + this.allowListFacade.removeFromAllowList(cid); + + return new ModelAndView("common/empty"); + } } diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MeController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MeController.java index 97c37ddf2..8f9a58704 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MeController.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/MeController.java @@ -4,6 +4,9 @@ import it.chalmers.gamma.app.image.domain.ImageService; import it.chalmers.gamma.app.user.MeFacade; import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestHeader; @@ -60,13 +63,25 @@ public ModelAndView getEditMe( @PutMapping("/me") public ModelAndView editMe( - @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, EditMe form) { - this.meFacade.updateMe( - new MeFacade.UpdateMe(form.nick, form.firstName, form.lastName, form.email, form.language)); - + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + EditMe form, + final BindingResult bindingResult) { ModelAndView mv = new ModelAndView(); - // TODO: Use only getMe + try { + this.meFacade.updateMe( + new MeFacade.UpdateMe( + form.nick, form.firstName, form.lastName, form.email, form.language)); + } catch (IllegalArgumentException e) { + bindingResult.addError(new ObjectError("global", e.getMessage())); + + mv.setViewName("partial/edit-me"); + mv.addObject("form", form); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; + } + MeFacade.MeDTO me = this.meFacade.getMe(); mv.setViewName("partial/edited-me"); @@ -118,12 +133,25 @@ public ModelAndView getEditPassword( @PutMapping("/me/edit-password") public ModelAndView editPassword( @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, - EditPasswordForm form) { - // TODO: Move validation to facade - if (!form.newPassword.equals(form.confirmNewPassword)) {} + EditPasswordForm form, + final BindingResult bindingResult) { + + try { + this.meFacade.updatePassword( + new MeFacade.UpdatePassword( + form.currentPassword, form.newPassword, form.confirmNewPassword)); + } catch (MeFacade.NewPasswordNotConfirmedException e) { + bindingResult.addError( + new FieldError("form", "confirmNewPassword", "Passwords were not the same")); - this.meFacade.updatePassword( - new MeFacade.UpdatePassword(form.currentPassword, form.newPassword)); + ModelAndView mv = new ModelAndView(); + + mv.setViewName("partial/edit-me-password"); + mv.addObject("form", new MeFacade.UpdatePassword("", "", "")); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; + } MeFacade.MeDTO me = this.meFacade.getMe(); diff --git a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UsersController.java b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UsersController.java index 7e559135a..43994cd86 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UsersController.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/primary/web/UsersController.java @@ -9,6 +9,8 @@ import java.util.Optional; import java.util.UUID; import org.springframework.stereotype.Controller; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.*; import org.springframework.web.servlet.ModelAndView; @@ -136,7 +138,11 @@ public ModelAndView getCreateUser( @PostMapping("/users") public ModelAndView createUser( - @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, CreateUser form) { + @RequestHeader(value = "HX-Request", required = false) boolean htmxRequest, + CreateUser form, + final BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + try { UUID userId = this.userCreationFacade.createUser( @@ -150,9 +156,25 @@ public ModelAndView createUser( form.cid, form.language)); - return new ModelAndView("redirect:/users/" + userId); - } catch (UserCreationFacade.SomePropertyNotUniqueException e) { - throw new RuntimeException(e); + mv.setViewName("redirect:/users/" + userId); + + return mv; + } catch (IllegalArgumentException + | UserCreationFacade.CidNotUniqueException + | UserCreationFacade.EmailNotUniqueException e) { + bindingResult.addError(new ObjectError("global", e.getMessage())); + + if (htmxRequest) { + mv.setViewName("pages/create-user"); + } else { + mv.setViewName("index"); + mv.addObject("page", "pages/create-user"); + } + + mv.addObject("form", form); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; } } @@ -192,16 +214,30 @@ public ModelAndView getEditUser( public ModelAndView editUser( @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, @PathVariable("id") UUID userId, - EditUser form) { - this.userFacade.updateUser( - new UserFacade.UpdateUser( - userId, - form.nick, - form.firstName, - form.lastName, - form.email, - form.language, - form.acceptanceYear)); + EditUser form, + BindingResult bindingResult) { + ModelAndView mv = new ModelAndView(); + + try { + this.userFacade.updateUser( + new UserFacade.UpdateUser( + userId, + form.nick, + form.firstName, + form.lastName, + form.email, + form.language, + form.acceptanceYear)); + } catch (IllegalArgumentException e) { + bindingResult.addError(new ObjectError("global", e.getMessage())); + + mv.setViewName("partial/edit-user"); + mv.addObject("userId", userId); + mv.addObject("form", form); + mv.addObject(BindingResult.MODEL_KEY_PREFIX + "form", bindingResult); + + return mv; + } Optional user = this.userFacade.getAsAdmin(userId); @@ -211,8 +247,6 @@ public ModelAndView editUser( String name = form.firstName() + " '" + form.nick() + "' " + form.lastName(); - ModelAndView mv = new ModelAndView(); - mv.setViewName("partial/edited-user"); mv.addObject("name", name); mv.addObject("cid", user.get().user().cid()); @@ -223,4 +257,14 @@ public ModelAndView editUser( return mv; } + + @DeleteMapping("/users/{id}") + public ModelAndView deleteUser( + @RequestHeader(value = "HX-Request", required = true) boolean htmxRequest, + @PathVariable("id") UUID userId) { + + this.userFacade.deleteUser(userId); + + return new ModelAndView("redirect:/users"); + } } diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyRepositoryAdapter.java index b920542ed..6e7a7b009 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyRepositoryAdapter.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/apikey/ApiKeyRepositoryAdapter.java @@ -63,16 +63,6 @@ public void delete(ApiKeyId apiKeyId) throws ApiKeyNotFoundException { } } - @Override - public ApiKeyToken resetApiKeyToken(ApiKeyId apiKeyId) throws ApiKeyNotFoundException { - ApiKeyToken newToken = ApiKeyToken.generate(); - ApiKeyEntity entity = - this.repository.findById(apiKeyId.value()).orElseThrow(ApiKeyNotFoundException::new); - entity.setApiKeyToken(newToken.value()); - this.repository.saveAndFlush(entity); - return newToken; - } - @Override public List getAll() { return this.repository.findAll().stream() @@ -87,6 +77,7 @@ public Optional getById(ApiKeyId apiKeyId) { @Override public Optional getByToken(ApiKeyToken apiKeyToken) { + System.out.println(apiKeyToken.value()); return this.repository .findByToken(apiKeyToken.value()) .map(this.apiKeyEntityConverter::toDomain); diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntityConverter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntityConverter.java index 4ab5b24bd..0ae2fb81f 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntityConverter.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/client/ClientEntityConverter.java @@ -87,7 +87,7 @@ public ClientEntity toEntity(Client client) { clientEntity.clientUid = client.clientUid().value(); clientEntity.clientId = client.clientId().value(); - clientEntity.clientSecret = this.passwordEncoder.encode(client.clientSecret().value()); + clientEntity.clientSecret = client.clientSecret().value(); clientEntity.prettyName = client.prettyName().value(); clientEntity.webServerRedirectUrl = client.clientRedirectUrl().value(); diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserRepositoryAdapter.java index a7241e990..e2ed39801 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserRepositoryAdapter.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/jpa/user/UserRepositoryAdapter.java @@ -21,10 +21,10 @@ public class UserRepositoryAdapter implements UserRepository { private final PasswordEncoder passwordEncoder; private final PersistenceErrorState cidNotUnique = - new PersistenceErrorState("ituser_cid_key", PersistenceErrorState.Type.NOT_UNIQUE); + new PersistenceErrorState("g_user_cid_key", PersistenceErrorState.Type.NOT_UNIQUE); private final PersistenceErrorState emailNotUnique = - new PersistenceErrorState("ituser_email_key", PersistenceErrorState.Type.NOT_UNIQUE); + new PersistenceErrorState("g_user_email_key", PersistenceErrorState.Type.NOT_UNIQUE); public UserRepositoryAdapter( UserJpaRepository repository, diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRepositoryAdapter.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRepositoryAdapter.java index c64870121..e4421c4e6 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRepositoryAdapter.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationRepositoryAdapter.java @@ -22,7 +22,7 @@ public AuthorizationRepositoryAdapter( this.authorizationTokenMapperRedisRepository = authorizationTokenMapperRedisRepository; } - // HMM den sparar bara gamma-authorization och gamma-authorization-token? + // HMM den sparar bara gamma-authorization och gamma-authorization-rawToken? // Också, ta bort GammaAuthorization och spara OAuth2Authorization direkt bara. @Override diff --git a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperValue.java b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperValue.java index db25868fd..508046066 100644 --- a/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperValue.java +++ b/app/src/main/java/it/chalmers/gamma/adapter/secondary/redis/oauth2/AuthorizationTokenMapperValue.java @@ -3,7 +3,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.redis.core.RedisHash; -@RedisHash(value = "token", timeToLive = 3600) +@RedisHash(value = "rawToken", timeToLive = 3600) public class AuthorizationTokenMapperValue { @Id String tokenKey; diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java b/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java index 89b180056..fdc2a2eaf 100644 --- a/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/ApiKeyFacade.java @@ -11,16 +11,20 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; @Component public class ApiKeyFacade extends Facade { private final ApiKeyRepository apiKeyRepository; + private final PasswordEncoder passwordEncoder; - public ApiKeyFacade(AccessGuard accessGuard, ApiKeyRepository apiKeyRepository) { + public ApiKeyFacade( + AccessGuard accessGuard, ApiKeyRepository apiKeyRepository, PasswordEncoder passwordEncoder) { super(accessGuard); this.apiKeyRepository = apiKeyRepository; + this.passwordEncoder = passwordEncoder; } public String[] getApiKeyTypes() { @@ -48,15 +52,15 @@ public CreatedApiKey create(NewApiKey newApiKey) { } ApiKeyId apiKeyId = ApiKeyId.generate(); - ApiKeyToken apiKeyToken = ApiKeyToken.generate(); + ApiKeyToken.GeneratedApiKeyToken generated = ApiKeyToken.generate(passwordEncoder); apiKeyRepository.create( new ApiKey( apiKeyId, new PrettyName(newApiKey.prettyName), new Text(newApiKey.svDescription, newApiKey.enDescription), type, - apiKeyToken)); - return new CreatedApiKey(apiKeyId.value(), apiKeyToken.value()); + generated.apiKeyToken())); + return new CreatedApiKey(apiKeyId.value(), generated.rawToken()); } public void delete(UUID apiKeyId) throws ApiKeyNotFoundException { @@ -81,18 +85,6 @@ public List getAll() { return this.apiKeyRepository.getAll().stream().map(ApiKeyDTO::new).toList(); } - public String resetApiKeyToken(UUID apiKeyId) throws ApiKeyNotFoundException { - this.accessGuard.require(isAdmin()); - - ApiKeyToken token; - try { - token = this.apiKeyRepository.resetApiKeyToken(new ApiKeyId(apiKeyId)); - } catch (ApiKeyRepository.ApiKeyNotFoundException e) { - throw new ApiKeyNotFoundException(); - } - return token.value(); - } - public record NewApiKey( String prettyName, String svDescription, String enDescription, String keyType) {} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyRepository.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyRepository.java index 33364fea0..ed88bf527 100644 --- a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyRepository.java +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyRepository.java @@ -9,8 +9,6 @@ public interface ApiKeyRepository { void delete(ApiKeyId apiKeyId) throws ApiKeyNotFoundException; - ApiKeyToken resetApiKeyToken(ApiKeyId apiKeyId) throws ApiKeyNotFoundException; - List getAll(); Optional getById(ApiKeyId apiKeyId); @@ -20,7 +18,7 @@ public interface ApiKeyRepository { class ApiKeyNotFoundException extends Exception {} /** - * Either the api key id or token already exists. Runtime exception since id and token is + * Either the api key id or rawToken already exists. Runtime exception since id and rawToken is * generated. */ class ApiKeyAlreadyExistRuntimeException extends RuntimeException {} diff --git a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyToken.java b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyToken.java index 7a41e2f9f..eb97d2bcd 100644 --- a/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyToken.java +++ b/app/src/main/java/it/chalmers/gamma/app/apikey/domain/ApiKeyToken.java @@ -2,25 +2,30 @@ import it.chalmers.gamma.util.TokenUtils; import java.util.Objects; +import java.util.regex.Pattern; +import org.springframework.security.crypto.password.PasswordEncoder; public record ApiKeyToken(String value) { + private static final Pattern apiKeyTokenStartPattern = Pattern.compile("^\\{bcrypt}.+"); + public ApiKeyToken { Objects.requireNonNull(value); - // TODO: Use the following validation - // if (value.length() < 150) { - // throw new IllegalArgumentException(); - // } + if (!apiKeyTokenStartPattern.matcher(value).matches()) { + throw new IllegalArgumentException("Api key rawToken not encrypted properly"); + } } - public static ApiKeyToken generate() { + public record GeneratedApiKeyToken(ApiKeyToken apiKeyToken, String rawToken) {} + + public static GeneratedApiKeyToken generate(PasswordEncoder passwordEncoder) { String value = TokenUtils.generateToken( 50, TokenUtils.CharacterTypes.LOWERCASE, TokenUtils.CharacterTypes.UPPERCASE, TokenUtils.CharacterTypes.NUMBERS); - return new ApiKeyToken(value); + return new GeneratedApiKeyToken(new ApiKeyToken(passwordEncoder.encode(value)), value); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/client/ClientFacade.java b/app/src/main/java/it/chalmers/gamma/app/client/ClientFacade.java index b40fc316a..43ee47ba4 100644 --- a/app/src/main/java/it/chalmers/gamma/app/client/ClientFacade.java +++ b/app/src/main/java/it/chalmers/gamma/app/client/ClientFacade.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Optional; import java.util.UUID; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @Service @@ -34,16 +35,19 @@ public class ClientFacade extends Facade { private final ClientRepository clientRepository; private final SuperGroupRepository superGroupRepository; private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; public ClientFacade( AccessGuard accessGuard, ClientRepository clientRepository, SuperGroupRepository superGroupRepository, - UserRepository userRepository) { + UserRepository userRepository, + PasswordEncoder passwordEncoder) { super(accessGuard); this.clientRepository = clientRepository; this.superGroupRepository = superGroupRepository; this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; } @Transactional @@ -70,12 +74,13 @@ public ClientAndApiKeySecrets createUserClient(NewClient newClient) { } private ClientAndApiKeySecrets create(NewClient newClient, ClientOwner clientOwner) { - ClientSecret clientSecret = ClientSecret.generate(); + ClientSecret.GeneratedClientSecret generatedClientSecret = + ClientSecret.generate(passwordEncoder); ApiKey apiKey = null; - ApiKeyToken apiKeyToken = null; + ApiKeyToken.GeneratedApiKeyToken generatedApiKeyToken = null; if (newClient.generateApiKey) { - apiKeyToken = ApiKeyToken.generate(); + generatedApiKeyToken = ApiKeyToken.generate(passwordEncoder); apiKey = new ApiKey( @@ -85,7 +90,7 @@ private ClientAndApiKeySecrets create(NewClient newClient, ClientOwner clientOwn "Api nyckel för klienten: " + newClient.prettyName, "Api key for client: " + newClient.prettyName), ApiKeyType.CLIENT, - apiKeyToken); + generatedApiKeyToken.apiKeyToken()); } List scopes = new ArrayList<>(); @@ -115,7 +120,7 @@ private ClientAndApiKeySecrets create(NewClient newClient, ClientOwner clientOwn new Client( clientUid, clientId, - clientSecret, + generatedClientSecret.clientSecret(), new ClientRedirectUrl(newClient.redirectUrl), new PrettyName(newClient.prettyName), new Text(newClient.svDescription, newClient.enDescription), @@ -129,8 +134,8 @@ private ClientAndApiKeySecrets create(NewClient newClient, ClientOwner clientOwn return new ClientAndApiKeySecrets( clientUid.value(), clientId.value(), - clientSecret.value(), - apiKeyToken == null ? null : apiKeyToken.value()); + generatedClientSecret.rawSecret(), + generatedApiKeyToken == null ? null : generatedApiKeyToken.rawToken()); } public void delete(UUID clientUid) throws ClientFacade.ClientNotFoundException { @@ -178,13 +183,13 @@ public String resetClientSecret(UUID clientUid) throws ClientNotFoundException { this.accessGuard.requireEither(isAdmin(), ownerOfClient(uid)); Client client = this.clientRepository.get(uid).orElseThrow(ClientNotFoundException::new); - ClientSecret newSecret = ClientSecret.generate(); + ClientSecret.GeneratedClientSecret generated = ClientSecret.generate(passwordEncoder); - Client newClient = client.withClientSecret(newSecret); + Client newClient = client.withClientSecret(generated.clientSecret()); this.clientRepository.save(newClient); - return newSecret.value(); + return generated.rawSecret(); } public Optional getClientOwner(String clientId) { diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientId.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientId.java index 33e1a1630..c98a81fb2 100644 --- a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientId.java +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientId.java @@ -2,12 +2,20 @@ import it.chalmers.gamma.util.TokenUtils; import java.util.Objects; +import java.util.regex.Pattern; /** Id for the client that is used in the OAuth2 flow. */ public record ClientId(String value) { + private static final Pattern clientIdPattern = Pattern.compile("^[A-Z0-9]{30}$"); + public ClientId { Objects.requireNonNull(value); + + if (!clientIdPattern.matcher(value).matches()) { + throw new IllegalArgumentException( + "Client id can only have upper case characters and numbers"); + } } public static ClientId generate() { diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRedirectUrl.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRedirectUrl.java index fabf9d599..fe73aa325 100644 --- a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRedirectUrl.java +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientRedirectUrl.java @@ -1,5 +1,7 @@ package it.chalmers.gamma.app.client.domain; +import org.springframework.web.util.HtmlUtils; + public record ClientRedirectUrl(String value) { public ClientRedirectUrl { @@ -7,6 +9,6 @@ public record ClientRedirectUrl(String value) { throw new NullPointerException(); } - // TODO: add more validation + value = HtmlUtils.htmlEscape(value, "UTF-8"); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientSecret.java b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientSecret.java index dc354108a..4b0c40b8a 100644 --- a/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientSecret.java +++ b/app/src/main/java/it/chalmers/gamma/app/client/domain/ClientSecret.java @@ -2,20 +2,30 @@ import it.chalmers.gamma.util.TokenUtils; import java.util.Objects; +import java.util.regex.Pattern; +import org.springframework.security.crypto.password.PasswordEncoder; public record ClientSecret(String value) { + private static final Pattern clientSecretStartPattern = Pattern.compile("^\\{bcrypt}.+"); + public ClientSecret { Objects.requireNonNull(value); + + if (!clientSecretStartPattern.matcher(value).matches()) { + throw new IllegalArgumentException("Client rawSecret not properly encrypted"); + } } - public static ClientSecret generate() { + public record GeneratedClientSecret(ClientSecret clientSecret, String rawSecret) {} + + public static GeneratedClientSecret generate(PasswordEncoder passwordEncoder) { String value = TokenUtils.generateToken( - 50, + 128, TokenUtils.CharacterTypes.LOWERCASE, TokenUtils.CharacterTypes.UPPERCASE, TokenUtils.CharacterTypes.NUMBERS); - return new ClientSecret(value); + return new GeneratedClientSecret(new ClientSecret(passwordEncoder.encode(value)), value); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/common/Email.java b/app/src/main/java/it/chalmers/gamma/app/common/Email.java index 34fee5d37..203a4aa92 100644 --- a/app/src/main/java/it/chalmers/gamma/app/common/Email.java +++ b/app/src/main/java/it/chalmers/gamma/app/common/Email.java @@ -2,7 +2,9 @@ import it.chalmers.gamma.app.user.domain.UserIdentifier; import java.io.Serializable; +import java.util.Objects; import java.util.regex.Pattern; +import org.springframework.web.util.HtmlUtils; public record Email(String value) implements UserIdentifier, Serializable { @@ -11,10 +13,12 @@ public record Email(String value) implements UserIdentifier, Serializable { "^[\\w!#$%&'*+/=?`{|}~^-]+(?:\\.[\\w!#$%&'*+/=?`{|}~^-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$"); public Email { - if (value == null) { - throw new NullPointerException("Email cannot be null"); - } else if (!emailPattern.matcher(value).matches()) { - throw new IllegalArgumentException("Email: [" + value + "] does not look valid"); + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (!emailPattern.matcher(value).matches()) { + throw new IllegalArgumentException("Email does not look valid"); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/common/PrettyName.java b/app/src/main/java/it/chalmers/gamma/app/common/PrettyName.java index 170e681bb..135e567f3 100644 --- a/app/src/main/java/it/chalmers/gamma/app/common/PrettyName.java +++ b/app/src/main/java/it/chalmers/gamma/app/common/PrettyName.java @@ -1,13 +1,17 @@ package it.chalmers.gamma.app.common; import java.io.Serializable; +import java.util.Objects; +import org.springframework.web.util.HtmlUtils; public record PrettyName(String value) implements Serializable { public PrettyName { - if (value == null) { - throw new NullPointerException("Pretty name cannot be null"); - } else if (value.length() < 2 || value.length() > 50) { + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (value.length() < 2 || value.length() > 50) { throw new IllegalArgumentException("Pretty name must be between 3 and 50 in length"); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/common/TextValue.java b/app/src/main/java/it/chalmers/gamma/app/common/TextValue.java index 25647ea82..1d05e7c50 100644 --- a/app/src/main/java/it/chalmers/gamma/app/common/TextValue.java +++ b/app/src/main/java/it/chalmers/gamma/app/common/TextValue.java @@ -1,11 +1,16 @@ package it.chalmers.gamma.app.common; +import java.util.Objects; +import org.springframework.web.util.HtmlUtils; + public record TextValue(String value) { public TextValue { - if (value == null) { - throw new NullPointerException("Text value cannot be null"); - } else if (value.length() > 2048) { + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (value.length() > 2048) { throw new IllegalArgumentException("Text value max length is 2048"); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/EmailPrefix.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/EmailPrefix.java index 3a5e25ef0..c7a6f7c37 100644 --- a/app/src/main/java/it/chalmers/gamma/app/group/domain/EmailPrefix.java +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/EmailPrefix.java @@ -1,9 +1,16 @@ package it.chalmers.gamma.app.group.domain; +import java.util.Objects; +import org.springframework.web.util.HtmlUtils; + public record EmailPrefix(String value) { public EmailPrefix { - if (value != null && !value.matches("^$|^(?:\\w+|\\w+\\.\\w+)+$")) { + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (!value.matches("^$|^(?:\\w+|\\w+\\.\\w+)+$")) { throw new IllegalArgumentException( "Email prefix most be letters of a - z, and each word must be seperated by a dot"); } diff --git a/app/src/main/java/it/chalmers/gamma/app/group/domain/UnofficialPostName.java b/app/src/main/java/it/chalmers/gamma/app/group/domain/UnofficialPostName.java index bd85fe133..2b0bb5d77 100644 --- a/app/src/main/java/it/chalmers/gamma/app/group/domain/UnofficialPostName.java +++ b/app/src/main/java/it/chalmers/gamma/app/group/domain/UnofficialPostName.java @@ -1,11 +1,21 @@ package it.chalmers.gamma.app.group.domain; +import org.springframework.web.util.HtmlUtils; + public record UnofficialPostName(String value) { public UnofficialPostName { if ("".equals(value)) { value = null; } + + if (value != null) { + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (value.length() > 50) { + throw new IllegalArgumentException("Unofficial post name can max be 50 characters"); + } + } } public static UnofficialPostName none() { diff --git a/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationToken.java b/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationToken.java index a355a110b..730679c65 100644 --- a/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationToken.java +++ b/app/src/main/java/it/chalmers/gamma/app/oauth2/domain/GammaAuthorizationToken.java @@ -11,7 +11,7 @@ public static GammaAuthorizationToken valueOf(String value, OAuth2TokenType auth case "state" -> new GammaAuthorizationToken(value, Type.STATE); case "oidc" -> new GammaAuthorizationToken(value, Type.OIDC); default -> - throw new IllegalArgumentException("Invalid token type: " + auth2TokenType.getValue()); + throw new IllegalArgumentException("Invalid rawToken type: " + auth2TokenType.getValue()); }; } diff --git a/app/src/main/java/it/chalmers/gamma/app/user/MeFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/MeFacade.java index 02d02785d..3b0b8ceb9 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/MeFacade.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/MeFacade.java @@ -109,9 +109,14 @@ public void updateMe(UpdateMe updateMe) { } } - public void updatePassword(UpdatePassword updatePassword) { + public void updatePassword(UpdatePassword updatePassword) + throws NewPasswordNotConfirmedException { GammaAuthentication authenticated = AuthenticationExtractor.getAuthentication(); if (authenticated instanceof UserAuthentication userAuthentication) { + if (!updatePassword.newPassword.equals(updatePassword.confirmNewPassword)) { + throw new NewPasswordNotConfirmedException(); + } + GammaUser me = userAuthentication.gammaUser(); if (this.userRepository.checkPassword( me.id(), new UnencryptedPassword(updatePassword.oldPassword))) { @@ -213,5 +218,7 @@ public MeDTO(GammaUser user, List groups, boolean isAdmin) { public record UpdateMe( String nick, String firstName, String lastName, String email, String language) {} - public record UpdatePassword(String oldPassword, String newPassword) {} + public record UpdatePassword(String oldPassword, String newPassword, String confirmNewPassword) {} + + public static final class NewPasswordNotConfirmedException extends Exception {} } diff --git a/app/src/main/java/it/chalmers/gamma/app/user/UserCreationFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/UserCreationFacade.java index 182a799cc..31d622213 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/UserCreationFacade.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/UserCreationFacade.java @@ -9,7 +9,6 @@ import it.chalmers.gamma.app.mail.domain.MailService; import it.chalmers.gamma.app.user.activation.domain.UserActivationRepository; import it.chalmers.gamma.app.user.activation.domain.UserActivationToken; -import it.chalmers.gamma.app.user.allowlist.AllowListRepository; import it.chalmers.gamma.app.user.domain.*; import jakarta.transaction.Transactional; import java.util.UUID; @@ -23,19 +22,16 @@ public class UserCreationFacade extends Facade { private static final String MAIL_POSTFIX = "student.chalmers.se"; private static final Logger LOGGER = LoggerFactory.getLogger(UserCreationFacade.class); private final MailService mailService; - private final AllowListRepository allowListRepository; private final UserActivationRepository userActivationRepository; private final UserRepository userRepository; public UserCreationFacade( AccessGuard accessGuard, MailService mailService, - AllowListRepository allowListRepository, UserActivationRepository userActivationRepository, UserRepository userRepository) { super(accessGuard); this.mailService = mailService; - this.allowListRepository = allowListRepository; this.userActivationRepository = userActivationRepository; this.userRepository = userRepository; } @@ -54,7 +50,7 @@ public void tryToActivateUser(String cidRaw) { } } - public UUID createUser(NewUser newUser) throws SomePropertyNotUniqueException { + public UUID createUser(NewUser newUser) throws EmailNotUniqueException, CidNotUniqueException { this.accessGuard.require(isAdmin()); UserId userId = UserId.generate(); @@ -73,9 +69,10 @@ public UUID createUser(NewUser newUser) throws SomePropertyNotUniqueException { new UnencryptedPassword(newUser.password)); return userId.value(); - } catch (UserRepository.CidAlreadyInUseException - | UserRepository.EmailAlreadyInUseException e) { - throw new SomePropertyNotUniqueException(); + } catch (UserRepository.CidAlreadyInUseException e) { + throw new CidNotUniqueException(); + } catch (UserRepository.EmailAlreadyInUseException e) { + throw new EmailNotUniqueException(); } } @@ -128,5 +125,21 @@ public record NewUser( String cid, String language) {} - public class SomePropertyNotUniqueException extends Exception {} + public static class SomePropertyNotUniqueException extends Exception { + public SomePropertyNotUniqueException() { + super("Please double check your details"); + } + } + + public static class CidNotUniqueException extends Exception { + public CidNotUniqueException() { + super("Cid is already in use"); + } + } + + public static class EmailNotUniqueException extends Exception { + public EmailNotUniqueException() { + super("Email is already in use"); + } + } } diff --git a/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationRepository.java b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationRepository.java index bdbd1ca22..f7be0d75b 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationRepository.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/activation/domain/UserActivationRepository.java @@ -7,11 +7,11 @@ public interface UserActivationRepository { /** - * Creates an activation token that is connected to the cid. If there already is a token + * Creates an activation rawToken that is connected to the cid. If there already is a rawToken * generated, then a new one will be generated. * * @param cid A cid that has been allowed - * @return A token that can be used to create an account with the given cid + * @return A rawToken that can be used to create an account with the given cid */ UserActivationToken createActivationToken(Cid cid) throws CidNotAllowedException; diff --git a/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListFacade.java b/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListFacade.java index 87cbd31d8..48d600700 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListFacade.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/allowlist/AllowListFacade.java @@ -7,6 +7,7 @@ import it.chalmers.gamma.app.apikey.domain.ApiKeyType; import it.chalmers.gamma.app.authentication.AccessGuard; import it.chalmers.gamma.app.user.domain.Cid; +import it.chalmers.gamma.app.user.domain.UserRepository; import java.util.List; import org.springframework.stereotype.Service; @@ -14,10 +15,15 @@ public class AllowListFacade extends Facade { private final AllowListRepository allowListRepository; + private final UserRepository userRepository; - public AllowListFacade(AccessGuard accessGuard, AllowListRepository allowListRepository) { + public AllowListFacade( + AccessGuard accessGuard, + AllowListRepository allowListRepository, + UserRepository userRepository) { super(accessGuard); this.allowListRepository = allowListRepository; + this.userRepository = userRepository; } public List getAllowList() { @@ -26,10 +32,17 @@ public List getAllowList() { return this.allowListRepository.getAllowList().stream().map(Cid::value).toList(); } - public void allow(String cid) throws AllowListRepository.AlreadyAllowedException { + public void allow(String cidRaw) + throws AllowListRepository.AlreadyAllowedException, AlreadyAUserException { + Cid cid = new Cid(cidRaw); + this.accessGuard.requireEither(isAdmin(), isApi(ApiKeyType.ALLOW_LIST)); - this.allowListRepository.allow(new Cid(cid)); + if (this.userRepository.get(cid).isPresent()) { + throw new AlreadyAUserException(); + } + + this.allowListRepository.allow(cid); } public void removeFromAllowList(String cid) throws AllowListRepository.NotOnAllowListException { @@ -43,4 +56,10 @@ public boolean isAllowed(String cid) { return this.allowListRepository.isAllowed(new Cid(cid)); } + + public static final class AlreadyAUserException extends Exception { + public AlreadyAUserException() { + super("Cid is already a user"); + } + } } diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/FirstName.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/FirstName.java index fff6185d2..0a02c8b9c 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/domain/FirstName.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/FirstName.java @@ -1,13 +1,17 @@ package it.chalmers.gamma.app.user.domain; import java.io.Serializable; +import java.util.Objects; +import org.springframework.web.util.HtmlUtils; public record FirstName(String value) implements Serializable { public FirstName { - if (value == null) { - throw new NullPointerException("First name cannot be null"); - } else if (value.length() < 1 || value.length() > 50) { + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (value.isEmpty() || value.length() > 50) { throw new IllegalArgumentException("First name length must be between 1 and 50"); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/LastName.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/LastName.java index c22893103..5daa3af00 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/domain/LastName.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/LastName.java @@ -1,13 +1,17 @@ package it.chalmers.gamma.app.user.domain; import java.io.Serializable; +import java.util.Objects; +import org.springframework.web.util.HtmlUtils; public record LastName(String value) implements Serializable { public LastName { - if (value == null) { - throw new NullPointerException("Last name cannot be null"); - } else if (value.length() < 1 || value.length() > 50) { + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (value.isEmpty() || value.length() > 50) { throw new IllegalArgumentException("Last name length must be between 1 and 50"); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/Nick.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/Nick.java index 36bc2bf46..f9294cbc8 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/domain/Nick.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/Nick.java @@ -1,13 +1,17 @@ package it.chalmers.gamma.app.user.domain; import java.io.Serializable; +import java.util.Objects; +import org.springframework.web.util.HtmlUtils; public record Nick(String value) implements Serializable { public Nick { - if (value == null) { - throw new NullPointerException("Nick cannot be null"); - } else if (value.length() < 1 || value.length() > 30) { + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + + if (value.isEmpty() || value.length() > 30) { throw new IllegalArgumentException("Nick length must be between 1 and 30"); } } diff --git a/app/src/main/java/it/chalmers/gamma/app/user/domain/Password.java b/app/src/main/java/it/chalmers/gamma/app/user/domain/Password.java index c403c5651..dbe51bede 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/domain/Password.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/domain/Password.java @@ -4,7 +4,7 @@ public record Password(String value) { - private static final Pattern passwordStartPattern = Pattern.compile("^\\{.+}.+"); + private static final Pattern passwordStartPattern = Pattern.compile("^\\{bcrypt}.+"); public Password { if (value == null) { diff --git a/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetToken.java b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetToken.java index 5c8037ed9..7109835d3 100644 --- a/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetToken.java +++ b/app/src/main/java/it/chalmers/gamma/app/user/passwordreset/domain/PasswordResetToken.java @@ -1,13 +1,21 @@ package it.chalmers.gamma.app.user.passwordreset.domain; import it.chalmers.gamma.util.TokenUtils; +import java.util.Objects; +import org.springframework.web.util.HtmlUtils; public record PasswordResetToken(String value) { + public PasswordResetToken { + Objects.requireNonNull(value); + + value = HtmlUtils.htmlEscape(value, "UTF-8"); + } + public static PasswordResetToken generate() { String value = TokenUtils.generateToken( - 75, TokenUtils.CharacterTypes.UPPERCASE, TokenUtils.CharacterTypes.NUMBERS); + 20, TokenUtils.CharacterTypes.UPPERCASE, TokenUtils.CharacterTypes.NUMBERS); return new PasswordResetToken(value); } } diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/ApiKeyBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/ApiKeyBootstrap.java index ee7849013..b5b546e98 100644 --- a/app/src/main/java/it/chalmers/gamma/bootstrap/ApiKeyBootstrap.java +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/ApiKeyBootstrap.java @@ -5,6 +5,7 @@ import it.chalmers.gamma.app.common.Text; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Component; @Component @@ -14,14 +15,19 @@ public class ApiKeyBootstrap { private final ApiKeyRepository apiKeyRepository; private final BootstrapSettings bootstrapSettings; + private final PasswordEncoder passwordEncoder; - public ApiKeyBootstrap(ApiKeyRepository apiKeyRepository, BootstrapSettings bootstrapSettings) { + public ApiKeyBootstrap( + ApiKeyRepository apiKeyRepository, + BootstrapSettings bootstrapSettings, + PasswordEncoder passwordEncoder) { this.apiKeyRepository = apiKeyRepository; this.bootstrapSettings = bootstrapSettings; + this.passwordEncoder = passwordEncoder; } public void ensureApiKeys() { - if (!this.bootstrapSettings.mocking() || this.apiKeyRepository.getAll().size() != 1) { + if (!this.bootstrapSettings.mocking() || !this.apiKeyRepository.getAll().isEmpty()) { return; } @@ -30,22 +36,27 @@ public void ensureApiKeys() { for (ApiKeyType apiKeyType : ApiKeyType.values()) { if (apiKeyType != ApiKeyType.CLIENT) { - ApiKeyToken apiKeyToken = new ApiKeyToken(apiKeyType.name() + "-super-secret-code"); + ApiKeyToken.GeneratedApiKeyToken generated = ApiKeyToken.generate(passwordEncoder); + ApiKeyId id = ApiKeyId.generate(); this.apiKeyRepository.create( new ApiKey( - ApiKeyId.generate(), + id, new PrettyName(apiKeyType.name() + "-mock"), new Text(), apiKeyType, - apiKeyToken)); + generated.apiKeyToken())); LOGGER.info( "Api key of type " + apiKeyType.name() + " has been generated with code: " - + apiKeyToken.value()); + + generated.rawToken() + + " and id: " + + id.value()); } } + + LOGGER.info("Add the header: Authorization: pre-shared : to start using the APIs"); LOGGER.info("========== =========="); } } diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/ClientBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/ClientBootstrap.java deleted file mode 100644 index 56c464360..000000000 --- a/app/src/main/java/it/chalmers/gamma/bootstrap/ClientBootstrap.java +++ /dev/null @@ -1,71 +0,0 @@ -package it.chalmers.gamma.bootstrap; - -import it.chalmers.gamma.app.apikey.domain.ApiKey; -import it.chalmers.gamma.app.apikey.domain.ApiKeyId; -import it.chalmers.gamma.app.apikey.domain.ApiKeyToken; -import it.chalmers.gamma.app.apikey.domain.ApiKeyType; -import it.chalmers.gamma.app.client.domain.*; -import it.chalmers.gamma.app.common.PrettyName; -import it.chalmers.gamma.app.common.Text; -import it.chalmers.gamma.property.DefaultOAuth2Client; -import java.util.Arrays; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Component; - -@Component -public class ClientBootstrap { - - private static final Logger LOGGER = LoggerFactory.getLogger(ClientBootstrap.class); - private final BootstrapSettings bootstrapSettings; - private final DefaultOAuth2Client defaultOAuth2Client; - private final ClientRepository clientRepository; - - public ClientBootstrap( - BootstrapSettings bootstrapSettings, - DefaultOAuth2Client defaultOAuth2Client, - ClientRepository clientRepository) { - this.bootstrapSettings = bootstrapSettings; - this.defaultOAuth2Client = defaultOAuth2Client; - this.clientRepository = clientRepository; - } - - public void runOauthClient() { - if (!this.bootstrapSettings.mocking() || !this.clientRepository.getAll().isEmpty()) { - return; - } - LOGGER.info("========== CLIENT BOOTSTRAP =========="); - LOGGER.info("Creating test client..."); - - ClientUid clientUid = ClientUid.generate(); - ClientId clientId = new ClientId(defaultOAuth2Client.clientId()); - ClientSecret clientSecret = new ClientSecret(defaultOAuth2Client.clientSecret()); - ApiKeyToken apiKeyToken = new ApiKeyToken(defaultOAuth2Client.apiKey()); - PrettyName prettyName = new PrettyName(defaultOAuth2Client.clientName()); - ClientRedirectUrl clientRedirectUrl = new ClientRedirectUrl(defaultOAuth2Client.redirectUrl()); - - this.clientRepository.save( - new Client( - clientUid, - clientId, - clientSecret, - clientRedirectUrl, - prettyName, - new Text(), - Arrays.stream(defaultOAuth2Client.scopes().split(",")) - .map(String::toUpperCase) - .map(Scope::valueOf) - .toList(), - new ApiKey(ApiKeyId.generate(), prettyName, new Text(), ApiKeyType.CLIENT, apiKeyToken), - new ClientOwnerOfficial(), - null)); - - LOGGER.info("Client generated with information:"); - LOGGER.info("ClientId: " + clientId.value()); - LOGGER.info("ClientSecret: " + clientSecret.value()); - LOGGER.info("Client redirect uri: " + clientRedirectUrl.value()); - LOGGER.info( - "An API key was also generated with the client, it has the code: " + apiKeyToken.value()); - LOGGER.info("========== =========="); - } -} diff --git a/app/src/main/java/it/chalmers/gamma/bootstrap/EnsureAnAdminUserBootstrap.java b/app/src/main/java/it/chalmers/gamma/bootstrap/EnsureAnAdminUserBootstrap.java index d26140aaf..2f720d4fc 100644 --- a/app/src/main/java/it/chalmers/gamma/bootstrap/EnsureAnAdminUserBootstrap.java +++ b/app/src/main/java/it/chalmers/gamma/bootstrap/EnsureAnAdminUserBootstrap.java @@ -42,7 +42,7 @@ public void ensureAnAdminUser() { return; } - if (adminRepository.getAll().size() > 0) { + if (!adminRepository.getAll().isEmpty()) { LOGGER.info( "There is already at least one user that is admin. Not creating a new admin user..."); return; diff --git a/app/src/main/java/it/chalmers/gamma/property/DefaultOAuth2Client.java b/app/src/main/java/it/chalmers/gamma/property/DefaultOAuth2Client.java deleted file mode 100644 index fd96c7bc0..000000000 --- a/app/src/main/java/it/chalmers/gamma/property/DefaultOAuth2Client.java +++ /dev/null @@ -1,12 +0,0 @@ -package it.chalmers.gamma.property; - -import org.springframework.boot.context.properties.ConfigurationProperties; - -@ConfigurationProperties("application.default-oauth2-client") -public record DefaultOAuth2Client( - String clientName, - String clientId, - String clientSecret, - String redirectUrl, - String apiKey, - String scopes) {} diff --git a/app/src/main/java/it/chalmers/gamma/security/MvcConfig.java b/app/src/main/java/it/chalmers/gamma/security/MvcConfig.java index 3c1802a8d..40c25ca77 100644 --- a/app/src/main/java/it/chalmers/gamma/security/MvcConfig.java +++ b/app/src/main/java/it/chalmers/gamma/security/MvcConfig.java @@ -25,6 +25,8 @@ public FilterRegistrationBean hiddenHttpMethodFilter() { public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/img/**").addResourceLocations("classpath:/static/img/"); + registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/"); + registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/"); registry diff --git a/app/src/main/java/it/chalmers/gamma/security/SecurityFiltersConfig.java b/app/src/main/java/it/chalmers/gamma/security/SecurityFiltersConfig.java index 54b28d77b..1dbc9e627 100644 --- a/app/src/main/java/it/chalmers/gamma/security/SecurityFiltersConfig.java +++ b/app/src/main/java/it/chalmers/gamma/security/SecurityFiltersConfig.java @@ -59,11 +59,14 @@ public SecurityFilterChain authorizationServerSecurityFilterChain( @Order(2) @Bean SecurityFilterChain externalSecurityFilterChain( - HttpSecurity http, ApiKeyRepository apiKeyRepository, ClientRepository clientRepository) + HttpSecurity http, + ApiKeyRepository apiKeyRepository, + ClientRepository clientRepository, + PasswordEncoder passwordEncoder) throws Exception { ApiAuthenticationProvider apiAuthenticationProvider = - new ApiAuthenticationProvider(apiKeyRepository, clientRepository); + new ApiAuthenticationProvider(apiKeyRepository, clientRepository, passwordEncoder); RegexRequestMatcher regexRequestMatcher = new RegexRequestMatcher("\\/api/.+", null); http.securityMatcher(regexRequestMatcher) @@ -118,6 +121,8 @@ SecurityFilterChain webSecurityFilterChain( .permitAll() .requestMatchers(HttpMethod.GET, "/js/**") .permitAll() + .requestMatchers(HttpMethod.GET, "/css/**") + .permitAll() .requestMatchers(HttpMethod.GET, "/webjars/**") .permitAll() .requestMatchers(HttpMethod.GET, "/login") @@ -153,7 +158,10 @@ SecurityFilterChain webSecurityFilterChain( sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)) .cors(Customizer.withDefaults()) - .csrf((csrf) -> csrf.csrfTokenRequestHandler(new XorCsrfTokenRequestAttributeHandler())); + .csrf((csrf) -> csrf.csrfTokenRequestHandler(new XorCsrfTokenRequestAttributeHandler())) + .headers( + headers -> + headers.contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"))); return http.build(); } diff --git a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationProvider.java b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationProvider.java index 3ecb627fc..5e1115c60 100644 --- a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationProvider.java +++ b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationProvider.java @@ -1,8 +1,8 @@ package it.chalmers.gamma.security.api; import it.chalmers.gamma.app.apikey.domain.ApiKey; +import it.chalmers.gamma.app.apikey.domain.ApiKeyId; import it.chalmers.gamma.app.apikey.domain.ApiKeyRepository; -import it.chalmers.gamma.app.apikey.domain.ApiKeyToken; import it.chalmers.gamma.app.client.domain.Client; import it.chalmers.gamma.app.client.domain.ClientRepository; import it.chalmers.gamma.security.authentication.ApiAuthentication; @@ -10,16 +10,21 @@ import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.crypto.password.PasswordEncoder; public class ApiAuthenticationProvider implements AuthenticationProvider { private final ApiKeyRepository apiKeyRepository; private final ClientRepository clientRepository; + private final PasswordEncoder passwordEncoder; public ApiAuthenticationProvider( - ApiKeyRepository apiKeyRepository, ClientRepository clientRepository) { + ApiKeyRepository apiKeyRepository, + ClientRepository clientRepository, + PasswordEncoder passwordEncoder) { this.apiKeyRepository = apiKeyRepository; this.clientRepository = clientRepository; + this.passwordEncoder = passwordEncoder; } @Override @@ -27,8 +32,14 @@ public Authentication authenticate(Authentication authentication) throws Authent ApiAuthenticationToken apiAuthenticationToken = (ApiAuthenticationToken) authentication; final ApiKey apiKey = this.apiKeyRepository - .getByToken(new ApiKeyToken((String) apiAuthenticationToken.getCredentials())) + .getById(new ApiKeyId(apiAuthenticationToken.getCredentials().apiKeyId())) .orElseThrow(ApiAuthenticationException::new); + + if (!passwordEncoder.matches( + apiAuthenticationToken.getCredentials().token(), apiKey.apiKeyToken().value())) { + throw new ApiAuthenticationException(); + } + final Optional maybeClient = this.clientRepository.getByApiKey(apiKey.apiKeyToken()); return ApiAuthenticationToken.fromAuthenticatedApiKey( diff --git a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationToken.java b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationToken.java index 15655dc30..4dc208bd1 100644 --- a/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationToken.java +++ b/app/src/main/java/it/chalmers/gamma/security/api/ApiAuthenticationToken.java @@ -3,31 +3,41 @@ import static org.springframework.security.core.authority.AuthorityUtils.NO_AUTHORITIES; import it.chalmers.gamma.security.authentication.ApiAuthentication; +import java.util.UUID; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.core.Transient; @Transient public class ApiAuthenticationToken extends AbstractAuthenticationToken { + private final UUID apiKeyId; private final String apiKeyToken; private final ApiAuthentication apiPrincipal; private ApiAuthenticationToken(ApiAuthentication apiPrincipal) { super(NO_AUTHORITIES); + this.apiKeyId = apiPrincipal.get().id().value(); this.apiKeyToken = null; this.apiPrincipal = apiPrincipal; super.setAuthenticated(true); } - private ApiAuthenticationToken(String apiKeyToken) { + private ApiAuthenticationToken(UUID apiKeyId, String apiKeyToken) { super(NO_AUTHORITIES); + this.apiKeyId = apiKeyId; this.apiKeyToken = apiKeyToken; this.apiPrincipal = null; super.setAuthenticated(false); } public static ApiAuthenticationToken fromApiKeyToken(String apiKeyToken) { - return new ApiAuthenticationToken(apiKeyToken); + try { + String[] parts = apiKeyToken.split(":"); + + return new ApiAuthenticationToken(UUID.fromString(parts[0]), parts[1]); + } catch (Exception e) { + throw new ApiAuthenticationProvider.ApiAuthenticationException(); + } } public static ApiAuthenticationToken fromAuthenticatedApiKey(ApiAuthentication apiPrincipal) { @@ -40,9 +50,11 @@ public void setAuthenticated(boolean authenticated) { "You cannot call set authenticated on an already created ApiAuthenticationToken"); } + public record Credentials(UUID apiKeyId, String token) {} + @Override - public Object getCredentials() { - return apiKeyToken; + public Credentials getCredentials() { + return new Credentials(this.apiKeyId, this.apiKeyToken); } @Override diff --git a/app/src/main/resources/application.yml b/app/src/main/resources/application.yml index aa21f0911..897e05122 100644 --- a/app/src/main/resources/application.yml +++ b/app/src/main/resources/application.yml @@ -61,16 +61,9 @@ application: cookie: domain: "${COOKIE_DOMAIN:gamma}" path: "${COOKIE_PATH:/}" - validity-time: 31536000 + validity-time: 2628000 mocking: "${IS_MOCKING:true}" admin-setup: "${ADMIN_SETUP:true}" - default-oauth2-client: - client-name: "${DEFAULT_CLIENT_NAME:test-client}" - client-id: "${DEFAULT_CLIENT_ID:test}" - client-secret: "${DEFAULT_CLIENT_SECRET:secret}" - redirect-url: "${DEFAULT_REDIRECT_URL:http://client:3001/login/oauth2/code/gamma}" - api-key: "${DEFAULT_API_KEY:test-api-key-secret-code}" - scopes: "${DEFAULT_SCOPES:profile,email}" gotify: key: "${GOTIFY_KEY:\"123abc\"}" url: "${GOTIFY_URL:\"localhost:7000\"}" diff --git a/app/src/main/resources/db/migration/V1__BASE.sql b/app/src/main/resources/db/migration/V1__BASE.sql index e6ab9383f..febf24d11 100644 --- a/app/src/main/resources/db/migration/V1__BASE.sql +++ b/app/src/main/resources/db/migration/V1__BASE.sql @@ -114,7 +114,7 @@ CREATE post_id UUID REFERENCES g_post ON DELETE CASCADE, - unofficial_post_name VARCHAR(100), + unofficial_post_name VARCHAR(50), PRIMARY KEY( user_id, group_id, diff --git a/app/src/main/resources/static/css/login.css b/app/src/main/resources/static/css/login.css new file mode 100644 index 000000000..307023710 --- /dev/null +++ b/app/src/main/resources/static/css/login.css @@ -0,0 +1,50 @@ +body { + padding-left: 0 !important; + padding-right: 0 !important; +} + +main { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 1rem; + min-height: 100lvh; +} + +article { + margin: auto; +} + +article > header > h1 { + margin-top: 1rem; + margin-bottom: 1rem; +} + +form > fieldset { + margin-bottom: 0 !important; +} + +#links { + display: flex; + flex-direction: row; + gap: 1rem; +} + +img { + opacity: 0; + z-index: -2; + + left: 0; + top: 0; + right: 0; + bottom: 0; + + width: 100%; + height: 100%; + + position: absolute; + + object-fit: cover; + object-position: center; +} \ No newline at end of file diff --git a/app/src/main/resources/static/css/main.css b/app/src/main/resources/static/css/main.css new file mode 100644 index 000000000..fba39ebc9 --- /dev/null +++ b/app/src/main/resources/static/css/main.css @@ -0,0 +1,102 @@ +article { + margin-left: auto; + margin-right: auto; + max-width: 600px; +} + +article > footer { + display: flex; + flex-direction: row; + gap: 1rem; + justify-content: flex-end; +} + +article > footer > * { + margin-bottom: 0; +} + +div[role='alert'] { + margin-bottom: var(--pico-spacing); + padding: var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal); + border-radius: var(--pico-border-radius); +} + +div[role='alert'].error, div[role='alert'].error * { + background-color: #FAEEEB; + color: #333333; +} + +div[role='alert'].success { + background-color: #D7FBC1; + color: #333333; +} + +#alerts { + position: fixed; + right: 1rem; + bottom: 1rem; + + display: flex; + flex-direction: column; + + max-width: 300px; +} + +p.error { + color: var(--pico-del-color); +} + +form { + display: contents; +} + +header { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; +} + +header div { + display: flex; + flex-direction: row; + gap: 1rem; + align-items: center; +} + +header > a > h1 { + margin-bottom: 0; +} + +img.avatar { + display: block; + margin: auto auto var(--pico-spacing); + height: 150px; + object-fit: contain; +} + +ul { + padding-left: 0; +} + +li { + display: flex; + flex-direction: row; + gap: 0.5rem; +} + +li > * { + flex: 1; +} + +li > *:nth-child(1) { + text-align: right; +} + +li > *:nth-child(2) { + text-align: left; +} + +.form-check-input { + visibility: hidden; +} \ No newline at end of file diff --git a/app/src/main/resources/static/img/bg.webp b/app/src/main/resources/static/img/bg.webp new file mode 100644 index 0000000000000000000000000000000000000000..66faa6fd1a56c84ed717e4f762950d7714acf002 GIT binary patch literal 150426 zcmaI7b95#_*Dv}c6FU>zw)4ccZCexDnAo;4u{p7A+Y{TmdEax_{mvif+*+%;e!bOI zySlo&s&*?$iissig96k=g%s2jI5l7Z008ZGo`wXlf&(Olg%$EZzfS?6c{awjPGF1x zfUTXgqmsA~p@yawA>=;*C;%6L@+|;uXzXM!sGuP8AL;*ddRzj4{D(77_a9sTXPN&i z72d?u$ru0tA^esQFt&Ge{>BF1nBC3U{y#YF8>1Rq7@B?->|WTqwTj0>$eQ4iLKqYeNc`6g-!m0z5j!4 zZCt+V_TTiM7Q&g@sVaY$q~94AAP$fO$O04qga9Le3&0X!18@e=eV2CM6eobvH(%)g zqL2MweT8o=qi-!sfbqA62;djM7GU^aeZYVE;9KT9{f}>*%vhNJO9Fut0sz3bzP|3r z0078D0N^9;>+3E5>+7Qc0Qj*10QA`XkN&Sb0D$x1n;!Q+G}2rE05KQIzPUTpk`(Oz-=i20IvxEpv(XOFxvmiZ{NKC@BxL(0D#K3uVf|x zfbZ3w1wEf8?Hc$9tE){rdc6PjE=E(!KOr?`QcH`*=0N(eGFORq^Te5jvuN z&hVjsqo0y1n_l7PbqaFiH0kU0_5QW@Dd`RJhVdo;iujn@xGl*j_>i6J%jCC9qxLSA)O$_2PT( zclF}(A^jzPRN7zj&+nSwf%oO_!-oX_)T{67?klXvtgnl=xnIK9{#)nu?x*(W_Sc6J zf0*CfedaC0tGE99)jh%WSN7Ad$?jdh!=uoL?IYjLN8vBT5Wg%xihp=7zwQX0d^PTt zwovoGGVTY;{Pvx_%o0EOU$%Pm`&H81Bu-1?FgDb9H7r#iJ15gL7Pe4#2N)RVq() z>N&CNQL#?dQ1*BdPxAZqgeGUpmHO$t3SgXI@rVs}-#3L)P;GPvEn#D0e zF8m!X`4iF`hW6)$QrFvr%bEqNV|!pLM9xLWeV`y%*6J^xvAGT-4(}T~I2zD_gBSh`iY9BXCKLsECSp&C}G;{zwn6`fo ze=SD#2*@Ht#Pbjf^x|VAoC>Rq%FicOT*dZ=KrCNxdM))HWGH6oqea>vFv7RNs{A!Q z#rM3ysdeLIx6fSo*0AzE46BA^v1Ql3(6HElHT=SHplK1}dWEbh&CR%xL^wlA;wr%x z$Y=YT;0s!VbHPLgqqhDt6R?vMc&Q}EShK?iG?MYp?uMb#ZGlVNUmNKUI7Drt3_sr|m2})NM8CMb@ z@Z%PS*9<9jMNGV76~^ol*8_Uz zjM!J5i04(o0m~cfJ%O@b6#xEJx6-un;>A81CigaumHxRi3dTSlI!nPkb9{nvIeI2o z*O)^L;?b_Ou$UVb71ro2mWlI{@V$|Tmn_I zgT2)HTj{u|B6`QLMQJqv_jV#xVw`wCsRsE#Z=N>i!F3sfQkTQX=F+CtAr_Id^0sY+yu3oOgjW*di7n74V*@=%^gw%h%x--;^!CvrF@)m(E} z7*8ISfkk9@Ui&bn-CMlSeSTKU49JiQ-E$%R>D$5AtF08Bp(GiCzth$M3^IR14@7nC3K8VFKKzwuHfd0m^9>HYP+eN!n$egCYVextT2OIjn+(|X-avEQV8H|uY9=^EV{+x zU2CecSr(etLL+JO|A$Ow)(e)n`}3{~cmF z__od+kFiP`LVY4I^1}n&VC!8C6x9y$N=8gY2-nfPl9quk3174_d9mcEpO{d{+8)9Q z2qERyQ35UIm1Mj^KaP8LYZzsWIm8sj_siQ(AI0n({uHsJw8>e&c(a<0IsCU5d*^bo z#AL*Yz4_PW?RT&FQQsbVlh8h^8+BNv$N`ygE)eE^`PW?~-oa-fS%(cJ+SG^hLz2Fv zKJP?i5tQsCTdSKe&w~*~SaFG^OpWfLLj#bu|1FDILmx4P5$b&KL>{5|(RT6rG-e&o zTdQO_rmDr?Fcn~906Jk}P!zLDBpBJ$pW-6Lc%7)=%x&vo60GkLlNP%&rxqU3)@`h{ zmKx)#(W;O zu$KHPjU4?*Wjj>@o8Du({oyUKKp)25Tie5LZN=q%_6nkonA-@)p@nHcp~Sm#k3h`; zVGJjeRXpZx`kd(1`2p^)jc}GnM`e&Dv6^-uzp^BxOc2lXOP1RiKw4{4 zT4(6eYdJlYBs|im&V`Y8#xx{VBR^=m@&boAjbEgS9ZjXL#vr&M7?3tL1$ASBYTpJ) zz(wscFkyjlWeQBh3t7CMwO37gGo6Z6UzM4%v`t9{%r1^{H{b^mh_LvJ^R*~qN=a0* ziB_hfYWNBgrCfQJPAYoLW7zCjgyyVI(CWA;&ia{-bykX%LgJ2iEq=xlw_Yb&rMqS6 zyhSctxp0>ASG(X$-2|I!IwB?KQZGSqp`~Hxn=O{6i}mJ4&}n?$^(hWR8Kry^&Thv9 z!Sx4iK@86qwrgu)|4}U=u4Mi)+p=oTrIYt215P<*bss%_4=u~BlPRYhg(_QHHrg@9 zviGE}W-3H;3b5AyjL%2g1((-Ic|176M|$P40cCNXC9lQd_Z9?OhX>hOa?(ICm5j^g z9&A=IW!K_4DtfmjKF5%f(9nFN_^iHmeNonOP*GU^+dV$3ps*G4a_f)8jrT*j0I;B=i@sa(3`Or zDS&!!?G7FW4uoF#@mZ2#x0@sUtoA1l>1t?I4^hU;+ju;k)Ii?Ys9>@l7O_=^>`8ti zytdMP^e!pvo0%Y7*AGWZlWv8S$LRWlxdUm z6yT;FU4P`zCT?i#pHX~w#-iobP$KmoCT)FAw4{n7!Ls=~q93|K-KJ~p5KabjygV4( z)4@VW#RXv-FBN3^kk4tPdj3#zOVG1)m`Nl6zNwBt7|H~@?e>}j*sm|QB*r(j6Uv~R z2nn>Yg7LsEIf^deh}Yd^_6nh8s4qX8|CIBln4?08g3Y1PfBI(JwkbrcK5j~YFd=>Y zc}&?)9=!oMMGnIK7a3SH9{pKcW*Q3mSTkIoD*VOV8vV?RF0n?2z%3T#$$4W6O#imK zB$B`^6DPLiB}w0v8)hP5(C2Y{hQ{W{mWTZwbM)YaBPb+sxxtq>crdhgAI}`G#j3rF z@zv4-3BE!#w6Bb0%q->IjV{zzGJ7IMI66O2I=^Aha)vk6F&%t6fg?k!yYiNS_qu=q zdhmJ_%Vb*H7_(Vqiu6E?Qs0N-LUq0Wu4hnr*#?epPaotr%CS(`M4v_S+B;b_Vo$tN z4*=N_`iQ0K+={$5#PN8!W|O;CkX+2`DE^T6FX|7i+OK(palL)T0<3B8X-St_Dm7#K zH`+ys#g33g8*M3GNOYu(2<#G>I)=5X8(aJ%zH#$62;#hb$sxT7mz{vRVLQe&VP^BC zljJU(Tiv%_1Q^3dn+u%1@%BdO>vHp}=yebeGbo`qyWM*-Ftdx|FP3 ziS|n12kr0n-|23_QFXd-zh5#OyV&wrbC?AwV5~?y@sfctk~>w^R@1-r;sG=iL77e*;vMhjMODvslUVhMDgBKd>e)E zthfOIC`bQZ9rX7{y>RBNa6RtA_@qfb`{68?@+X#2VFIaA>ZMn@3@vM+XJFTDNQEUU zD4HDOyLdINXj$xzNsleQBn%p;cppK<{*5ad=IE0i16K$NC407&Gdw)Tv>PPfXVvE3 zB1(kA;`gI3Z}L2xYmT>Y)*Lb*L_z;t>KyIE@LkZ=ulEYd*ctMOa0jLuIi>^$U4FzxjF7ouKWNtI)MxlUYUUXth{~c zPhigDP4=+Bu58q^I~y1|Za;TEQjR)0!YVyBJ<8;wxStwZ9vtN8mj5V|-%gJ*M*oQ^ z?9iy6t?{5rc&(M(p@OhZzG>c9I)Ip19_#;+Oicbmr!(=WAr~{4+ppFu5g$sCRr}2G z1*0S;K@cX3iD%(U;U_#J82yQ}xNt%@8|l1OfWU%~x`;&g(|*KKM?WmQf;zUblk(Q| zvV}SISc?Bek0uN}&){37; z6CJ0K0|MHvSh6DM>)Wz1=5_0U{ibO9of~x%uh+=F4`sLz9gNtIjyB1MslvhYmSr)^ zxz$oHdIKYD!h{WDkx1lah?caCP*)bnM34TLDr5`dqQzHpOo;d~kH3ratm> zLqO=hOD`!-rp^~%VSPz`;-rnvsr8@I%Zt)G?{G?g%38w7mA$m00IejPuc!?lJhpSI0kV!!HK+{wn!hypjUCKX|XqX)mKTVi#y=|Oj!`dGGb;htZi=W+YaYIH8Rew^Kn;bPUhD zA^W?N8oDI^M&MdN9~$0m`FFG1U1B-Js*32B9A1fnO+oP5UHv%BuWNoa>{w#*K4 z0VXGOsyKmk^k>@6eMdGScnHZwYcMEGIVY*8pqjYbK{XTfOkrc{WrR0%)6tnUb}K4j z5r&NPZNmU-E6bWgBTc`$E)fIK7o7?o@12#Ug+-$#kuuss1{ifZ*DY~(u)nK04+-8p z-R$h^uJv6nVL!tJ_%B}Jy`M=4KuqAZ2&d`%?NHNn@D^GGMHCHRkD;*ZlGiucFcqZ) z!Km5!AuJCrP>YE0r(RQM$9Hj9pKg6BHnAI8#o-fD{X9+Ck9Q~0lhE*mzamY%H)0uGV7LpTO6U_RQD%hlVDQrCH!3MKPPf z%4yKwAq^{Es;{EKZy`Nwd9p^KBUWua`}UdF*Ara3qz9sZGAHYjLc@V$LDv#@SMWsi zYu(RI69359qeb}I6YN@E4wY&~X!z&W&CK80CzPMyWqCf@--QMjItJc)ha5}WA!sCi zHQtFzBZK}z0~7V;ve_VTWK^lo^e9OT{%rPT5RKo5ltV^T(boJ^m{El>oVK(4FUd82 zpeR$1B)Z}>WnCL`*6t{U)Vj10ILWf_U4@wXJw65ciW)@yC*=_X-#Myr$4t}SfqG3$ zEr-N)$tpVnj_2tMFb7fKgz;V&X3`?b%vZp9zmLK$i41E>GUpjJQ|d_?$5jLW*WlsY zDZ>%&VM1(JwOH@TN|QJOoe@Sp-X&;1x5AqWa)lWiCC5K?!h8?9!MKj|$4F|yfBqfC zEPehJ!BOd+0M!nyoxjV}38dw1VY2}?2f$Y3>M+*Jjp zd$hkqVua(MWGBV0T6XkTg?AMrWuDWP%SuUSj95XVgg`rL1cRqrc7}g_>Lw{O<|p+m znV=0E-W9h1J8Uu9%ptT0iQ2v_XVeO|o6Nmmr{X2z(y>rQ-XJ#A=JoxxDnBu)u*6bb zBlK(UD4n3rUY9#LQLjhoAABJ$pu2yVOGaB2<2eN(i2UjFcyNZUgrMlIKggICb6Ch5 zIOTcQ08?C0!mnJj>jJhuwo*x==eKSib)wdDFQ?QG-rC$2QD^<}tNxVL9@u}PagtIs zgCug}yJALTSYgy^*~##Nxy}>yCw5IT}o7LSsuu3_ywYoM>CPM z6LwtjW$4bEW>6y%$EPiR2C|J_A89sV*>m@TSmv1uSU0JGwH$#D`mBlx5fUnkSR$=$ zY81Yw2Y&KsXs~H6X_H87`c1!j&$vr=N(x0iUqv1M2-+Wg%F?!?oJ7nSE1(yNNaB7~ z9;8GvT5Am2YN60{#^oXN*i#(bxQW91lSh>Zwg>HoaBMQ3E+Z)`*Hq4qJmhgCT~r{4 znS?@FT@I^X)lw#ukYEg-2|f>jtkju`rL}Q0pcN(2tcpBI>%|7s`sS5^Pe`T5TQQ$_ zqMYtWcIfIqP%6dGctLbNMX&+35D4a~bE`V$-_MyG{zfh{C?u}d`dD$xCeneQqD!F+ zBd%T{gOTn8A2;04l_1NYj0|0W(h6?UnWt>MSG+Tc;5#N_+ zC-({x>fRUqr(Wtej;J3a+ePr2mD()>)lfQ%>^vVQ^7{{~gas#bTemyE{-4*sXeZ?X zH(14)V)2!j*qzprj4{o{8GQ+t7{G%S*arNZ20TE3s=|6OwKjs~15htpp6Uhi>Y{Ih zyl>pl{_HsjKA>`;uQ$J~kfSe|t3{Ef)nrg;wy{FD0FPScSR;-C->=oxezJz)xt}GJ z_0C_AlZQ?};4C6(B^5FzPZjX<2fi&yFH5K2g0A%jHIz{g4klKA+){goKJ?w`XNQ-@;Zg8~-#+P+gutOMtV z)=LL`^g#Y-0)4&2Lr=;HUPr0x$jhYqfoU1pE7aWV@}Zxh&n9$VzyqjCckUbp_m3k; zI+h~n>b8P$HXh>hO(Rww|DEE*jGXE&Rk}B3xcb{gBdDcTK+4?jr1;#Y)4K<1*gh)> zSXVd~TQP+FyqTCzJT$nkg-4HRPv5($)Q@_O1Kas3<-N=yi`J29kDCphng?swGVpe) z0)tlp?rY4ANCQi-kY*NAt>8qU>##rmI9{d!S|fHZrAuApu^Q3cnP3P#7Y&x zbBmJTt<~*+d${|)C&$$9iWtn5r&UOdN|J%Zd@6_9@qZ$py!9#m!u(n6PZXz%|6})5 zhwRQH|3OQ7J^&X6Gl*(e8b>W*wOd<`gKrrYkxf>G3X|%utaeC!e18PaKufl>c~H-^ z9oh91f<2Pp1berk&4xy;0@b}z?iVbRcV5IkO-bOJ5<^2~2j)iJKE8q02IZ0sHD z(%&JvzYI<~UBL)IBd8cQ-ow`6Nq-R+3vES>;plx_$VRfY0OE%aq?$bI{45 zhZkHREhmTA=@#1$=uyhT#X;EpuTPXo5|{z-i&3tqG~NRU+3+{rHIF{`3}OMmX^`4}_?bsZnd?)!b1pPM8`SAQ)PU+n){|Hr55^&GtuJ5{O$h03?+ zwdeU^K$P*ve1%62av0i}7zmg^4l0%XTxXGD=Ah`l`|%NGtdmG?lZo%=HVPGN;$@Bk z70Yzfv-$WiUvgV^8sicSA2LJNSW?}GG5F)0g!*BrGJF|ia+I~sfdu*&v zSgSYhVbaK!^I)L0<}O_xpS>pI7$v8SzJ_2+j%eC?KURNtxXk&7#68`GF=&L*!iV#A z((+)5IAMN*nVw7EmIxhZwMGo>s=4J9ZK17j8Gwu`D zzJ#nekX9=|uk{_j5NL07EJ z}hs^R3RdC;V9iiA!_BDxlRd7WB3Pg{S<)6kzq~qKBI($Qzvp zux-E0gu1&OSrw?OrLTm6St0N_9Qyv3lp(Yb>0dG(4vdzn zK~bSC%Q^m3_%?#=p49WhKOLBHHSMzU{8cm~)3j^GJ&Wh#G^zIs;wQsbsC1D8DBi7z z;wmg2Behf7u#YP2pTwiXKIY^$dy4DA&-P-mX7T)a>KXi4TtBlQVcFgxftYS0&9j_cjf^eh% zl1j$N&ZE;$=6Cp%0WU-Me|^FZIO`$588blp6@draYS=gy#k~T0Hp68c4x;Rt(sMji zTHGMuQ?18(WxTDjeyIOq!dylU4Su_nE&&Uj@~S!dC`6TU>%Oqf}#JKkb)>e>1Sk@&?9#6Ei3@#*k z^5@&|t(_xB7-Z3(=K&bt{_kp)4m??ta2j%n#1@YHg}QT(s!?qgCv$ZWJF1J_tE44T zpT-}>tb3MhQCvldI!jFJ`-Fl9+mj_bOUx%hhRTP;m{aJ}kr+UntcOjcaG5Oz4Q)jT zvAb%>N{yj71g6DEV%xLdad<~jWg2*zuJNERm#;|FBhf=sM4l*Z1bw8vZARTh4}bGXr_aW@O^l9n zGFD;2d?O68abJaid#S?1C29D^Us03om;1A2HpEWi@LCA8W%7T|c-{i>Q8Lqef!$d& z$cL+0W90cyf#rfKzl9Az;*spejZT_5q-p-8)!0I%f~6iH7Mw7r4jxs()3>uRb2Y3M zc_VDSZ)exbj-fV>PA*dau)NPbPK94QGgRyf$6_-LJ080UkJC6Q>xDdz_VzhQCMI25 zT5SMhC2Pe{T++`#&I4uAR_}llAA*X2Hq2SX;@2!Ysi=xkxhVBP@kisS zoY*i!F^Op)iLwd^IV3@zqH(C-HY5F5TrNRu=8d}#btZQ*B@sRDk5rgnU1XkOq7K>F z6o1dhR_$irADrDieEIz7Q`A-NIoyP7Jp^q-;KHyI>gxK%)~vj76!THFw#7j>O_Yqu z-kafdltx)AH)>Ti*k~Fw92D1qTm-N{u?ruw%7GlH8%S**sG!-+Tq>9?HAk8B8! zF=tMNUD58@4FwHOs;+1-@&0~gzDiW)lA!abH^; z`Qv62ibQ7divuj9y;Bk1F0Ga*sMD?Eb~_wNkOC`KZtV4HBuPJOzm@$92rBJnoXoPl z=9D?lGI_$@wq-fa?O+Au`;5?nY$)f*0B_*2nFJ#rsjdu9VVOtrpRif z4aJhrhrF}KNlE1KW0+%6ySc=h(D+c4@DDn4I~l&>tCgK~YPWq5Tb5pFt6Xoql=P zHUhSpmsbk=zF!9(d5{c<$kHmL2e7_qqj!0*F4vgEXXqbC8#kB1gMN5Z%J)|sks9la zL-;=P(AsR-+O9fR2Xo2c(Nson6uo9lHDjK!RMtwhjT@Xb`68w9hBf2SQk~@1A#ao1 zQk}E8w#eu~>&KZUneHb{=D=9rnyyN4dYYr&{JOq8};S8>D>_rgeIk<2%C{ zm13jyo-XIutJ3&S?zus$VoXV=l9NnEBe6!^NzL)~!}rj@ z$bQpRQos7_MZ>b&+%{k90oCNHZ{U=8D^_kd)KNq+xWG}D{!J7Ns`pr2gD&FQxTuLf zGUW2j7YpulJ%Ti*{?@&86{qyaFd`B%7*6XkULe7k@?GDexMwtx05iN&j@|eUn&<>W zC@WXxxK3lfn7Jvx~Wfw+72u@5rm=;8GSFPCX%#9W>d)1q7J$+d05ifOm*B#LiNZHHv6rY|;Bk{_%;0+#w&_7dN6k>dsnSuT{m>Jt8;8kRq-SPUBLosQkx zc-e&H>SSWBBF0!f3$1qB|om)fXEDUNV3pTYiXDHug4_14d+Y=OG!#g8W)GJ7l#CZ`ge6rlh zT2uKr!-@QihCJ}$!!Q=}X&+qY<2Y_oW;K_pP|n`?I(U%v3Y$Y+A~IT+ z-=j$Y^T}db$w~D2McS}ax72X`Sf<6|+-(-RI&#mjqMkw`zUu3rXM?un-I##-0$Zx# zixuzZ>9hO;k`#ZJ2s1Rc22R0a*8g9gj{^6kf5$Tk)HajM?bWDvc9R9-!6#DkOy}M{ zMC@3gskUNp_*XTi`1f+N0tzsCl%?}j4au*6BRU1u$+^>RnKt)0dVA`x|1Og@os)9p zek+fp7VR_-5PhP=cQe-JEZfghr;0Ne*&FG1(#@6k>b zsC-FSbPmJK>moGDGUNMRq$Cr0SqY3Pq)GSY-U7jkC;$G08v!bx5p-129dZ-F=TN)$ z2^fx=R{zWA;=@sM?%8Ma(EHdP=qP*Pm!)DKF<2=LYR~>GNmI zkTBWS{Bbz_>ALO;3W!Nr!^u7e4d?9vtSi2FX?F0=sb5vOuTZw=RXIEIy;-0XgZF{N zt9>f4;OJB(rijF~AbY+nEZm1Hxy;rZa{^}=HD3N3RM8HvNZGJG(d}z4{L(j%;>*PJCkQ&kN&Amo8zv{ zwo&kg+!e!Gyo)N@b2A=}hjyQM7!nA=j^RLUO7qUQH|JG~YdvDEqq)HrfA7WkQq|Omk`pRKmVM)osQKJmO)XmLt$)r%)sChf^*{WgIh@6r+YqWK@F zO_L*#qo>Naeo*W9gL|S0r%Vv+sT22a=2N_lf|wv)!+g|xVs=|?4Ka8WS?fliv&#{x zWjhkp{)Pa*%dW#68P!&!RK6+TYmy_$PAj1@ndBeDzbz{Z>ei?O2CDyrN3!^4s>E+{ zBG>?cli!^FP>t&`kxt(jWShudoARI*wH+aA)!rJMYLo(5u z%`M^rL+>s(<_Fn~w|lMs{mZZG33J^COm4K^Tt+0k>bs7c!g@+l`Wuunp8ieuK~K4- z*e#>$UohGjVF>=SjH?m!Mqbo@H6WH>@1mS8m_6_0_nP&EagO=Gx&AUAY44x6IM*9Nw!pMmns%1|__|ZeR*n zLcLh{M?~<5$WPqwybd~S63e}q(a2h z)45^=w$Z4`$=Q1=gaFRu2bo(X5o}}CCJAiVBwFRVwhJ2SWbR~-N2u>rPm+}c(!K)f zjgWKYw40!5QKw@nnxP@*3T1TM(g+!rC|f3zh&NO~wTBuU$Ja^1N_v`JKm?ie_xpeh z56V=4+YP%}VCyewUa-6*qi4hZZDTcbQ?M$Hr*e%spY&ME(z)2ud4z-<78@qxBrNWq z`iO~wkN>z<0tat0a?W(@u*SWsjRU6`#gFds=SDTgV7ZOzfpI<=90!l!`tZrC81JqN zs4btdqx+%w+&7SlvcsK_ANFxQcH)L4zHRBL$yeQ(b^*&3{+iH9qs~4XmPRpgC^)>- zD4zcF7_{PCT-hQ!)!{rRrnq_QY*X*p2m!(mQGS^fDgN1FQ{(4-qnj@JS+^btQ#F*T zVz>mN`AVTW#$+b}dHwRB0@tEqYSEi`nSafsf=t|WK#Sv~c+8gW& z$f57(H(bWKX{x);PS)?Emr7M@J!^tFTfh01(fNrz2lW-q>%J_+ci%}FxbDx9s$EC1P;9lXaQ6+vM*oCwh< z{L8seCA49FS@p`B9(QXTr)upV5PqXXGo(BQMA)&|w`?f(sXNAb%)Iau<(c6R{Dq|! zVP~XjiZTK<_>~=EwW7U&OtQTk)_oeo!@{(zlK1LIj7JiM(C_e~M}^s&&4NAc(`40s z!51VM0EJf*N4<jf z1;CPJ@?cS=m4nj{DfpS9RmS!AlDNEk+z8R%d|{#Rouv9p+fdInR0{Xcu&=?8*rK%K=o-n$ zIGsS~r|@Z{d%;ovER^FIbjMhof1|cHi@WjcRA;f+w!o`rzxIYreDWfqk}ojKKx9T< zlpQ!F1uMTNKdtFdLWQktv^S=Bl=`J`uFrx$v#d1%viQ^nI_IFNKvichr9rYUp$S|` z5UX+-mriCx@+l=HcIcu%-L<^SCeD}>EN#JoHVjS_rQb7=cnH48>G)nWeM|5rtWy+j z3azH^c~8)qg#UDiY9z#l>3=w3h|o0AR>8l5-?O+3?N>r$K?>|64U1)*v4A%6K^}bI#6#u zNh-^a$cl}oU;oAC=K#bjx z`K-tQU$6?%DFSs0y`fXw0XAH%e4!d4dB$U;_P4VHOXdn(zPK~nDeuEBk7+Ji6#5KM z55!%^;u`Df#qiE?zHqOPCOMl|+T`z73dm(@tTH%Zmb#yZ=VLhsT?~ec#qro&&67>(Ct(NG6YR{YR5Rx6bSGJFm_Ju5yC<>j`8F=M4g%`76_=cVy_I_qDDRCFU|kt;usiwQn{ z>w=xtY%IID&2~toni3^J`0?pVaaKwh%;B8 zj_HKMA9s#bRwg9}!0D6pzwQfa96Uyz>5-$KWcxw=BIoI|J4N9qCa;ppyfc6fYajLg zhsEQR1C29+7#0t&m-wTJe#@+>pFJi)3-8ymh*o@eVS%Iunfy#=A10Cu#&3SuC6d$n zL9(76t$fr6Y9L-fp00}%5xyIz_kv-VHpno_QQ!f5ShqDsy` zO_fHM!tQp>JDbz>b(}C$yAmFX*?JAUDCErY)OR_v2kst*5yZlHC?S6wPmF8Xq-A}F z6&~(~o@+kD?FVxw4zy9|)$X;3v?ZJln=;Eux-1g?qMnby1s!yQDbyEWBYnb$9aP9R z$VJJP(A142S=-bpmX;RnMxcUv63I7jR~L{SIh( zOp@&{yGS@)9F)%=#z}pz#V0IJmhDjnY%5X@o}WSvPVVYTCxO02S;$tlO|yeptT!7K z`y%s>LtrzLG&%^8?DP*Vfz%6roHEnbqc8`h{R>Jx1U}MhxAoC)9$1}}5V84wj(s>* z%RQ>B+Vb{h&Nw_{c%F!V)y#xG!^jSOoToRm6|`ka^caym8Dct7aK9G^jH2oEQizbU zWy(-YJb$MjB9d2dc*f|s*fr_B^A(t|5{vwWP2^kQTM;4$t@$cx$U(ncKpAxSWf@u^ zD~a$u{hB(Y;$NIt`2M(J7R#^j*>Qwxr(8VQt?CX<>Sg-{Zldq)P2gV|0h}nuHz_v5 zWLDaZ=sraz9c$7`MTOvu|9Aad4iQKcx6u-84SV}Xcq1KUhup6EZynX&rwaz^Q1e&O zbK?(XiU=t1HokBTut;Ny9HT@~8waFY6L>JDsZp8rj<_RhH-Q?+usX44`-us$))#l; zu?&W4EL)WKJp)shM;I=0d1cCx5+|RN8g9t(P9MMQ@ z+h3P7XnXbRUi4Q8@iF&Z=?_jNe8l*_*P}d0%JZf3lqp_$BRF}zg)9*fi~p9be+hkxQic(H+PZBGOA z^8R|ocJgNzG|PKZX>i1t=+|3?`W$(w;8qT6e*la`5$#9)91k<%jXY%mJRuvwtd$Z; zTX0abc)Xosf{34jTS6LFt^Zg?r7PACq@QX~3kxz=<3?s#l%nO+Pxj3J8^5W|p&` zo-IE)(I2zn6;e+uH5+%KgH?MGZJ!d2Ic33L$D-D*QuMOG)nXUXGku1;A=V6=1RneG3YU8*krDb z!f`cuHy=mk`N_1A1(uL^-odm2e0F*2&1d?#3Hq0yi=KTob4ODx*$$JHWAmFk1r(G- z**m@JePzV(i@X6X_d1hQV_xi52U?7ToWITrq)0Z4G3bwbb^W&s;$#`-Db%+-S4@pZ zxjoN2wdDrs|wBM9+XDQN+2_1goV5^|=MjhmBUi%n*m~}Ntb`n!03??sn zN}>t9-yw{-P$j4DM@3OG?}!&w{=Sbqw}qvmD2DSk#O>}*Gj0^EkKH-;-9IjX9twq3 zT^H5HMJMQDDV)=+9pN2rA)j&{N3T!@^yVpS*$W2aM=SA2^EAyX92EsCuq&J4LTE34 zKYYo^f`x2)`KebIykrgJfA%){|C~Lwgrbj?83`4%Yrp6}jo#13J~|I-YmYbLFrK>+ z#UgdHiwwap7ucbvn6!qurZ$f*1%IpYzkc@b%+!?h@zd$#b};r?*wa)k=#H)(Xh1c7 z$<7X!2-C-$t84q4){(KsO5a1hxPVmrcX*i-)Gm|l8TY}l3`UJanwnflNpL?m7Mrze z!c)7E5_+2YGKzyJs~Vw{hEs>)`+u8sHYMh-1Y{CemUp-gZ_MChniY8U)XxaoT15W5 zTkvYoBwbzvnbI40rsrN`h(@tBlIX8TBT(n;#k8gj5zQ`U>;<`OA9UHUSMo-Y9H13| zmRl%sT!3k2YIVlY**1c5XhS9g6#dP*#}#We``!c5+rsC*0z}wK;Ki>>tu`vbu|(K# z;-bo(fXe*mg)!y{Jra<}jppi~IYWy!0wT^zBZVkz0mz`8#yJ!=6Znyue1CQb@<80e-qn*kL}{*FOkCC>ZpjcHCRh}kl6=%cU~O_1+~{RLVrEC2+>#5niEX(FJvpk0UWN<_4|V68vJ1uHB$7H40;)ICn<}=`*%RG2U1m# zM5e9~4fzSLjto$s?m3^R4ls$Nm5Gu`jk$2Hi2eqFK+%&mR`l-ay_P;))Cx&n_$JWK zh+{~1+?fol{FH@byjBCd$woH(Gmx7tE;>Cx=M)G!h{}IA3;%G#2}WpLYI&pMZp>{% z$ETA$(D)uT4L&%*67w++iNYSki!){G{dQhf1i$w-EP;a_h_cKM!w$a%EqW^r;yh34 zH7Nu`I2+czBJ@7+c4s=zMKDd|FyjTG8uMc$kM;Fl;E;=m3?EP&Y8B$3lY*&JVwyZn zJ1?C)KyNcfz$|xRQ^jNj{joHLsGc3OaT`R0pzrpxpde(&F`pu#6tfDMj~*bZ3pp!c zs}!55nI;j}3BoliCTc{jTXHfT#1K_jN+j!Dc>UOhShD`cv|Or3iWa;0Z)%3OIRzP< zqv?q2bw`>Py>FZYK|}wX*Eh;|s{YE(k$;&cB+W#-!Lr1A{^4?=m6^v6wyOs(QIL`?7S__~I0 zui}apCI@du+pU8_YU3?HhZ2?9G@2Li6#-Rhm=gxg!9yfJ`9)G3ZGBgneM#cL%Uq|v zt-Lt1Rz&&f0H6dFTRabx_Nud_+T`y?E}>7;Gj`?8&#xrdlBv2=R4yh@+cU@*NB4x> z52Z=|$x0hJ)o!%h$-_g#&dSS(jKdiQC9N8bqpgM?Pzd#FeP}q>c+Vmcy~@DkoTLkn zNHvnq!+&KYsq7Mz>S>wQ(}03;i={2$^cYBhFZYtn{*Du6%OLRd$zhN2U;QxT$ zOVbjsoi|!UDJzr+jNOBKT_7G5uqCy^O()4ew_4@&I3byWhTiP%aC!$8FcyC3KD34A zbX!Vl%8Z6jiYN8CQOd}6IBC)V%5F56JZyNtS+E%K+;Y2=ETwfx_rL02V}EiTV!%m% zfjP155WeDp1hF6E;LprA=jBi3KZU)i$@8q?)s z7LY!(+2jlX{;E8JG3K1i{xVVtC#$!6y($ZYdSSZKOT`}_AoWUmFBTTpL8Fr)Mprr z+--j2wKWt!o0o6;SSCLuXnhU`{3m8~`RQQ`o2$BaDG;pwQRUo&16-kSOPa`O3s>N_ ztPdc`z2Ah}tR6cK%+~d~;A+q3CbVkpg6gr#lks;m`aL026;FLF0EDD_Y{7+bWw{1x zFgka3t`|upe7Kl;{+>jKh*t47i;;g_y%|ZGr<1En4pK5N06ZiUFRfwL{c1&jKNK9s zZgim1tJ*N1#{^7)ze3BW1YvPhEU&g_y1|c3EG5d{K3Y*Ce#L^E19U^~7B zW;soES^uz4dDyLJ-zMFv0FWMfXhsI}5@*TgOp^fw9hhBUl!9xBa8^1VlQK&FU_`11K^knoY6`&qD}wJWW8KPE9_0YL z-9tw67vR1b9I=_Z3M7SR-swNv6<_GOLc>qppWL$v$*x|uZ})qh@`xJ6mP)EipaY;B zvwm1Rm6;ISk{?LyWC&31x8X%JLy57+7~>6UGRiH>0FpCjuz4yPDG~u^*D)*&W=58by&4z%!T$Ns;Oe7)4ZXVEgf{T|`p-VdNpG9$gtfbdtQ z)_(TK;(h)}d6lMSt1LY&EYax&v4=C^gNm(F;UMf?=)o{)=ezy`h=rwZ(_KKJ4P&Fz zNGrn!YSt0n?L5pzO^_XlFj9ncACrvc(z=CRR3H1@_^)q|_7G5x*j!{&f9vD!xurao zyB$)CE$KxEA>4ty(DB6|KYonh=z`nu&AcfTKKHfl(yLPF9QT0l#x$kJqW`CDH``z@ z?&mfG&R~UHNdEU_j^NhTOfT z{?~0hG+EddEGcgG{T;)@r2b4Oj2wzSSwOksRHXRS?TzwD!|gn#0yrlESd0n_&g?Hh8Pj53|X= ztW~~QmQa~2(oZ$GWlYy7uD}=MY(;=`l;mf%mfO9-F)+nyDAS~8Sh`JziL~ zPxLlALmzp9og(`IK=^+O%hI@#RcOi$XZoUCjW8s}5WlWI~ae^Tvp=4B&wJBMwiCM4!8{c@U?rJzF zI*7!nc2;$gGTKXP=kF!9INP(TM)g~R@2pCCAF{N9Tl{XLH5iQKni{PFqbK|jpl;wn zB{oB^h-s$U1Z9Pt;t=lkk54!!d;$v|26X8wyid90=raA_21OU zp-h?B{0OGUI&(n?8D7YOyM#a5MfCuF)!5+pZN8yTIziEXZ2QqeC*c7Zbc(v4N6$to z(2FL7J6_YgIiu=BbINtvG1B)=ljfcs2Z_}7rXeR6uPe0vJ82*#C-fIkLbN+f0fMQu zE%i%2oSa&ZA?SK1A{&T_!?RJIxtlKEEOOTE(ky+N6lz+&Hbs*7Ot^i z``{_To)$^OkSgb}hdViK;;B$3JZjXs1I|#iv|?$wQlwPMM_q@S9;4&>+OycAo%>2% zbv1}FHBNpDB66D0Zs`L4yZ1xCHQk@ls8$U8>|QNT=+;;C*9F#=X9|)QbX9hbtv^km z0Z%L7J_HP$OvQ>@w)K|n_VugQ3m|MwQ9G4Qf2g2xZ+8$sM)W2XT~*Prqi_TuO!<7l zeFG<4W$C&j@>i%UsoassTO5^gfgaFbOfWbVDNVmh$4O{ey2vV-U1~{tY@?#r+@vsH?g4&sQpfj8F}2{Jqt65Xd9{Y zW<0b3qaPl&#N8@15igf38&UvB?3TXjFP?94ImzK;^CVQx?)Wq`Miw(s{N1EF;1ujA zOVs)#_SNL#9? z6BP0@&~7mNPMuPK_QRFT)Sp!Ch`IH-9__inFpDYeiJ1&NMG>Gfw`N8eCxh{B7YCg<{2YITL0A zUJX7`(OcUbU)YFC(5R0Bx8%~lzO6eOtm+%&SglOQvQDY;*g#zQ;}S9{5~65F_%ta( z$gWxqv;O4cvq4Vp(cAG&{6~Re5sRDlNW`Y8y!lyrv*({Xi)U1c^n`rp@P~$m;!s3G zn91d!x&8d?641N5sI2Ia`6x0{K<2CWp2f$fZMBnWn?2&d1X}t@bsvs;3&>xjub5%2 zURgyD?jdW4niVH}qHEOPCDpzMFW8c`YFWDRU8d(_sGV5sM7U(%o!OA*ghl-*;=wMx zIgi!mK$l!kuRn~Py3EdxNS^jvvHBMY96cPcZm>OTtWr zko_*zNsdW$?z7EI$nV|}b8W8B)wNCtQe}KU9oSLJ77!P5Sw)s=jPOAm#m&uTa4S{x ztl2m9L;9a&xE&=eK{rLp5-eAr3G27MMBx%CoN%o9y8W|G#fPvjL&`7hKRYfIaExw0 zkNu>c_P0?`nkRvIo0g=Kg6se)ybb_uDE<-FmU&^lxOF4@4BI#QS5Ok(13IBu^ng-! zoZ9GDVGXUSje?`8D5gQSa#6>gteK7bP10;kTy8N*L^9Blr9dRVvH82m;O)D-NFUnm7Y?QUn=jNv_$eZUUo|#x<@sh~ay{8#kl@B6fT|k& z4J63bG4IC_5R##LkPG1+GpbV^fb%0>|S}_MlWCToBIB9<6&QJ>K zr)cFr{Jvv8zD(b;ikwYs$NTvg40X4hdp}B4OnIlSkgR6Yc>yU4uLPPDY~*#a6=E^q z4U&e6+K*%EY6!KWD1|Su=+qVGa}lq+)74NTuQM+Kka*zJ0LCP|wYFPbl4h`*Xw`c5 zvD$0Ij&q#sF@Ho@d))ZQHPFEC{kM;hd|1CIOlCYjTLVYHVmxhkiu*65U7KO~28lBG z(1WC|0mVw&lWGFaq==ENM=Py)blbXHo-sF&Htj?hKQI#TEA6P^#&yzxfcUyq)Fp=n zD2FpHyRkCS=Cc6lsQQf-XKcLI_V$(56r63<*2~g9h62C~M5ZtrsU?Gn(_`Eo^gp=| z6W7GfJ1dByaU{px050*p-bktfl#pC&!Z~57&yCrD^`MM8>~or_9>M3;%jCmn$d}e& zk_#g_vV;tBLmWMOckbBh9vN4?)N2{}u3UB8thOv%20PpvG=p}}ZsVvk3>;quMW-fc z&h$lI=r9+C6OI~u(3m{b4(|=P6?WLxN5K5KJd6FYi+C!ewz2`3BZ%*On3PK4QJ(}N z5>MdqM)-EQpEBeSMjH(B#t=TyRi3VfOrFkNSyS z8^@pD_-t=mYVcDmgIJTSIanEcLO2jP-r^9eeVcq47WXam_up*~4{pIITg^^cBC?va z(L*H~;a|9Ao*3v+9n1uy6f%0%ArFP3yS@`L#6I{^JfJvrFeMbgrc5GMaK8|hR`!BDKB%QCUi2b23d|%|DQOEZq zgchvX;Bc}qV^Iy;%Pl^W&e)}X>U#kk37`1Mw6pSkG;FL}Xac~a1sF$8oe+F9Z%LnJ z(FIqA-}x62el}u|r^>Kk?kJ(`_(FaL!N%)>=*lsq_7MeBH>ggXHGr{hcBC>!!#l}| zyU*P7`NfHLokRBn{8H8Sbm`#AD<1xU(WfcJ6ghzzMK>v^IYe^nbb@I{+8P%FwbZ&@m*s8xCuvf4 z-5Tdczl_7N3m`frrL%fScj7%QdE$Z6(9>GEnyjgfPrRMdJM6c@=>^~Ts$@DK)d%ef z9JMEXFy4Z=**`OVsLCMdj~__Ksj9)Xpy}B@v{twxCON&dndOnU^(r&v89R+ zvje(#nC;7_m#`uzI&wRLglQ-9)cYc{jMTN<=` zqaMU&+s4jk_rq-La(jYhtdJ#%D7nV^UtYmQGC)#Swy{5Ee5I2?7a8Kf_s|}MUcbbu zIy}saW8IWq(hknCB^NwysR-X~&v;`cq~kv~Kjsg}4Q{Th$(FI;q9$57V2Wr#3C<1u zN!7>}+y4K8;ppvLqo%GWEzqde?Az{KPO#!NQIS_=Apzk+b;bD=bN|fe$C8`$)~P&3 za{%b~Vj&f!KHB{|Zv3Rzf+3kXP}Ry~Hz;x}Ugp)e7bx_IYndaD9i9|!`^d~}6w|av5c(4;Pg;>8%;{ObtOTR%-r6R2&(I2 zCha7ef^~%J^J>A?Uqsho=&kp3p6DjW3P+wSd$(#l&<*%4@0%R(GiAAZV5imTUD&b?`7br~B)4-%9q~bzv|`jz1N3410gYUMZ*vs` zFjsDX@ELu-!P|j}l)b&N8iVJ~PmmU#WdteBD_hB8h0pM1oVbt3=;4TP(jdGIm6Dzs z(01RiY;xO^0?ED~peVReOFSV+lckK61A~5{{XkFT`66he$TWslP(9+x8Lwb5PU1_? zgs3-CWyvxcwSCRBUY>77{zj?YiLpg7K z9eOoE*+Qvi{8cx{4}Tn_$NBYLQ0gm9FeEh!u=TtIXO_YHC+EjhY z0PaEM8}jl;ga5qjhoCZspfL0GT7Gpuml}lG zkHM$6)SwCPFWj@ly11-JEpF}?N3d?yR2r~LRF$`rWQ1z8U=CDtO%_14cGDT(q(8jC zMPnHs?bL*yD zRW%sM8(JM_GeRI}{uPX-(|Hll9YivWqO3}eZh`BPeSsx`nmA8k+NBCjj9$9`+GH7 zy{-`X{rqxCK)}^XucF4$xPkA^;=HiBOp>2Xg^tknjA1rQwunKJQ=Toym#cOOVIqua3=b>0UK)G|`ycpdj(+ zCjBmbi`}UMHPRA_mPsCC{7!@4&%+&kui?f-nFp&dP<>{_WGbUMFga``vtf!&T=->x zG7C4cc+kVRA`L1wHA6>fm1*@Rcl{tblGs$amvo(aA-eIvdgv6fdJ0EBKa0T%xuw<= zI*mlDK<(XeVf_J3@$ExC(F~iAx_b<)$&<-$mv!wK_EmQzmSvmd2QZ%I+**@gL_T;V*@K!x>hWdxNe`>108v=vrxFHiK+znQ8gBO zgE5U@WXnAWRhg|>1k(v8%?(X`JB1AfIuumzjet!MCSxcbnMuqqUH35@qwlVI5A10L zCiT$TN7~f|W_%uJ-=Mly2POVj>eRZb;l78qm1I;Zbv|aou(38k1bD{DwDFyC1?1MH z=(FpZxm6{yivyy1$Y*Fz_Ef;T{O`K4n_3I9CMw>h^d|wjcR^stx^17 zeky`hQ{WNs0XNX+8moU_2G1cgjUR98>CWNcYZ`Tzij8LC-WC3o6&pH`Z*!>SpIjf# ztT5`(M1&xF1+yDyIn1^@W4V4(UWnMmkRpm~ivP<_R=a+Yw)9(1jL$7;unWoQ9KP+w zmbrFObFZtE9;%Pq@iJ#Xpi&2Y=n>;w5@M!;O+Hf0_a1h&vzZ1{#x|m6Zhb7*_2W?x zsm3S6B}h|Vr4u1EGAt;+@$;p!V_MS*xP^M)YsVIIR#@jVt0D>_Ikf;FP zI;}JBR^jK|Q^Hr57XUA=B+6QoY@7l%a~UpjRC6iyqzG->*t->NsatE;a%uw<;fGcz zZBTHZU-1@n3y?86q{cCfZFxTBuac0WAW87?YZp0UYQgX8x#U!rNUvsG0n&n?M{Vz| zjBQ<*hQn=IV}6Jg5({KX+!;neLl5RITOj`3{N_ktDFbtkW)WCwWH5AM?T;$n)tAr_ zsRjCb#gf(8tc|pW|3MlnTGq9#gS~#}$Dk=r2_b&S{zMYMIQ=HH=uo{PQ^*Tg#nOZ% zVa<+n|IrQ~i+rM4WI*q>VSwm`!L;2TE%gjf_ z?VP1A-)+mzbDd9Cwd2HAnFRD8yxs51lZZ>dVsg9VDO77JmyF?B8hp-VBmcD~p>C-j z6w;-Fdw>m4>H3$L!hYeaFF@ony7rADPD{F(VYG;&b0p&lfB*?|)>J=iwYBxC^kq?1v*!^IU|F(X zzT22uGL)i|abC}Bc>yJXG=gY@gJR4_?1%WK2G+rh!!1>r?Ard&10!_yvzErxh4)a1 zJ;&UD-ue4)Sl@ombA9{6`I1u1CxPy}<3D+B0q{Z?#uyP&NHDdPyyrR2bDZ!QZH=h~ z&U6L02JdDa#BfVRMC{F?$|c~#(dBd&Wz-xP?Z^5rZWmkN%dw1xs4eAze^l3 zmh<{fP9X37uymZLc4pJdQ)Fkg=KnWe3mxTX)$9~*stSc7?c*xLoaZ^?T+S(Z(dM-8 z$al;yJ%YWl&UCQnN8UA9$Ue?+p8C>x__`|usx{<5U|cp`we^o@I(9R*eVa$Ha4At7 zL-q+P5i{t>sG2=Wt(}P##NN(lyW0+Wh;4D+aS#s%V$~U|HkdI6b={*g#1TF&V1{2 z0Li82(>l%zALx?BgzNWrJBu!DdV?W<&L;SM0jr_x_$t=5vT-5Rrei8FGX2`&8BAr5 zg%oRE9~-f^PkglP;Q#>s`}49_|H}OT-4Fige*pjfW&a}I?oo0 zXq_G41z~K3T-{=P8Y7F4l{he{v(cPj$AJj8n|L6V<1quk@Mt(})4avFg-H*Z?yU%p zMlgUV)TXPP4|!W2`6W`KBq|zVB$BL*LLZNhf=ccZ&;Ak|)4BG?C=oP-C$r?ATO8mK zG*ym=3jDoFH=adYERxzwq}?r*Le+D*zZ>G+mWC9G(gVVrp%jsHU%gqKcC)c5xlbtO z@OP|unuBm$gJ!2u=t5*gidf?PNcHNEE$0$Z#q;kP%`;uUV_s?;se3iHEt0?@ zqNoq1v7!6nCftV}mlMJI6oOKvK;czc?*>KKkGcFP?0Un0R#Z(_bCFJu`bS&m=`zMhTFQ<2zWj9eIbI^5TtD%@;JD0UGdOh5SxrM zjPOosaSRT{%=WtMMN4_jZRbB<7fNRbQ%rg~YhJ1fU=x8^jY8D67WXyO|0@Nv^``-3N498=R1&b4xZ)K~Rs zDe=goKow26DKN{xeXO{1f&BL|yDr@vD)a^iFAu^QR=3Lq@*)pdsifwL1V3gjzQ_mK z!r~t2>fyR_n9Sux6YyKvp&v5UO9E2G>{L?&j=`aobV1&Ex)&VopWRbDJq$^#=Q{@8 z7Fatc1Emfd+Hmx(y>y1Z*rH?qli9OEZSTAuq7T_jMe!Lh++fscOr5Z|xEpb4S#Mmo zq-oL7m+?T^TH=;IZ-SQMD=hzXM|#30BGk*=Dj7a;qxnPM2cn2H<#Oa_hbtwWHM~gD zWD`JH(<*V!fx>z)0Deb9cxubZp!~3cM02S`z|?ZSnFwphlQ{V*=K)t+up~d;6}y%R z40IotdjcvT_?u)=+I1ege-Q8>3|&{{-#rlY1Lu- z@xLi4c*^_Uy69(5t`#Olc*iWCEX|@v7s{I?2(e$>vCUIvhiEgv)b1?z)Zgm=>f?R( zzipGXg4!G{f+yIaR{=hEHhh=><1--bixyEb-Bx*m(*2iXdbbED;vp1i{~Tkc%p&SE zZZw#zT|!@}m}fdBX+o5R3`s z0b@cqQi(60AVtMxSRniwoDE+)d`(~g?jygCd@n=v+&C6dXvDX_A%-%!guK#l<|q0F zdroxCS8nX(HC2KwToUZG3l#~K2ir^_0J*X(Pbbm2On(%eWPr{}JZy7qrX3A+?Qee8 zGC{$cc}QG0jhj%&Z|u<*deDwLRLcO`jAkw@HmgB2G5m|$WEwwbp zRYEa=qLsQ_|u)E$MG4LU#tXpCnC z#!}5F|K3Yv(nX%g_YR7UuWI5Oxa)}GfFbO3j4x&1wFpZhJNQ0f{!zc+T+84aYCujO z;a$u3dY+Y+8oJSeFLPk23K)HjKBVvDqBiSe@y5USp}wj3!cg9-PK`&C#G_^YVl+Ts zc`zbgu(M#Xutro#MzudAV895k`h~A`#sIlB6{5ejXLfhP9i>O@LK(7vbgrZQ*cQn4 zP9)jWC&U<;*Mu!m6S-UHv3ldfl@`NTzq8+0xWy5rNB|c&2h$w)uDFpFH}>`6PtEKd z)9;nH;hK8o^idxiU+^Z8OMIUjqyZwcbj||OE-Luu#J_@ki!wjHV+4=rp6zfKg&1;U47Ehzpo7LH565&>u6ds`NRbVdtxJpgGR=PC-jPstSYnDMD94SUI zM@Gbdx_p!@y;E~fX@_TKqy%3^6XsBm000DhOE}fI0D-zlY+kXxED=P^3@#WACTbX7 za?WC?umhATu}Mz@bK4{;G6r#xTj3G_G@5=)bDw9d_Y)e`Z$!kR;hQE=#h-vPP(X2i z(y{#u_tl(zNm&WO+w{4zUPoTw1jYh9D3hO+X#-{Al`jF!`&wYRz1m-@>~ECg$c!@HUS>^sE(UJfG&?h;SkA9L&LF&pelF z8Qq)E0g0Q9oraxp&S&mZ8RAF|MLF4lm6X`S+m8E83omfm1B)LhtakTdRs%Wa)B2z1 zodidM;CqL2Ws#vKi6m8;6HXF0XYMWxQ#4`70`~kW_Thz3!F}bOEY7ulwW@SK*KDew zD+zb;h4Lwaz|gzgc_dnbk!Q1t;YBGC!Ag8Kc2oM3@Oh~KH6P9@gV<-9y;|1>WJ_p9 zHi4)iq~^XT&wiGjrq<5g1N;fFa|)(B^_VTYj2rA;bO+-pG7Hnk9N$vDU%O#T>rDOa zLJgkCFe;_+C%ZNfp&JDyyv^_I5{z$b;R9s*RkjRi(R;2>Q2Id0mJl1-ZZK+30p@7k zE8vRL9)lJGQVARw=WKbNtsNX3@)Hoywfn#BM`-B3Xa48Zd1%9XmXb-dmfL&C0`;#(qN`2j%F9RNuxiqei}O5zebE&I3B}q`q7ysK1=2@kJ5iYpI46HR zWMwdbRAgNi1G%hqPDx+u-Wpj9o&7G#gRGlois-e{3nYa&>eQ=;_>lUs?< zCwi#t;8r5}Bt)N=4qvTN#Guz}BTJMMqh#?N8^o5fjNP~)A8!JFrn#nT|(M!l*`>TUq4v2dpHcLPD=l=)He!d?pl+W&Y(AD~FLO zjMN%WO0IhP^Kj|ezSWE-I;e8`3k}}!QW~;xm4?kNobXSFkg9n!vZ+q_N4Q#~b<*cmeBd6hzcoDFTl zO|Nju4PPdFH8l?k`hXN|4kSOyj0b0|Ua@mkQeBYKcj8>)cX@cb%uT%S+O}=)%vL(u zuqXhJh2}+T;*Upc#2xTV^glzfUi=~a-}Z*$$94aa*})?a?Y)wUPQ9pIV({S4<2~mA z+cYIVTNK=zNuf!{r^wAdjd^;XV&JF^EC>L~H|oDC(FFKrt&8^+P7%HJLcFk$6>;1w zk9xEUUKVR#D`en-FH}pPhY;6fYX?~YD^el^sA>50LwXWlI|UiGq&BDh*`WJhK*qK@ zlm9>%j}9W$GJq~Lt!UD_iOd;M4DDj3tECs1goNG636&pHqmbj${uWj(Lu+OJ$bIcO zYoO)Ku4nM)EQ~TJ3LDz#D{+co%AdUKj&MOxzYDqV3E-n0sKn(K$KmZW}C?I)_-+41vf8reG7@UN6FlLUS z#awTRx~$fPsQtv^Gb=Dhw$WJuX5~=)5yA4mik+xHwb)0I6=bJ+FwQ#% ze(qt^n?o$<@(Y-UEBsPwKG3m@ZjD;`CRCoSycVODS@~|WT~rSrhin34KfYhN0(BF0 zPi^NP(0OoWkc1T~lLQ0&4GWz?BWae>p{zzDCEPIn_nNC~>$C^L56PRYX{S*C0_l2B z=kO@t_!9d2o%*6*dnhZ?_hdQyTe`v8>`H@$+&1Hgcq9$A_JR7QlK4o>2&u~i9VP?Q z2v8x;O{z$=GUH+_GAsLTUdZGv}ZD#FPnsARI{j0b6N~rKibhvkn5U;RT}U9N{P;@_CfZ%QG&1bs?7GjA`Rnfs_q_ zI%a;A+uAzh640JVHOc2uu;9>C^IY#BPng})p%^ylJk}Dsa;uu@tL4*w9~zzR zQ(e>m|Kq{Zp)$L)9WtLvUb+`^SM<+v2tp)A?-is0|Ci%FvMKp$(;T;=*^D8WOCE+( z_jbPLJzs1q-0Wz2FfDztUTpItMJE(q)98a}Ao=@vTQGXF31##teyMQ%v56Ms(k5VD zFt=v=V5ef1I=>l2iR@F`;y?$U*Z@7BC1?K37Q!ud@{Hh{80#!_M?uOQ;mgK#jYJn6 z;H5j==vOmXciz4Y{zYN7qHH1ydlCDkEyk(Z74vYhhoDHG>dNf-aHs|PgVq=PF=b=W zNLHqfaV_9t?mO~ZV678F@By6{i}lBF08UV~CyYK(yC zG@K4@*gDhwX&Yb{0CdKOPy};YiWz37?st*lS~eA(G5LPHhaKdIG*laU$dlJmc<{oq z*~}04^UDG#7v1M&lBr1pA_RnCjVtr>o)@}lxp7R`qAsfZAGVd3U(>0-s3+RP)PiK@ z-$=stRZ)6>h_8IQ>G~^5LS%h-i1k04JV?@q!2~-4*PiEa8(e(F(3+s~>gFqlOCzY!{k$1l*CuO6}2r?NPb2k%ud_AGnKse-}b)b(ntR9dLN7t1B71V+ic2bYul{#b?Ry6%)aIc70;e{R%X9m1)~! zYwLeb7{u|_frT9hI)&Px0;RHPN2d7C6|e7|L9 zx2TUod}_kjs_6G4j39CKtKEcyP{;e8=Q@B`?~ZdIw1_qrdR4?K&%=x4T=<39P}G9( zMxhyq#B$59!kC3$ZqPC!JsBX25tdtsSzv-uhmK?mT#-&IH2i2`$9kCY0=$CjuW zll49E8{_6qTB%=~CoO)%kGa1ylb{)z|!j5ehQ8uNZ~)k<(o%SL+X z3q(kI4>3Kj58)^rO^SSZO1hD?5?H=E{jxWXEK$s9Kcirjvy*YoNoZJ{DKyl+M@7#G zGpz%NhtsHeqOxKsX$nclm>4v#w12RNBNsUbuw&RL!avPM37EUut)@UmBl*79i>!2A z+sBpz`x-+TN$=wqB+<=1oZ~0g7HyAb28B!ub0&+J5N7EM`2)ol-wq#@GSLH1k{QCx zB1G4y*$|LScR}<4l3}9ZFg#0NIJ-v4#*CsUq<+<>^R?qY5oDa&QL%w`>A0gR7d`8W}M)VM;xcL~h5?|}0F9ZW635{4x{4i^YUr8M)O_9%^v~reU|@(va_>MDNEUYBl}| z_wn{Oe058lp8gT!+FMYL7y;i4tL@%qy|TyHwcCvzw5?-H8|6 zej3u~-u6XdG@V10?%EBYPW_;LFdWY3 zSbEL$fk@V;v1;2`^Yc6e>I-sEUSZml!BU@ze|8NEdftowSAvZryK18Jz{-#KvMoN| z2#otsGX#L0)o+vJA%lCz?9*jsTU-6ah79Pywk;mNiWiQ@|rkM^< znyqPMhKE!C+a90%EtOYSzCpf%yu4msGt+PUxI57H(UxGWi%hf?PjdnyB|}aQ3}!yB z$Pn+6!9#ZiIJ;U|(GtBLu!EX&_WFa+zwEC2N1wgz0D-bu6kO9kcvMqQ>FNZm+cA0K z2ttJO7E?Ywms?f_tUoRI3>s(Nv|7pm=!jEX#B-L+3-KRaTtYUb7z; zr@kwHYpn}1;@F1H+ZsbTK83nU%NUNoF)*`wUN(9kSq0C441H+C|L#|no*_LOf~tnoS@LEtlQ@-o z*a5MEvUk(=6unW&4koeUBFD|UW_w65G4oZ2qP3$pq?xQE@vqukBQI~MyqBatfG_{t zbO+Py_ww}r;&v92FxM;!Fve3$S(_zjEk7_lJb_6enW=tcm&jIr%3Z1kM7GjXt&~b? zuJYa*&uW4)zW=mW+k=WR*(`0_kUlvDzR_q5qfVaf)J)uQXq6cjNijj8vo{}iN|Mlb z*R&VeoW^;l)cS%_dNQqu0l|kREW%=Go?pUmcinR7dFr-;Dnz;$gu%LH|8XcG%w?r_ z1*=`-5{D;?{vW@2UF-2>8|z_sHA0lAZnF=KQH;5a=q77z?89-sfY#vz|9;8rBi(yF zE^1HBbkEydCj3DK=XHi!{v=5VpKn*d0?v9r$e)A*7r?a)5n>trDf?mMjnBBxH*+0} zxF#GQAAAVhXP*0nI*H|OAS>Uv5wvjXOt5Xb<})h>?One43i}o>zp#3?!EE9@rUI8GPWK^@1zaD{{f6k^Bs(sVB*n*0~+h0c9vt>KHAhvrcL zO125oU{rDuyUa}Ok#N&XCaB0Uc<-w5em9KIX9im`{xlbzhsDAG3X`&Z;!|~C?4T~r z<4jKoZHy$3yLEINLHz(|Eyly>vC!o|d*e+^Tz!{v4$Mp&Ze9-}&$=$4N4YL7xGnsp zJA{~PUzWDviV?LVRj7H}kd?4Nk<6}|K#aO3sAhhstD;pXpHQI{^pGAa-VV#~p(Xu6 zG(Yjj8}E^4sknlte&se~-5zEO(sr%+%&w5J;9jkKg-jb>8ly!uj__c4#|?YY={$l| zVYC3qc`jsQ@LwLy7UenCq=<)kl=;wx0iTNvqvU>?!h|vcE$3JuP0Fe!>}YyK&+6#D zbAAP1fGB#f7BUL1(d`t8ydy64D;8@!D_4n)!?qx*6dwxW-j^34ux5)9J{?^V;tu?A zU>@<+`hG9%=`D&#-toTZokkcB4;{)r&y$ZBwt>R5I%|srAe3jfht-TR6UwAMHrra4c-FSF~V+ z(J&k6Y<}(-(=te>!Mz6brPb6}{$eBcaA8$1t`R+{JbtR$_rzlV-J3Xbx;N0=I()5) zLU1Z=u<|Ty$mY7?zfk zBDEEL^tE-N0;4s68-{|f1}+y$eCkA5u)7YTnqyJt0Vn^682QMC0aBOD zK*$@)64Av`KHY-Ba>lus4v-4wLAz5G%wNjBm}KNq7HV} z6Fxd@04+e$znN#A5$25h6U^Nj)0MT%EcQ=90#uZ+x?}8FlCQJw^`0s@xch@v*$6CK zXhgs9Ue{g*oy+wJs(~-R(hk2d)|9LF?jYkzDr$_gZUFn@Ct@RiV-YqzyJmk@1CVva zcyf3LN}XVJ?RRdjWR1fhQ~S=TFZO%0lYcLlI_zC&mU8Gf$593Gtl{=^QRa6hYsS*yTHHsg-H-NS+%#{7S5WE!K+0gP`;V%Rsul-iK-E4=~T0CBDqJA^Q z?q}MSzkNTrzrV^anvvY|O9U3M+j>ls83*qa^}M5D=w0I|z>%+&diSIbx1fSJ^o`AR zZc3kd#QiozZcJ9Z`P^CnL!-NbxHgYk0%zfK(7Zc=w(o+*CJ|k2Re+(DP;kuK4_04C zg)oF!hO~r~GC*CXHwXAZJptRK<&T}~iCB-yDhlt9%=GxX1+tq00uNi*@iYib2Wml{ z@|nvmz-;^r37UX!OR$bJW3qow4KaY33pSN0l!JbO87WNaVzm>bi53=lfj*#PT1L2E ziX~u6&z64GzuZMrv%*tOa%zS2CWK{9v3#PCpY`ZWKG(sYv zB8R?IbsQ5#53=tX4&3X%ANYS@dp2zg&B`1A7j5mSNc1GN_9#j-6!HL8Eq{n)VzU{h zw>n@QHpQ2KRb@L&OJQ3WvcMKX4FwLR;JV?hiEr5;*{IN%`Y-K~%JqL^7=|Kq166)= zb}9I~Izz+A!%SLu3!Qyr2+q!4#(~byieJAk5^edj8%Tk!Z7`TsE_C&+IqJ>$50E1a zSJAwK4gLiTcv7}@Y*RZ9!4z5@vsFO$EFh2LgEv$SA&|QmR!6FYs;;#1h zzWB-PRk_;Fz6%$pZfF1Oi{n{xW!cs)QMLa``U2Mx)O>P_VjD~7(ciwIuhYZMTZSv? zt?%=@QVP!SCuR}R(V)%1@{CeL|Hmp>NZbHP=Q1Z-k53}wzb>vP1Ph_mc2E?5&WTcC z^{|s7ATADWTm<(+2jVi4J`NGv|K4f4A@paD?cG!rYRJqpagQ+Z(suuTilzw+%~@`7^;fU2iKwbbp{5_*L^Gb8 zoPx?RFC!PS&Lf2Ex|J@82cIt>{ndwf+3%VfW!V2B`qqH+OT2SZGNU>fxwbMm=TpYy$i-Ad;v=^@8*a&Yjah>}V~ePgwJQi= zT*{dK5v0<{tw@2)Aiaux(1Ql5-LfrO=`Qlc3TV999+;Z1oba7*@5^PQh>&7I4EJ{v z1{mZD$D@{eDvB*9$H3ti@ga3O0QX@S1+iPRFY@k&J4~N?`0gT*AQx6|7QW~WNROfPZ;fX_gE3`CO%2T_BvO!-2eAbS7>QfZ0!^`13>J8eViV^O7MS~BCD zA_d_1w0)y!Q-6>EM%Mtc#r(!0{#OgeLoTK(Le$ADpk_gs1(&}ehu#hE%*~@p;lU7N z(wIBA$wuSz5$_-!GtUTmVn*j1WB5Fwld zh_afW7`og7DBxNc8hcDng%@u*9E7o~BXcgv<CQF=PsaSWyi5`DC@fI!lh1` z>M5+F`ey&?_%k#K<`;KXx57TZBnRc@W!9gLa9P)(L_P-kbbi)gl7EC@cCfp7<2=nP zo_>-l_Y{oQ+|oOlY{JCk_Jk06o^U?*OPSN^#d1)3G|5)B{8#c%UV}k}VmEZebBQAG zbj_{_GL*u0CZ9RB$acgBtxjLrUIY&jKHb20xQ`(aWpn;I>Ics*y8Zt&6D_ALH!X-= zo#{Hq(Qnb`Be?Mjm(%O}VQ1;@TJ*-amCw>HvJX^v9SVu#5L!l*--P6!|qI06~v8ZSiHt6?^!Ip)Q~ zZ5z?|vpvVqR^CUKv~TUq--|+K;5X4Yx@~ z;V+`+BWu(?t{nxUshE-P0Q#sz@N8s!y^iT<^(OWyxTPG6uL>K7GxVk-YGCdO*XUeF z5wq_#_Ds^TE4B_~2jm)WF({iZ;&|ODtg9qAp6A%?C<-Qd9!TzF z=9Yx6`H$`5Vn#{o*Z96t0$~u!cjhvI9+&e2Z69Y(zHxi8JWf?K4Pc!D<)&lB3uzaYehG`WFUtwc-* zn487Kw+nu@!T^wC32j(&U7XlaFSQC{*(^d^*1>5z(!+@%ep(AsH&@UOZvGy>qC9CD zlu(nbY9*&xdTt}S*ZvTnbIV48G>YZ~mt#UHciF<8l_me_LOW$Vc`&Cd0*LHs-19O? zfx}7pFm=yY3W$Bs$w8Ju$@H~Z&noPQ@=PT(@8C5`MZt(`!?>Ca?98SCYJLe#Eel&; zI6@0B@!=y$6jSUWhNMzv*lVUev(gD8i{A%oBHC?ws*(C}KhM}@M@_`@*eWBcMd%fF zYf=j>Ct!0rC@;8oWI>Mxj#wUTh7caBaaqh$C6O^|U9-ugt{WJ3JtLo7_2#zB6>i_v z1y}5kr2*9mj+37Pqf?;@fx$)qjvE3RZOLnOnxhA8Lz)kgyA_#vgsxBd-{8x;=U)Mv z=C#S!?AHO@H=Gz4i?-sHIQYm;2&rjrE+Y|IaCYJP3f#3=2FjOrfR+n>(CXlun+$*i zwjkRS9MyN$usR&%5U%HRun4n+xCtYJ9M1i9+&Tb$eTtDtLQrSL$G3MN1Z4MrEc{Ke zNh;B#+am;3VT%9{c%Xw_TIh@uS)PrEu$L3C<^A+qQZ`{nH#{rph!o{ALo>mXS<})> zh3L<+tSkO2Y^tM%?6tGQaS;dm+az#c4GMK|cbbudaO_M@)BvvHI$dK~U5QR3!apxf8)HN_NiPtj;%htD`b935vyeko4|l?gnNE z7Db&ri2eu)Fm};@Vj@k5PSJxxo4-ukfBK@4#5=jBS9{;*Oqtis(;* z$m}w+5kRh&?1@z$yrj-wlCdFUh;cqyRtwH|XcoZ6U4q{|yAzi;7Y$BMN?9thv9DZ3 zhD^i+kThYw!0efbEjOE$U8Dc}#xehM;vNMsavx9>Gh9#6#*|KIrL_sJZ4yc0)yFa3 z89uTzjwcM?B8KB}<7^w+gy~><4GJba7FoL_Gx*TH$VQjRN*!uZmf8C0La`kfI5)FGuD% z+tt?kb85Gh*hhXrSYEwgx{qMO^tOp;*$Tk+P~pv<7n?*tyhHe>+u8fjoD6>9B_W>y z(k;9xbOf(7qUE(kthI%sJX!)!YGdNWey)z(sGNamB%KHG60di%d!%3d290WPgLS} zD2;wc9-y8&=u=|=QXeW32;>K-)et+Df`E2=W3H2`6Xtf;9+Q`bRg0oD_;t6rxX()6 z3vp5$3uy20Mtt74ME@pjuPwY0zzU|dr8wz*PW9x@l9n{8FmAe$T=Z~A2lJI#YFRAT zj?UuDR&Wct2!8;QT}(wDG{+Y+ZEAHrjF|gjGLtwo$-2EXThMC9JbC3-{KaD8n&^fG z;y2nfb@edYLoKYwPmcX`TO-5j&i5@FiJSU9VZWT)bI*$-J^Yp0l``YCcTkgRaT)q< z@j+xxn#c$FbY7FWp7kj8iwWbiIx4c*P!?Z-R2(qP0mVYHGKHIE40P`x_GP5^#Ip$9 z(8q&-)`VTba}&ecD&4|mWQ5tPCcSXOQf?pG6xv44?2Z=9D%@$}j;3RaY|_g&uSX5< zcfkS&c&tP12Q8yL3$Z~#d;T%`P)1}r$g1o;ck}x%z?TbB)D%lQN-kSb=$qB=c^6~ucm4wj zKutIT`N=$%>vLuJ;A`?0;oOxOT+|j=ptTr*od+r*(H~oG|0}G#*)9U+v0?ksBlFFS zFkth{{_+{gNi5<&Hm#CIRSiKYe)eHhd!JD3B$kYovuQIbL3dftm|LA~ug3R@R1Nta zQf0WX^hd>)gSPi>VYW&!g_m~lEM(+0QzW+$)NFEOiL0zJzL6!+Q3EDvU|dfY{zXB; zrdgkyqaZyWZf`8LG}W-wVKo0=uLUKjAZeuAvCBP+J=mh}38WUfHvq?MFB$1-3@aQI zl-NV^pC*WkmqY=g3AUokN$K6h2cs%eln>G~C3qp2d}zA*te(3@Fd-dg#cS&n=Y6s6 zpTH(d2ZE*a1uZ2Jy1^tE5}ShjuQd*^E`uqN)z#MPj6ir>t(`3T{(dOrm`J}{`IB8( z4sOE>4*3wNdM3hC#a0QPn|&k3eu|6f3*`l|j`K1qZB!!LrzFOoPL^D7ArZ*otB)Hg zBFVkFD2Zl4Tr8j%x!f(LUR-l0sWo1ul z!6{U)5sIF?`^!;v=&LVm&!Q{^KOr4p?E z;0VmmoKf^f2{A)EJc)RcjA!qAh5!%~(W5$cw%;Dpn+(l7gX`c!W5BXXouUQH_gCzT zraWR~fG<@*4gBC(h1|I#p~{!+DfF@6<2nw+k@n&H?TP$9boEMku6iK>$ctI{D8x(A z%c#oYz;xh=EcVu_we7Q|A?)0xYqTYG3sTG?>q!l}v@k-GJIOqN^vEIQSYzKr_gYi= zY#vm(CiwjM+zHwb?oFioWQ45jYiTa?u+;<{6v82ta;%;QF#7ljv+zfQ>TTt6i}Zb(znF}%wi z2x(Z9l=c1IJb4-Bhv&gm=0fIUFe>Ha*b|o8Gb;9wy1i9?&dz-bzKv5?QY%`zkeeM_ zXR3{Rje2R~VhhZv_9Y?LZV+76iIjPUc;ch-Qad%ljK^A1AxF>v80vl^F7XD^t+=zs@asqsWayI|Dr_y zpV*p05K;FzQQ<3bIy<=q{U%M_AGR)V6vJ!!5l{mt_Ll#vrNcCZ1e>Rjrl4`Qe&cg2 zTAG52zA-e_TlojxtQ7<(oqc%$ad4o6X zj?EaAj>rR>fSQQ!D>1fz1qmc9cjPop%BMg12-FDrQdH!bSkSGq6 z-kyufT;#tpZn>L2cnv0UBO1XB(@VcD_v@DB5EPeA#(J6vE?}6fDvo`_%=SgWZz8rl zd3c*tlEIlADgzb0-BpsYW6dV3bh8G9&0-5Z1>e|JhUX|@*^iq2p%upS_yHcB7n#{& zoBtpr^IO>2FDW0U9gqREU?96o(;?Y@fq7oQ)~oapZ`34a1})tkuRwR|cxyp5Kz`d6 zw9-D~whD3y+5Si^Bi#w>lqE%#$2daU`0SZIBIDPMS3OT%@vvNQXg<05O1q=nr4>sk zf}!#MUCfO}dkzFa^c{?)4S4r+E>L_&cq|EQoQhh}kP}|Xs`f=i%G_IJhiZiOq0RsX zOy8;Im9@!xhQX@`ZC=#4>nWHRhCfk7;?4nx%6}5D0Z!x8(_rQnV$!f=qcQ8yZhQnB zk3pC~8aFSg>m+ee*?ULMhUaR)bVU7fMn(0pVlYlx?st_01a*NXYgO<7DtXB*EZ#Gd zjL*AQr)WM47Tzbzd-)0Zw{xR#6%m_wukv=(!4O%I)xoc9*_UJ&M9tGcaO{x#Xuk%| zq#(k^oo(5tP^V9b{afv4oeU{Wh0aui#`_g)%5U8rk3*PP4)QO@e72{ZKs0Cw_T^yFKDd4SpXs=TvoSpyS3P>~C!W%YEg zNL7@*jo5L@CUZPV?pWI<5!3s>o_mAF5M99~RcLANl9EllLBtoP9iZ)uQp=J;rXk@< zBlv#*yZyKYT9Yh6pKN2G1Wy3}u)SZiBXJH-wCOk>;FZdR>y63h`45)xhe?8y{3~je z6cuh3;+%p)>PCbRp0A9qRC5`b1xEy{x1ItY`@tN6hg|b8YrHB+qtA*3Lr0nw66~Jk zT2wf4>;^@2Lqrbnf_d!fx9PSKLgaK;?7te!^}#ds$PmN{ryL%~k;DYqXb|Y^^H^1x z@n@h?rCv=>?$E*Kq-&-ciX28yAL=5jTYgy5`iS)4C_?HC2|+O#ATp*-q<+oF$@|Dn zbMiNQh~`CvpgbjeXK(o8ovwEy^Q40V?4%T%CRpOWn$J`Eyy*&E-pk*Rm63j@%EP?} zuTGA9NwgOO(>zdKW6G{=()Cfx=lSFvinEaz7{YqJ_7@nyZK0DFC@rR$k##!-t4|Sa zGX#wy2DE(IGl7ID)wU0C#pHs)PpI(J{#*RCqJuh4h6ZmzTY%)k11K1!kZo(vK}#ux zdu%vYjZ-{Pc0Xyd>m|Doe*>PnvNr@SLz$f$4B2d?fhocYK$)&fhP!ArxJ6Rf`_x3$ z>EKZu0AJ+{ML81#Cw#m5@Jr#kIvit?cb+;LC`hI*6Ibqxxjo)j-Lo;c#yokBXj{Qv zeq$Z8_JvUP-+iu1(-e}!-I}2>1DnKC-rI6@G3C!p@%gLvZ6Wi!>og#=jDIyTU&MQf z`AsOu^i9rjxOsXFY0s~DTPYsoQSt0aN3R$@=O1ZHBfBB8Zcg2-_J!a+AN&k>c^ zz{UO4twI3^FOvhVi3?JyxlupVwK;G{q4S*#rNO@rASEVa&K6F|c4R0O3HhM1yoN7T zH0u|i&>Inw8Z%IO`LgEVA0{Y*swEoAz~%Q26(>BD%mQ(EWzL7S>wEBNnV7n-KVBukq|auQ|;!91dN zCc=}?JB?fD`mxdV!L(xM$2{od$;0NgVOld#1t7|=>xbaOXTV)I7fDVm(-`meBfx zzE`0MUkrF_C8C@Tp|pGD`?3^nWR0}I0 z56+Yo6y(&n@$6C?@hJ~`kUdy6S+{O0YDNF^Fblg{O=tX6>YQ@LO?HB--2@{{S1s2| zz!F|Q{lU~d&px0r;PA_kWk(*q4#^wcjLp^Rt+Wnn$zcD$79vUS`J;X?J2~b+a}CFVjl_%U z#XP_sVJ7I2CMHhyk>i#9jgymj6Z;q!&yD`vyRmznRE3SSn35F%dz5nDk%5oxRt!?{ zi7)D1M7Nbb&2nb_p+9XMF&p;iE5L=`8X=?t%Tjtc$BZp@oFqsfJC;|Ji*z{{zN&(q z2p`CTmxCiRFdwAXR_JYzFsjD&E-C4A>@B=ogbJBbI)}DoqjK&;a z2mWzmm3d$PhY}=EWlVGhqVVdPiRrXI(N&YC6f_u`b#rz!hLhs{K0^HE%dkVJD$d&* zmNh;XHZAe7XfXF=d!Hag*`C-M$k-(yIH+35I)MJzyw4movynP=lc2%7X9>7sKYE$! z{=?8X3s-l)X#dF%`c=WhQ~y2_Ve{8<)UMg0RpBy8={8*hAr~?K$9kk_Gc_% z&U(YfopiYR!dmpfzs-{%V8pHA7HYmdOnI|st1tr2p_uAin{N@lK&5cutex7Orna&r zuZ*yGlJs_0eW{u*KqRC2pq>aFz%s!+{K+0F37aROSH{_m<%0V7=lxYH90}EYKf{ra zQ%O`EGBj*{M7k9ww2FvP)$rF%LxL$JbO~y#?A6On@bh6}=DhtIypOa(2NfB$6L2FX zk1{EjGvJcJJ;`p!S&Py+b*jZTw+uQ?ZS|O~hBdpQK0X|~z%}H(6A77HKH~9vlQ6$_ zU``>*3LOw&Q;Tpb=KL@l%&%#`oL2${{<9QgT8$coaIh_aWNH+n&UHfv|G`Aly47X9 z+QR_1K_h9@#COSp#cV0mTt78SBAwPaQrd6a%cTharObYN55ao_ULc%Ik*+#?ij0>z zEsCKi#cNxx6m2cScy#e#dHzuhFkxXMR@&pzBq_H`E@q7X-pG`#&`7<>-o4^ser+TP z@0JX8f;bv6lJe~g;=VEs4(vxLH3E^)IXC{Z4Lvqyp<;3eQhb4Ep1cdwIpmY)&vaQ1 z;)X}D81ZNhTZ*9H#-_Zc6mrEXm>1d<`E^Pps*53}g7Q|j*#^ZB)+-D5Ghb!!3m&>4 zGx@E-xsf|95$+GpM+RoA^_;AGLD;M4Oi|d65c&*LMw(Mz@~C5wuJfwU0V&0) zSZiXNEV>MU3@H1cR!tjNf|w0DXt)V_C(3TNOQMZmTTa5uIHiCBQnTA<{N3j3V+Z-M z7=WewF2pwuqb4pY;d?W(sdYS*Blh!Q@o)i>N9K7g zi8^K1d1MI5>UE>d;bf1Min_nWJ2?iVC#=_XM!q6Wm?wOBxKGaM7!%=J4re zh7??s63j~X9yzhJ8(C5yUvCf=y4N`3(Ui|c>G5-pWyjG4V?f7u!HGs&m=Bd8C!>`6 zhT1(4$NWG2&+Qv%=&QzAQP|Go?pv<>QD@k@tY(du0TeP>(_5{~1sq01T)!;35$4Q?Md({~ik{ zx7>}4{1N<|&xq(Wd^uRKXN;u%)^GVRYmj5}yTOK5Z@DVsz;MjKgIJzbB2r|6^Lg;3 zu{)vMY=AWI-Bqq*OPct7pkvCBzr7t)&?&t8ioBq8&GKvBOY-3YDXT{rm8f`Y0; zvfF$aGd{Kpj;B>0#$o>5?prr(n_Ce~zpvu3#xglFPLCO6dDFiDThhoM2DX96LsTWq zpLFQOike5;Vw(IE@9<}01O7UODlENyl3~=GbbNN-`Q*H~Cs1~<%OK{~FE3k`w8NC_ zZ5E~~TX5DWBObEHoh^pMt7G643N$KV;2U)$GN@%PgwXBN4`bUQuLRUepHS-a<8$k9 zJ&EU;-)x47y1KLonpwcb%y6*WyA%N#qQfaR29A5qkt*0k{GKw!TS-)7jKIPaB$oSq@W$es*mT5u5fjWFtvRJE1P8N zKOwYbG!L5@uz2AsSz9d#IEu^HEDAn6&H$aOhz390M=wG*WPSjLH9OUfVf4dT?iJsJ zRfn6N4CohX7S4fJ)W(L#TP@~(Q$fn`6O3+ABS0B5sXMbjBidn*HscGXoM}}+<1D}4 zy72E1$xyE}xh;j7NJ#ed*z#?4Dz;5@LOLp$?U}=h8_xK9NVXxX$>{fOqzg;UP&e=x z^D!Xfp62O6v?2m67Z16#aY;6_WmPw=oPQ2{%RdkHAJ&Ta>iZ8$=Z_=oB8cq0ZxL3q z8~qiRwyG9^)WUXzIf_1dpucN>14scaM;vn}x@K}_=Z*tHT?hwXrZHw`Mj7}W zP=RZkxA6x@@h~Xk-T80P(=nAfT#%=}|A|W54C;(CcJ{|i99!NmR?Sclls{)wMj%!| z>FaJobl%ChxVn$L@nLcRBE^6dT9eu8XL=H&YhQA#R6}qujwPIHc9$I@tSgy{Px1XI z%g1qtJB$GZ*%$c~z>f5jN`c?-B$Wzrg8XuK&EUPp3WH~Eh2r-E8tVq;{tVT*bDg%T zdOusLHmb<`|Gc7swj16G`ulQiNw~q95vu^ccyW=Alf0LWs1;($rp+w4jTn4ZiH{6U zJHtJ^x0CZdpaS1p}xu&hcI_{dUc%p*zs@W?fY5`fFk#?2IDliV zZ3}u%;=IKVQTc)v>vaQ6moY1gA=1*3RRbYXxR@~aV}LM^@y}E*iN3qrRO^mgg%}k9 zIlqesddUuoZ^TX~-fuS7YE}#7tKXq{WAB95HZOiIuF>uIT#$|vOB@sjJ&MpE9x-53 zmmgSW!Q`*&mtO}87*S0w)ha-Da%hjonq8^&c@u?k!x(cYI69=#i>E!7^OA7$XmybyRNH$53hDX} z&p$~Z#M1J{lae~ff^UT;L@1Ruo_3KRjmme6Vtb)H);g*lTG=CUN*)S4@)Oz*9Dq}E z=3EDl3I_V9b8zYKDCHi0r&spUQ3t(iUd(Y~W${`I(nJ)^uUd_9q0g-bB=2 zrYXWFJdi#EDu=lJRGSSDEijh#WVQozfNCCT-3@qxI7xEtJcCR&f3JVij$wbYj^t1<}53g-MU3G;V7R8=V_>-csXx*m%)oefT?Bs5K}#v zEmh==!Y&GZJMJT1P5ovIVwwt9AQ*_pFW{7AvpDb>a>LOBC}1xYp%PBSHsU%un`Pq3 z039m2nLho8Mh*g$*phrp$k_ZiS2-E8hx22otDhqy3GfPid&bnkUfa;&``A5ny~L8b zc`rrr(#tJIH?rq4HJpOU+(v_zHMnl$=}f4sKBW-!Vj0LPFMxig{UW-O8yghv|GdL- z3Ni18CZ9-zVF^ypi@ZI`-oGj>Y*rCUnDOJdjR;ThKzyn9tesHIXL4e_7fu3N+Cj=cqK98+`^66I6Am_3QK;elQZ;o(~Lk z)`8WG{m4^uOn8SOM+_04#Ylmo8KxO)3v>bQthGfP+h1w4OZ;sEHt?`0M=l5MFFws5 zKU--7GD=IVEVejoheT5gH;Tb-E~3Zt%+1}Ch_7M7^3>bS5K7yIoFxpV+T)LVUjAE9 z&>vF7RP+KfCA0x8F>dE@Q)42RklaHftj2x)r16H*t=?~Tqv$milWY%;ZT|Jnlpoi;7B_LZV08m z!NYQ8obhPIe*aSCI!B}11CQRVkNGAx8p3HEqmcA^NbF!VfOw3xMP2S?P6-bhZN@-pl8O&A$N4$tI&zggA*I*4~UhY?t_XxmlHg` zv+|%maR&8uulD)jGj$%K_F7d>I_15L4E>l%_zP~^m7TXoA=|et z1J+L6=B;X3Bqt@0AKpHv-mTtTEB*tDe!LZx{q$mP0f4F;AWsU2q>YaVFtN-a`xz78 zF5pkEGL1$ehjKkME%1mg3s*i8wub%#F?w*mGIKKmn+>J)mIDC>h>uJ2NfBy_lRdRT zzAN2GBwrVcVnJ!ec&cqmNEHSnU4wp<%kN$sMrooYI^g4@WdLF;o?WJEF)im1 z@uxUoR#pHzRCL0tlxRihOUglxK8wSQ(l0Hm6nnMMefc96GEl6cHSsw(kO$o(U9)_*Fz5919ps5fkThx9MbR`j=0F68w_Oun$j02wB-(CRt!Le$Hce+~lIpUI+jiKFp5 zZSzD#7MZn~dClUdQbP*O3@6*?dQcgZ)A8}8$hu=h1U6!&pb_p=0kRfUZ~kJicA2BB zCTEf1Ufwt|3?p6YJlEcwJXkz7rD~guNhz%lp)bbQdwjHy)9giKPriM)EYOpa!STXV zO9}xAwbo`_OjhUGLq4L}6;l6%Qg3elhOaZH$`KEG3LUsy zZd?lP?*Z3WeF-T4Y3tN})JYHfML;9Il5&zRnNZiZWHM18b5C+bmjapC-{xeFF53c? zx*5~iOL@SjJp>%7;|nz#WgJEobbzH)GREQ`UYqXTzLRBu-G_Y-dWS^zpw~)hL)`vd zP^B1~A(avZ5WJnQAD1XAoApHMs7kM@sB=1~6Tsa2nk!|@i^kP=q;%1Zg8|(E7~qES zbb!_o_Y>4omz~`~^tiQJ^xWbLI*Yez3MuxvRlr1mzQC;N4lnA-ZPoI))mc$u`r1IY zMaAy`DpL;$8EY1c#V}MC8?wwWgJ03DYs~ba)NHwEj z(qF>O!52AhW_~|;j;X@Kq9ElzA1N_XRC$^-5)X&~tLAzxm+QPfPx759k5oqCcH)m5 z#YA_|i}<`J{#%D#wnJi7168hR5<9fi!FV&M-n*xq7xft3>yvazIF|bS%v8?au_f$tF8gO2 zpvn9Ei~v}xlqS7WNgiIg3mWGqYi*BPq%I+oKfTJ~SwYtWmZ;@Rvs2hE0pZ&~M(>-2 zEw3vvB+0Uk_F?{L>pu3;rgD|JhvCnA5^@`O8}5D>oF8QDHm~r{c&jxvIf2l2{MXt> zLlCcPyJ>hUQO3LAAV%&JS9I^HU=v?xHR^9AA5@Rsr3Iw%m^@B%6PJt==qpRuNxssO3zUn5B-JQGv*YiITqj=c%7H(5Dc(jw7-iEf8}Q zK(Uo{vF_xp2`l$Q4w8K=dgzSUoN6217(vH&&Y&iS>uao5L5I}=x0dWczEE%cfLEub z*gpfG_JZ&mp>mSenU!aZFNDV_hCpe@+vvL_%%>kidYA(#qCXE zD1?N!!_{>;hwb7SD)G`W@Sl%ETMt5UztAe{&fGwlR)PmQmgv0#O!RYlLKSye_l1gs zQp0&PRo$dp)=9G@=VC`j3ewx4aj3KSLg%p@+Z*asvNiAnmqgryZ;mk3r+s9ez+-Bk zF=pz}kuCP!E>%>Z2|IS5Gv5%AF1ZFBwvO|gfat@yR_-_*T=4uPp2T!d9FC0o@dEc| zEpX1@BA68Tr6OxPb5+FvF(ny!*fnrSugkt*B5EQC4DJ5LgbJFR>*z}PU^sVRK~L18LCl-xv`_)AFi?|t-`jiZA8+Y`<)xgEcsI9>^IU9 zG?;?<6l9K=(au0jF8vi4;;b{?N1-Vr8nr1Fi~o0?4_rv|As4bZ>VurYD-DdcFw(jp zB1<@zHq%L?3lmW0r6pm)VDC^?(_r3gz#S`%%FuDTTkXv?jUW=tPS8Cgq*{6lJcSy@ zzk&h7#I-9MtJO{{fyUSDq!Wv6+(WDW?#F&!07v{e(RDlF8bVl?aOy%pKs>6T?ogpf zpEKkU{?e+^01V)aKN~TpC3W$eN{8a&wNgd>ZD^e2(2Iw>)KA@qbwW?+uh+ooS002o zIfG^+J>AIBl2IrNGvQh%8JV|2K}*i?O{}LKz;B5~^9>21CLG&SCkX1tA=NV3KZxq) z;n$Vroc;7ZAM^G2bA+^S_UFLcl5D<^|hbWTM zLeg0%=c4#kj8%}X2f|%6{$oLP2EL>{f_*L?cwl7i3xP4?x8nHf=iH91=Iv*R&xHFZ zyv&23x1;F2j-qcioJs3kgwTKP=dWN#M=+?>g=LlxYJX7^H6=9-lXEToFX0WhSxVUI zUtZcE`teL2u7y@UNP0BFXb3+TD z4turs+Ri+1uDFTCN4ZlYPq56JQ0}9hko8A2g+9-A^GR{LndP>5r+Iv@eQ8Uy*ERWh zkz~opF4%8<*uZ0bxzBuedf-i^`}ro(*%mM$(Cv6N$x4Dh3@}r5kKwOn9pj$g6j90F z9$CdMa>RC9;B_&Coxgyb&nzikTI5Agw9&0w$~1x~uOJqM(j!2VjBXPe4T_sw3HJ#Cpi z{m{@(7XKEErvJ<%??0$OUYJTgGI-+23-l~idU_Qx`(tbh7~=7|PmyCT3mWRpy;JOu zWpI`Hv#37^U9!+vy6%D>f7FCIdq)~r+LueK_&utmS<`HwTws0YVhUf&8lN%|KNZ&E zC^{v6AVN7CF32ckmJ?*F(N>3F;;&!C?>`?+9Z(jK>M$pOaoav_}j za!Mp(N|BM6xb|43@vlCs8|&(z3>FJk**{qIij2Bvr})ognTAOu`$A{4O3V3drT*(t zW7EpK1_a3R4&UT-Adn%ELJ~LaVZ~yg*dhvGHIpC2?{3F?>B~=J!YNoDLnusI2C;)k zKawf4JL0JiblVM!K^>%@XJphS?(p15fr$+FMkB_58=zWSm|I0z=+>Q(s`m3gfxr`Y zHx?=X@)>M3U#@}AHI}au11l!F(6k~SXoqv@m0pzi%&W@$j9 zkk@n3{%>Yy+_6SH54bgOp+rXI%R@VEEl=K~#)lv(J?!@an$Z(GpMvlC9#6ksZoI8h z{9-EwwReI;y3-Hq=G(cBL0l9|zAALoTh)0Rv};yPotD|;gUk~`>(F!K8I#D>lAl0Z z&QqGG2<131)h#@=1N}|`d{2$&;;Sc?q4HiQ^Q2h$X)X=r&EQ2ubjEaUBdeI(O8Orm zSV|gar9Odwz_=)E?-uetkdJ&N&&3vGy7bZ*MV2b%Be1>gmo;4G;m?Tu*m#6T(ERj% zGNa5Hqu_WOV>}l&_!9o9m9|B;nZwwF5~6LlFucm^MM6 z!s`E2Kmg-x`^lxUo8gX(m9c&KttGOi8F#uGAz2Tv^BZ(DW+AH zs+CQ`zB#A;fv95!B2rn$Ux~P%xBx=RGQ1)QCdRnWFy8`D{{)3=UNGf zPI?Mg%I2UuYPp7Y7F5<=?mSc~r&so+{;r#AJLyU|w$U|nh7yY)`t{}T$P!pv2 zxZtzX@3M5r#mWdlW8!M6JL>umXc~DGCw>`GY!rV#4vyMqsru)X*R{P4y$00K247l;C1ut}q3 zu{L}85B^OC7_i^4U|#*nSXnadRToO1evbl9v{~+iYNVbDyRG+2vPOd@^Er8zjncaf zZjo(Tuv51%rLI@e2=hc!P~tFK&y5jZ@G?`(#>Jk@(faip|DHuHAqjAfB>GF#<1V+A z2E%dirp|6eH^vc8j=_@`nv6^G^djo=J|=STvkp{%Y``m3lH~243ET=8_kc+ib!ORC zs)kXM+u`Y!WniRzRP`&?p}Wdk^;YqMRso|QeDw7<+r{j-NGqD|H|K}seaR6Cqm{Mt z+#gy*nSi6|nNf|WlyHS476s!K+cA`Sy2au3=r#9chL2E&>gO3_{4n-YJ=%cf3B(V; zW>Sv2;d9f+ma@7!c7n?DOjOy>vROy3_R$Mau{wYyLj>qDo#Z>3+<+y;M|yn|X0~Qk z3YOTz?r^Bx{Z(}*FV|JHMCR2pL}%{2j(mCZpSrF~bNQkWQSlkm_$F!py|uNOuVhN2 zj;;iYso~kCNAS$&4q)sV%&~x2^LV)yfPr`$EuI+wMAjwmtQ6eZgKNZIi@Vl&`%Cgg z^+UaIoHwzJ++3i(xSzw#l{H<;-z4gAdm&OOvR+NwfSQi6AhkRKF$lP4#_XdV0JHA# zP&Acvu-{+0NK8`E3Ts8s!AUzmYj&J$)z`^w#(ur{LFwd0E#0nL_fXR!>2{!9@iDx} zMUIYt~zC3kVi;1BZ$={$s3$jDjn<|RDC9(bWJ(HteHp0+fX(*JU$T`1|`P%~=} z0DGYPzOU%*J{X|xv{CH?qFqX0V+46m}^m@8m%QYm0#g_&a zd^7;j~?xd zAO`HQ`IFVp`i;un4Lm88yN6(N!S7|Yg=~`wgvWND$La3*$criI{R(l@fy)@ABPXo~ zi*MAFwhze#ATle*eGrr?Sda?b-sKTl8}lz*e~LhZETA$J5WymzOl%V{PM1kpm`LXT zZjYeTp~|fH0w3h1z8ol!3LYPV#Ht5}3Ng9Q{d|HEU7h8OT{r{Zdwmj#K%y~Oqfieh zD$kTmS9grwWch(ajkbV%o&Ckac@CP^5_lmvYW8QA)wi%Bj!$t@EsX^UUn_;O4^8p* zlk+82a9nrFxFMF3uK={*eBm#CNUawbTbtnJtu= zqm-Ig+|%vit(r(`c5RqfAlIs{+|%<2!{sGuqB}>oW?Jz3MO{rbHTVMM%^~=;+dQGl zx!~9Z{yIQ&r`HnFzL^?~#L?mmewb6Vk7T2~Fe=<(gO}#K?3~GrZ5QTzN(5PUD|?|& z0>3F)4MEX-Hdq9lFfb1Ex=#5vnqL|hf7>kif1@V7uJtGaT*A+5v`L2l5oTCaLt@C>0SOg~LUWuP z2D^Xpky0MB>N8)rmC11N$;n5KISzcGF1s*NK{} zZ7?~#kTD@cSE?Vv(F$MRd(!9L+9Wqb*^nEPssQ%8To<0NyoWxf-7OV($^7=%6pgfvnbLO!vi+(U-Uc=Wn}xE5_KMDJ%re5UmETi zO1GX;rRM-YK)}CBQRDF~H%V_BHkPj=#W~LnweB@RTtV%PuNf`9)ya7bOl~3yy-pV6 zeX%*B^kKl?xI1~4;!(w|8%y|vMC9@2{um0WlEgO+V1(3Ksf7Ud#Z4a2#IWU zXH;Au+B^`~;8vcokamdrUaTb1I`xh-=3A+}Id0-&^I9PukywtZ(13mxNhwM^g(cZ| zJrp26*`buPayd{Fpv`rkF+w$qIqSeAe8db`CQwES1l=SSNJu!0FtEm!=QWQ^%h9F# zTs5()nYkud$>G=B(i-I22L%c5u&S*Zut-$%+O^OMP_#I6*MH{=6Qj80wPjfLwO4yuy-FM*7jE#%LW z_AV7=>~cWQzX=GQkZxLL>S(OoyA=|>lwT>jQ#04oZl;)4LB*4@Q&yq|EPR!zk223lt2_2GxO7-l1)f~9(D9J-Y7 zx4g{lz|g({1f0yBR1*}}BjAp~DbfpJb)*z%7a=(Rb+zt^JzP3vx}>m}l-}5u-c1!Q z>e}9vw@)txrvI3H5YXlDbimc{xs7}S)bdC2g(W+jv%3Y(iIsmW3FDUSnfCsjI*f%K z0U{l!Y>UoBeY#RJ26q>uuJP}a?>dYoKos3Dkcq9x^iFZ?;WCO?_Pta4CR94RS=&Uv z9=bPQpuu9ivcDZXR?>eATD!20T}>IEC6O#_DM)wxk5ap+HQhNH;wDU|g=Yg0L||L5 zxGA~Qh!9ol2*;NV;L*Rhx}A|!Wzef$Zh6t?mb`kx|Bm12T6 zczvE}SKJ;FFo95-U~EU@rzqu;Gzug9BsXV$A3(&OFr z0Jd!nT80bJNM;^|H}aA;$~@jr3Tc%?O0)&?yCmGlR~HtFBKEA@k>ugBU@#MiMbz3W zqG#^?Ufe`{DcyyS5#mn20by<`{l-~)@jIA+_-F`)6G0W zr8uA!Y|`jL>3iq%)3srKZlIXWAn^kB+c%D+-WUSkTeeodEV}(^J-|>!pP=<=PEWPl z7hA09K!)bqC>EEdZ#3e7YAFX>k4R|cQEpv-SGfic(G*1axByhPqY<;S`~ULh&KjX? z$L5af6H;z3-W7VLi^S_sxDC6lhA+F>*Wf1VJ%rJkH~wg>UT=#By+RcMw6DyCswcdr z$G4SLJMA6Lk>sA#ip^Xj|1RN(*XZiO@L2t7%^O?(L6|&cGC?UQ!qv~*0_lo(4lZvC!`Bg4lo@6QdFk^)aT*D!*6vd#b{L=~ zH}oxjadPF+)+-^8b*>G}cWq;_8v(TZK)jZVs3>A?aU4B`>)Ox)e&zVSt{sMnkZ2wM zlS$W8&bPQ9tC0+c4X&|@#1wwR+9rLjQwLqzWq!7SWZx|ZBjF#Bbd7iU>7IORxw^dc zuIsK@VxH_PB0huziXKJczij3pj67t05)ss;YGtElpl4Nd9~FRci|c$kl_Z}y!r{Nh zdTS?H*cEcmfJg$g=@k4hTQ>ejCzkty-ThK?pz&x!ePczWIbaU|5mZ?w;eS5VunZ+f z*}B*_25b$jGhJ46(6-&w;8iO4BXqw-u=lMV<NKb1`w$Q6rzc29l;^&`gzaKs zdLm7qq#YgN{dNS9sR>u0^ulP-yC7EYS}h`6Etfqt(-M#cVF=LuN**O+25Fq55~t<> zPF*!5vqQKFO2xxg$p?EmM1U1JLl@pIRn2`TAXPJKg*DkpzBXNhf$ z3k~8|J>e$v6M^8!htX=UT)E=1#EDlO__?cU^215GUp)?r7{1~xj66&PX9LoeY(D(I zFdi|f2?(p!jQ{_i>$r4Fq+P!o;YZC&DY*|y zhXvj>_psP?;H6;d*4c2cN=Ingq_Zwewx|x!j*`BtL;d+mXMjcNLDaL9@TEK_M?mp zcC)6Hk|f_}oZ5DMa(CWc7ik{K*N3eo#HqR4+S7&_OGzPCgG0aa3i*4c^i zD-U+l_?QxUuN@G4G<=Ql<8-WgsHk#r7Z>KloJZ?eQuQzo?h+LpWWiHKHkAq{Q3I~+ zIDDGPwe%3(mNW(%@L4-m&~|&-(_b1_nEcU%gb0Y0Cn%5Bak(hj-9P2t9lnB`{DMpbCR^>JHwY%~ zm6^*6H*9$zbUVHa4jOrq&{ui7Xl&I}N>XVFyh_(+d#MdRs8S59t{90ae!lK|0~io( zO6o`X!0J`6QLBJq%RP-QKEYzXo5;^A2g}!nLKm)N?bdImy7bnKJVEHCVS=f;%X=dG zQUvVjdwRwRE~3&{?z9?ze$O|T1Ce>qeB@2{fX6~F5J+qDKK`Xm_vCIjTFfv20Xy`y zZJ!qt)YWLclZwBbTNkRC=%^&FY_?dW5#VJP08*s?O+q^p0W7sdM5#yy@J0ACVrR>f zi~1-Rm~yjV-}OQ58Zo8CtbP%h0~Fqi(P0Ag73O8?G+%o(2DU~BV`s^F1G%SIf^e7e z<2x!}yP`<$yOZI6i5k}R&-XK=`UF4PMl%&-xn%^qd7;LY1!G-PH7uppWHoB@vX2d1 z{rWRJf!N5Fl5eZ2W_=UcuU7~?`wL6rKhHG6m&q~V3_u&G=LO7>3X}S*PeAS_C{!Fz z=fB8AbA6~xkmV(8*+oBTDKRv-kd~>gwW&U$JtpyB#SSBAsznY@D5DYRS&OZqvr*Oq zAgKoj00S3MJsL~WDH>5f1wT0;eEMzZ{h4PQD~i*&nzdDbOm4}-MQY4f1*u{JxxV-HoGOApjFtFIq%ux$yt3 z*zg2-gJ{rQ^HW_tt~%5y;hfBz4+Cy$KaTlA@dyV1FO1(ofXE|Etl*L7II+m6Rq&A; z5j-{?E7b_poe3o~%Di%ui<<^0m%@t=_>dpd5^(u%RL$f*FzRkzl9aMcYn8*arRD#d zI7H^7pCVv4>RY?kRla{jba-&=nJLbULNG(?UDJk%^|~n3k*pEZD*Jji-<;(o9R~k3 zW_8|vN8J#B{YhG5>S*ZE5D)t)S`-V6YzduNBo*f4k!mj`x;RasDSs3-<;?c^fn^Ms zXTxU7DgE*CLN^reDC*=4aQ8<QN3dgtsb?YLpaUar5;eFHZH6P zrxK!ky0D|KAa^9+kO%mN@Tx5yrE$e@u$8?wWTL0?uBbbT zPr2JS&~)w3f$A!>TK>2sT**#jw2a#8}AnbHXVhFF%8ccEKx*0x8MM_;w%t`#KQsKcZ6}P(dN8K+0#J zO{Nv9gUXR^tsHC4Xr;kA@@nc&+`QH;1~@anHGg=q&IFQq);iRd`QS(`W3mLBluINztFJ!}W&D36Exf->rga0_t39WBsIB z3QF*(&ION*NW(fxd4S|T@9>U#3QSTm?aL9PAF#qL?d-70ghj zc~FN!)TiMAf8L_Hzddk06$7Co`i>W&arTTa*=D9zHVUj4Moj0#(u^<|{)65y3qZEH zh0Z6zhS5*ht~H#3ji*uW*7$?332etOI%h7 zq%i8vN(Esht*qiN!N+Z%oPzw3w((u$Sf6V%Z~29^qF9^SETTig*qlkGbW1T_aeg6E zznVzh-!+`>UaxOIizmOp2mV^jWanIZY|ZiHJp=6DoB?X3>7cVfCw>m|ancW@&8dbG z(+bfQTZt?v=e!*eyI>d%SMb~#hbFX*)0j9Ou6*OH9Wm>y*|6?0A0e1qG8uz?x}-`@ zu6tlZJGLdzzbNp}_4sTq%|D)N5>->Kg8=|f-y255sqqBnll`07h5Ywngq>p^;s&IU zSw8Tzl>5?!h(<_uAiPr5ZFsWzX3XZ2BtSs1SuUs^pHwQ~Sf z)*5AfhDIG9Lzb25zOA_p^qBZ$a}Z$^n1g8ZOPSEC*zk~7G4U5?g<|2`DN~ss9(!4d zQFXO4BP&A3GR5$?F21OY-Yq>K>Pu}5eGyv* zyi@ZqQ+IFADKbnbV0fQ~{esi%IV1je^pO8EG_SxzY(jc4K`v`)_~GuO77BcWW1?d+vCzT-=xF2K zSH2kVc8{hKDx9k-Rik@F@;jwiR_i^ck(%8aNAcA-Pd){WV+NyAw{LrI8Z7kM zgON`DtBHZmp8NuzFXiYlOP;RqpNK4?oW&62G?T_po&O23W5PMDxFAe%DpiyD!fKHC%{prPnOMF-aK>L#L z0I{m75A_6IGj*2y<}*^=t;;pjWLoP_H-~ejj?jPNFd~tkm_P&pvN{6baOyUyLFn%H z$ey7Mp_kk7%}uyq-P=+nkM-D`^bh>#jvGk43H&+66!<=#qILG>FNfez(gp5!W4R{- z_1|>DR?lDr+`?pr=Rx_b1$JHgX&GR&Th~vmNIg?D%)|5I1#Ee$Q*iM5x&)=+VbPw; z4`Nx3o6)KW0MxR6U4xN`&{kwnoGKofbSz1+x6;U+x$a2_YX37D^Ie#h&fQ2MLCFT*vQLt!dZ*p|l;93(>Q zpy+SjB5<2-A!P!tOg$p~Jlu1z&TLWN5DJV3q^z_)G{Q%MG8@OTQEB+lqDu@A1L6E>2-<`v+;+ zZz+x`{8{ zR$OGgwrP6UC6WC3eGG;io1jIH+~-J^_Ow8Tv}mrC@d{;HL9#CZklE{Jw}L+i4Oj9 zaza(1%iK1ac|?EpZv*ZV$oDjf%_{f!P0ZfYs?s*)*S5I-FoUJt`*mQ}@5B6%U8b#A zbn)UN2HOJnm1G=#F(%EEwV$J_@wAMx)F=U8M&jkofF!D}1T`;sgDB+tY5F)hwc=8G z*-0CW=C~ioSt52^5A!9pV{5%#KoncTI_sTc6hOB$qN(r6z}M7@=x`N(fa3D#Qt2G< z0!zJxzoSE2v|YT!%Js*RS>?61Yl$h%Ru2huK6Z~WMGQao?XP@6cbIE>!0=vz z1e9-gz4DHxJ=L!7@%JA2+gQn3dJG zQX3gMeP3dtF4(EjMm8;c^I;-^dgd+KiXXO3&sOInK#Y*-9O8j0Ua9c_e3ODX4XMYj4c~%7{nK@+`;R@B-iAxn-yzd@1eR6T$Sw{ z-{1T+pM4XCS461-1eo*yMP4FWKgc8;Rq;XZB=HF7H8yM$NKNZGSsld!v(v8%c@}Cz z+&2NVx?}I@d|@)gvJe+*O(VoRS_LRcwI(zbaM`^s=j*Tm%Ot_>6nu~<+E|b^CiY}w zR;xyR?0uBNjbbE%V`QrbzxHKf=CDK$`)}srh6Z&}uFuQ$COy-0Cq46^H3w>3WJhcd zpW?$az>Wn6cVoprx-N#t+?PKEy}#WHA5?KhDPdK?L2sdH_5X+KlR>;O9!a7b5|GO@ z2R?Ol6?b!;3mqUJUCs4SttDa76W*;0p9rS0R1Fd6os;(XOfp#+KC!cv7Gf9WVq&Q~#;UCZ5fP_CZ+! zyaXD=Rw++uZ#u@P;}EApe6(Nl7rjeW?YTs3(@aF-pppPbH=EAdC`gyN{`#$7+B8DZ z0_55eB?y%QxaB5a5U>N>V?_jI;d=zQV1z!DGkTu%%MTuQ*LDi;@W`*mzici0^(k&) z-*Uaf0+PJB^d@fv1w%&`@8fq56vT;ncd_j!?H!uu7QA`|gJAs~P34qG=iN6xSpduz z-EOUaME7m51@8OwsqiTuars7XPfvZAXsl?2p`bQnd25WXZ|%>0fnNvx2dz4z$xlsJ zY=8%v$i4k7-*?LQ%JuP#{E{{V@UUD05C0tnp4agtrgMNnpw5ZMNA~?##qi1w2EQkU zfXcxmI|y8DuZ*wQKor}N9U>N50g%k%0N(>rdpB0q zo;4j4p{Bzt2&6F_Oi?~3i(|xP`kpZnv{qS>G%Wi156rTH?Ks3+`txS2n5rNxMo*`@MP zud#Na3FLy9NzoJs_~jpaSDfP2?(ZrGODCBGMC>36qLyDtQOZf$tbf?+G%?!cE|r&x zSdm>$$e}U!VIV%UHrTLUdA4+UF6gI1XFT^T87U?T8pvA=&T+*2hF?cwvnT30?X@Sh zv%5U1u=%?%Ml@B#>1bBFLou)Di~OrXX~Bh)?+t>B7M|D3xQBOGA{*dp|BVzD(lq56 zl%!X0R{@sBk$;W45-!g=MQ%|Sh}}d@ybhxIHl#N})E(+>!jxFp|8!4k!{`0NFhW_z zS&0^({HluwS^Tx%pGqDt$>=0wPA_GvLLJr+4qR_FlV}1*r#^oFD6CI67QaBn!3_>Sy7G73cYsNUfFD=i$1 zzQKD2um&4qEaQ8ZAv@6v^^K$?J#%kaWW36vmpw{|IZ+hknf$n?WJr;f+}E1Z=>5IA zk*Y#$-QD00!hj4qfB*8=9zn}O}wvjymM-G=UE_N^S})4LAB|KKOgnRj1GrYIco80Uw}RS=VX zKB_QPT8}jDBd;1rupZHhU6EnqrrImJgXx=NR}MQTHOyH)a(dM9{f- zN;=tZVrnM}TF&K_QHiTvp9{Ou2RvJ1SoP&n=%LA3eCEFLiqc-19ktUOd{g(hk0M6$ zn<(|fb*X-k)nHmLoBcWS-Ft0rSabKa+kP|Siv6UR4BZ0ZDG$YRc{vHeQz^*D2!=V_ zA+Pt$Pz(qgm^7ageZp*fvm?K7)0x%OK&>%)R#1NBWkf9;x_o`$Td%)gng6Gd5sbH> zRle|Av4*j@gw=U>2MlM_v`+;r65(xH)Cd;q$sXN-R*JRi?2{rgEwIRZutRnYGXK;1 zToACB{?HE*_fh(@C|zx?f~N@Pufnmr6%0HyHEIo36M4e9*IiJbq@IlyknAizx67jZ z;n_|bz~+`R1d9r_p=Zw4EwH7LxUR}E8rI#!Er$t!;RS`~JYG$7ml2;-QttuNw+lQm z^;RXkjI>X>kY?>q5|5&P29lt5^KDy;Uxd6EeY3|%tKwcp33dRR{tW(ODHbP)90uZC zUaOvj=;yC?(O^dvTeeFfQ*V%32Vdb{sRmEN5%6A1enbfQvs3htJz2+qRp2A}yX_?B znWP~&inGs^{i$BlsEmgX#LjZoDwxGy`kB5jnLYj0Ic@JYvapN&`%Zz9ckq9W1Q(j% zOitNx&iYlH{C>QM{h*NU8|Hq}wjdxThcJm?yypNz%Khmt4kj+!@FE`9zXzP#GEl5Vk=8>+lzvFHq|bY6c!^Z3%E7)>MjOoEvDe zpLk?oyG<-1C_6TfWk=5A_k(^m`?p8^DrHCYhF@5|a7_N#m@l>;2ZFAGbeh+SUn_W3 z{=D?a{oHvgIa&%SJCdnWb?5v@4nqebKIa1p)3nG5rwvU_xZ>D4wJkjaW(b^OsDiJC zGC52pe0XXGJL|hgNI)vaqyjBw#+HW_A?vP#L%L1MO{&vkp|J-_b z8fGvZ+a8!sU1JXm_NSxaT^aj;pco$9#*R8(&qIsVl=@J8Bh(ZS-T1{s?5g82^gL(8 zMJkby564#&Z~L)Olm*+lVbr(h$WtOSq?}JgDOvzw6O4{|M9;jnqcUQkBd`nlc&x2` zv=*lKIvMjtO?3s?gnfuts0z*52AS|bUNURN51`&pFi zm!zM0ylA?cgnermv?IZ7147Msb^`UHLT47Bww}?;XngFW%sJi}0bLM^sgyTZti)mK zd)>wd;ps%sd5OV?UNz+Q`&RqO=8M`>&S3ceI$sf3QJzvvJW>YxGyPB^^ojDAjMz3R zWPBk}m#|U{%yGW2A)6}L`h)7QYVdmWsI4EGFIeaO z<*kc-Q+Fu#TAJ-m>WdJ0M=Wj3IFQZ=9Z+XFS`ro^N`LU5@xeDlt9?h zA-C(VAXb&NXV>}_#l;>DuYw$HKPA~w29gg4KzANNb&yFJyNCNyvb^#|_`#p&`+G4B z=diu)(J!rXx~^{2;c#ZxfsDj#xT7woE%&hViSBGvmn=K+Pp%Et?9FhI4em#0Rrxpn z3p^Md6%5NHE9Dd*Jg%_sK2i41%Mv28H$JWW9oIKH*y@oV-SM@U9MqYxT0^F4(wuc& z%QVN-UU>{bUIy=^!&w~ zEFPB@>L8xj;^RZ_(s+I$VEN6fFj?sdKd+F-)FZ!Y_tvUw!Yy7K=)OdgnHJq|@4!(p zn(3V;80gHNL%B#h=w`fo=2K2Lml7_(A3r&q!>0Z|t5+xbHvyD{GVOp;P;cQfmQE)Q zcQkL2oP)!YeGyc>VPfW-2R5&Z|8|85^NXzi^y#vSIP{=_RIdGR&1Rj{%)bEJ4OvMu zP?-dI1F&qiyQjCg&+_O_=3!@0g%U2ES9qwvofob-So2I)(1Wa?`;@5h=?18;18n>Q;{e zWbwjwOG&I-$~i2!W^G;hpn^anVbR3J4)cK6 zCP#S^eD8I2H{*7C?+Ii57kS&Wa=QvEi6(DL0(~&|my(jxN{c+y8d=#%jy2pEWskq@ z$qFuMsCaO(0-o^p5GUe5j9T+-G0ssfr*EqXBP5B@zEg%yj4{GvWG!Q98hl4AJe-`| zZ`taNq}A!5lg|ZH&I}Knv;<&aq7V4XLvNc1$Q>u95Iswz}S)$~?cjS>()0pQ+* zp|(u*E9_li)P=XVUhOGtnJco~v5pvi$CGmBD4gDDdRNTRqI4ZGhp00n!=_6c$mR)z zU;othNC@t`JEQi!ik|jZccQ8X^YPWX7t#E{>tS9+(x*T{q#)MUj}(XX3g>)zlFH%gi4-*3&F&OO5>3No=;6lTrDqg3+?$1&OC` zFWPd7enFd}ze7!ri8LSc(Ad+_5btWM6_iz7ki`$Tq6SGi&m!XsMT*E@7NB+`EDT;1 z$IXtPvb>oz+NWX>Xi{wp+Y(8%cey1{YK+oTL2L?C%J<(!1*B=x0PztD@MaKGpsEAY zP)yY=hjn>cldg#E{lcxVva`k>WWQus9%`4b_e2%$w9#pN?PyswI`Cgkxo1lJouV5j z(P+RdDUQv(RGb2Q3_whEdB_(1$RJV<^!L%C$UJJwqa*(uTeuv=N_peve$oX{CNt?i zIB)e_@k)AMI%f#8y_p#hCkndd6WA4+mO_AhH}N#r=^B|tS@-1c6(O{!Tg4aYOgFzg zzB;CrsfU6IYF!(BKJTx`$o6E^)<-a6ua*jLdPW_wmC5d#hdl^DQ4WkXMAyRhBfT z%v5dv!$&G;9YXbA#QCtNcBtXCaKV(RwVK0HWav`X2N5%%4w3F$jf5mgBEftBM5IMr zDs%!1(?6pEI~dBl^)0r$Q<{|PgcX(}Q0G60eSEuW)kutT6F7}Uj-@DGYnXjHE*0$h zADuSK%zTs7!L+59a?rKY)JcfCWDjHT-1f{dIfOpXh(q3@rbq|Nh1(<+bYDx1mnEN1L^W z?5Zpzy5Ft&2SKO+3T4QV$9}4#7_$=DW_-L<*ZSUjghsBaM*!O~3tvxVNP$hQ7jmRt zWS(uu^0n6PylES!G_CXqtQheaR@5B+@{>22c2cZ4vg96&P$h}P&rP+Xg2N*gz#0nHF})u5KLxY@iY6{$?HQt>tti@L~Hv}&@#1{-86paX(yymb8{Ss38s z@_YURCVCh%Nc*2~aXxj{e2KZ^$=mKqdz(u(`&5JYjgae!iGpX{6AN#ZIIlu!X^W5b zt+`YLXo_#K(&z;mqQ{(#$if|%$JoupRnpMYck}oq)zzQ5v8G6xCEe&xc#OYRQG`G(#FQEy+W`Z6mBMnoM!kl@FGjs95YCbX555B=;-0&yT zu>)A56ow`ufMIm33`m#hEgYfbO=%jV)A|TE<_E;Q~x&uHV)ZFvaTW38%*Pp_NIZs9~fsq?yE51Bk5B(q$M}vPj8{i9_|L zK`Rj`i^q5c7u4JwP2N8oGDwz38Gx7;lJ&V2HmB2q!@^M9T|AxAZ5jX=x|UZEt0Na* zzI=QPd?dBe2bCLxGf_L|kgEDEiV^h3n3$lUM{2TO8=fuFToLsP$3nu^D2qi+C`q-s za?qEmgu#a%GE>||RA&wg)uvT8$29GOmwfRxN9j|XX>37zq>E9rxx3As$%<&lK zeAn)3TrHr-o1(knpy}>0^vsBmCOS5Nj5AdXNr=l9K=0s7nn6a30m|hKYDO*K?*RC* zdtAkTBYQwpW zpk1|X`;E)?Fk~w$EW8|^nfzMI3V0%Wr>|Xb45rN_WrLaA_PxZupp_u9sg$16A*~17 zP8!g`IS^8$J@l;@z;61Y&ux5nqWA7RQt{I};l!KU;maW-MAklm0w-XZ+TcmM4G^BbR zVs;{LzC_psVu$5GBDX70nws4WnxyxByyd);(R;1Cja^08pJuBZ85r@%k@Us>f17g6 zENA=(<%mxo;GvM-ng(f?1r<6~iId_4_RARJGm))O&YbB&(fg*m+GK-5etyfLF?P&i zcqpF#+>~Co^Ys+bmQqa8y^P{DBPE5{A!E?70qKK_6J6A+`Lm^mGs<`P{b5d|ZIe`h z?p;wSUKl0>h8Ed@n?Gh{=XEq35^ZW~s*Kd@~3RwGXO1TZNW|OKr4Nu7mJC(5c8@g_j5g zVpX5xJH=Y0h_0XK-gzXRwV_apC^PwxY(Z9@*9>C)&iTpAH_~V>CbNpW94>SfKVle+ z;o2QP1kbn#3ZbCw=b*jZ|CEP@s?ClfJEUjqr)6iJRBPW?qo~?=_fymLcL(TImy$9T zy4`N_DY42U`vfg(rFKYk@{s;Bh7%qe+^1cpdV7t|GEGvIA*s_0sMIk+SIO|*hsdP4 z260U2{);#*%>=4MH@ePwiLbi*`>kM>>)K1ooa}3JzuTqBG*{|Ozqy<)LSA`s{IL73?o(Vm4fV@ZpJHv-N@djs;)(!iTCcypKTu~sNz zSUeOlcrL^1{A>D_#`kfMs>b!_kQPNPo1mO#tjLHHV=*0X zr$lvQdMqGuc|fLn+JaBYY^&!GwU5in+E#JFjMpJEjJ~XNG&YAIut;<<_^4<~w6ii3 zK$6RrP@{%gT0N3l{>xy>QHNg`q96&boVtYXL{^_Xqv7-ANy|j)dk0SD;+KuqJwpY| zqPP+uvgX;V^9z6lgTN3QH?e#vPWo(hFVyBr(JhN+Fb4*2Cu*vhvjo9aE?I0qZI zSBlx4P$r{Rzp{g7g50XU#+uU zx6o{}A#8GnWr^e`Z3=6ixgAuZYCD@`;&VP0STOUX8eF^u?!8u2#ZA3OW-tjBVCi1b zK6ZZ5m=1e1N_KX#cbdh@s!)BEO8OVqxR*E}|MovFqWQ~bW7Red-+n?d=)iPtE{wrc z%os(BvMMa3XvTwG7_i7F@fM2gnpw4TJ$y1icX6;t%q>`R0Cnv@7rVKSN9v+m&U=qD z{1b14Iu{OtS~shb0|`J#i8oI8IP(0BhuTf|&GV$}PlS$3H~YnAb7QgA@m>%Inr#_g zb++4!(}W;^PXN30gtD@>fUBg3xfeuc=9|yMO~{Qpo=~8iI#A-*hzaduB!vgjLuY6F zPC%r|j2C7=y1W@5!0W-J&7^PVRj~}{={I7hurrp64a1qG%J({y#oOtPxnH$8 z4-?SJQcYnd^ntGCUwyvGU57!FR#FLH`+qCtm+|!K2$(S)ROKMcr8+<&TZroik&2YkJJ&W@ zESe_BHpCCJtcKAaR}{wS=O8BU81%g4WRotm%mgBV^}3ew!`mwmRMY>X%h)UBVh6l( zhDeIU7{esdDRLN*S9TwS%&R!eKAsT zYYw+`Su}`fF4&IQwR-Dl-w)#3%vFaOXNZ57vFpilLr56!6FfGTI@}lYP3Gnd957D< zlCTcwJZ2Xpa9jrKA|9oejW7P5qT*x#?ECygM43;myi~eb?r|WTbdR6np2Eh0+snOl zd|6jBgFkjQ?4fps+zK=X?WZfE)q9L~94IBP>5oaW{~oLv)7T%cw2qHE$W*v~gkA>5 z!TvP49q*EBWC~;I6~Z&>H~ZNk4U=z;F1%z%b!jp1eG`KO`L%iL>>lx&I$NYy!0F#b z2C<%{OL^oA_OI2ZyDq94&o`_t{!bz;7Thq@{^sByhUYlZHW-U-mfeLHi7oH{jK*IE zS?Ld8fBpC}t8Y-2Hd>T$<~p($Iq1(!A~-VL)a0uz05I6i@<_m580Wd3lPaJSakxrA z7Ty>r%CGPp2#=P9NTL>mz^d@_^I2#Ls9EdObSQW)b-t$6l1}=p5YY%h3TyqfbdY+J zmEg~$V`YY1y}9l^H~3O0rlbEa7-$jsqhjA1@NF`Xk8S(ESe~99W%r^XY>@YO=4W~= zceO-eM~b61%AOMHYRLDT%(B0)ImfUMULr`a>!a9p)*xdC zmbp@@4D_dxLdWEib4Dd_|q`J42|u)K$wb6C;?}bz}q!IR=fR z9ex-oA5jB)M9l2k?Lnb_W*H4Kd8vwSTcEW9zbti}sheXO`i%5x!g)zm1UsHH^Amj zYIAOwxV#(sTWkikN1Im_Wfl}|*;0fX1V3kQtAvX1m0KXdoVI;tO<6~xZR$SOXR&4Wc1=CJV zI1e7+Nh?6n%z$86XQ#Wcz|LL1Gq3VriFQ0zBERMdtW%-vK$FXcZS$1~^#9XwfX@Rn+(@V-R00fe|!?xO@xlly!CuLX>#8r9Q^rSM*fX zo8zVH`pjBhJ|iFJA>kD(@pdCaMy|!|hqgBNABf%zV8dqg0ivXe@@1)B85AY)tHaHH zQ?k;csTw!cz9KOKQ$Le1UZm%prOoh$8s^t#>@f$UW@7>D-G@ypTSj2CYqPSr>PClm zn=W%{_|{_@zkY(FHN}>Im_4rtDkaU`&AQooh{v16MR1_XVZ z$u=aF_F1ZK$eW(yG9kWkS7MJHmXZ5ka`^60?cgJa-KKf3|9__;Z%>5fWTM7van*4s z_O+a3gL~Qf2wj3L-nRs3WIkL#>XN?En3xCWd?{k6?aWF4ZKT`Q`=l=;97d}a7XfWY zi3S>*!)sT#E>xyw%v_3%WcBY^joV!fh8{fGNvoBU zoLYyuPmBzHI-NabG0;utZ6&1y%L5+amxBf}5A$&U!VdyeuwelI#*qX?^-jT6J?DL0 z-s7CBUDuleJ7{%g1ISWjEs7kj%9uQkDyd~{r5lXuASgfOAh#B-QIA1SRR%64AUYf9 z^yF~0@S)ya?mh2n9AvL;bd7@#t#<1=eTr;}&%7YY4__>n>iTm|`ePuC*~4*hBuH1k z&x7>0`s*#f`v$+IwHRovi**|SwNCGK`s)>+QeMi$!UMDHyf6(HPo>Pg4N75-_-oW) z&=^-(GC$8ZdqGK5Mq@1ZWnbC>PyQY46KfLBH^S;KddNl^12;4Mi@asisxIgZn#`-Zo7A%ho?UHV z!4HU25ac8^DhQpn%&Fr<@!14^S3EV1EgDn%f zq>o`_I))q$kLcpcxd;_n=fo&q_zsZbr30ukQs(`&G2d!&M>?nItQ*w&Jh7cr8R(ad zi@txH(1oW)Cw7)Flz=#%AZlhPdw|@l@78%Q#O0a8zVhS_! zTKgn@^k;!z5>OX`X%sznG+Op$vk_jbR!Mza9KB1@_KN^qlG8`)ASz z&y!`O%=gk3tgd|+3hks)#NB=?f+?1AiYzm7eBJj7Qy4--_!#KUb-7YrsX)u#;ZqR@ zOxL)b@ep7nsFBp?TVmfd&qo5iESKvF$%4enrXx-`Lw&$%)f zQw_wvmbLxbTIB{8h|lWn-Nho*=pB}Hy`cw$-j^jWwNKlhc4E!At$aj!2CX|fG-QmL ze7EwYs zC#C4*KxkMk+3qndL6F@ovs2S;egT9YVq%_FO5sicW#K=Mqc#^| zIy%HR{JeCgq93!Sleg6U3P)!(vp^J6?d}1Od>->AXW0li6gKGfS zIlE0gFBu@Eb-bh)SO;TO(`(aox+=W?33DPr4lhXB(GUSUf8yoKZa<Z zxD=cb-df~m!*ZO5?v-N7zNEx~HO}d;tjr^BZ}1%xdhl%g>bO*8>`q!rke|4Go#>8w zSM3}$Q=XgPcC5Uy?g~Je2TSj|d4?Kfd-7LLuzLGoz1|KF`t`ZmU%uA&Xpaj6Ts zfnUGfU#ZPt`ib?-t7-FJo0+rz9~l+|3Q;xx@>abb?;{6$XkZk3!q-V$n-qVh{!K6F z5y2e1JZ{+VQMx|NL{M3K7TEz~8)CpWBj>*sh4dlpStO|G_yP?Qz0Z}{p2=IYjE0t@ z3K*sYN zN`jrOC}}wozh{kLLp>EICWf1pJ1AEbH;;qDiZ(ljyKV7YUP+dr5D7!4 zSOH)F3g7QJa7lpV8x}1v5OUbe+DHKV4{U&42F#BgqQmJ{Zam(Bf4LZPq#q-oKLmIrCI?RGsnsnc?fj231v=io0*0mhd(#v z&X=T0Xa}UKb>sX1YaN~|Y)QJA6)B2}v3xp(WPcg#-!sPt7XXnj@h}*5tnCkt&g{*$K-3`a1C8C4dN9!~d5iN+KocI4AGZFTZ~47+cDC$1Wj zltH(~GE#t{vq|xZbnOTi+8NZ~+M~8+XkPleQGbdVF{>e)TjA#oqL!wA>1-4uU_}?Z z$A%lf<6r9;RDu|4u!|SS#Ec1C7}1pHP(EGqe}PV!l$H*=2Z=8 zSq#yCY|qLcVoi_d(c1A{KYRI-mLDPmSFqrQEy;76Neq>D4OOz*QV1BCb!eN2WND+O z-mVd9h-LznkfuElLOBaxO5oU zu1;syK$S%_6??RONzM`|o*YWw-CeP8pLyLyE<>98^&pOQ5mRx$rs=8K<({+S zs~>59AnOT#;yZeJiF2WpfFIE}Svt3Eu>LlABf-+=1M7Sa%M5#{C1v%sY1qk49 zL5Tm;2#WRSRJhRmKeA#$@mEZJ$qSZdd?QhZ$*qo^CAbTEo(kv+AK&Eha45}j=C`&G zD`R0L2;2Xk`1%*tSnzmVkl5mdA{qtLtdGqZP&bLYe)K6&hLu!jYrOQJWq*xh%d}=c zu?hB%j71OtdIWx0I~3Bd^&+8*KpfW11r77wx2>k6{v z;46n(|4*hIu!A2%j2a!Ak{r9iQW++G1tH9l?G!DN+SXUe=B;inO{G)tBJe&HbN0^5 zjq*Wo7VN(QUGsUZVkXb85v7c}t)RW8TufTPM2q}R&(SRn$$T#!$E_%+k6Hbh=m0KL zK2Z*BY(C!7mi^9B`s5Leb|wYyBq#7!^Xz4gxIxUL9fUI zN{g?!2T}jDUlZo`tKbAmz>^{P=J6#840y=IG%eOi(3HC);kU!m^6^`-^nRcM)p1qJ zOFAOiq^4#5AXl>W=1V7eo@etiYlV{EquZv8m&CY|Go`?MAqo2%l9z_Mt zp040fp&3F{-5aDFeKl2jR{%tq(_|qASN{Pdvt-C(4dG1XE}}@~gIKR`3J)0s&V%=J zSC`H*<5|@#=A{Prvyte&*3gqynRom07=Op5Q)8H?w{JXtIo2(bnnu_Cvy1=RBiz9; zs_w_;W5aNiB^(loZHnA7+BVDe5zB=nfZ*v?>cEi4@)A;zu&bzKl?f#yoUY%11or7m zC6QP)$m}tUt269hwy`XIIHw&~9QmheyRA{wT@Ze1;B#&wlgc6)N@s|RsgAI=OJfd8 z%5WQ*UvFijkGIo`MpAt7^HADp1?eX*MMv>)ZMbzs`h%sel^Tmyx9Ae4ki5mOD^3Mv^Mty}1UXq3a2PI{{bz-?$u_%7ds$D_t zZ0O#P5G7MZhS?4pbYvBrL?Adi;B2>Ey`^B8KjTdH`MR(Ps@;jSIbFBUr zCn%pbgAT`HwsS(^^P)8TcZ$ffHN%rZ+V-+U%j3LEhjfh2&gamS?ixXpuekOkFZ8LP zz_?BHWV0#ojdm@LwkHL1bauSIaJJ>MEYs%g`AW`0d;^slM!X&s%PtZbE%zKXT_|9e zYOu^st^$X1h~Mm}=x5Lc0|>;AjHbv_)E1YXu|J0gm(6I01N<$Q6)Te0dI6U^VfWE# zXIh4P*p94bofmW%bN3}}Uy#}g2r~CAfhgN6q5!@Xd?RB0ILq(sY7gSh8(&bTi%KOU z%ME^J=9Zl(VA>@JLS48FAk6_A2Ly^fol6?&r&c|jJ1;J9NJpss0n@& zakxj%&J~Cmt+jGu%TuTNaI|8UJJZ_TXG+)4ROGVr%^)Odwmqfgr(5GXl=!8=9Ta%P zPirszDTZ{l7P8we{54=BSPK*|tx4YZye5W5Hvxjgr12soosWBTKu!+1l&O&F@nrz1 zsY59=hau%b-=xn|!99ZETSQ8L0J#9n_1XY6fB*mjPPGA!xBCW#E*%Y=ChsE-PGTqzj@T@~Ve*m$qIZclpOA`=hh`q8&gSK+ z3;ntF5jUvC1RMd$-YZQ40CxORk;g7T+t<@gRq%4LyP`K7tNm#t5E4hIHj1hHE!fC% zn2XoENrLrOo$wGFfk)qQsOj@sw_YflDnJ)?m1Uk~#w|@$)<*;|W#pLhteP$#I%{jD zfZ|4;8#R+;&B;!Pg>`2!OsKpeW|Q4ry*}WyJ2NPY6%`n3q|K@AbaVb;f;8n1u}}`i zj)4{>j0R{oq>X|es*V+8S{*uqcvtd$fEu4p)PgU%fIjFj_^=b$0)&@^tjd;0C5USo?eSxQ7D*vCdzjK51zSG21>i~vns6pi zd4mbt6N_NxEmP~qkAPV#Y68abPOj?;3m|r90To~OQ%6J&*S^NvKykpWM`w7_ujrSJ z!uA5MIYpDo8s0$y;ZCPn-6dgM>`<|Py-Arp&sy@MsZ0>9MyfnTY6*wdBQ(4YhY~^~ z5_Y&Qvh5APf9v}z>CR@v34crkqFi)Gz1?R%6X=QhkHFURZa6Wj~F{3y6@Mw;@3C`M_`*`;zV zCtIzxJr1_LFA;#XX;1OBxqC5}=j$KZelY7;Das*sno@x^cmnhL77v9X7e*?~8cf5f zS^jzcOMl_&58NOAQc9jj{uJk3R3+>>!-ek3Fn6<$OOVMGQ>^{fE?1~cWe+f|b12pF z>gy}6MkQs#j<>w>FVeP9h)@>|)xSu%;*>|KS>^%R#nHA6OW3R1b^34(1G-RFXvNyM zC|2CvdXJxfkh8wJ4>w?L28fYo8W~6lzj6emKvg9;Ez%>*ajg+PODuEwGIw4Om~6KA zKC3WIUa?86_4erq1w%f;OR%*Zot$P#^H23s&bAOuYyQCIItY!U)VyPgtmte9j`bBX zqIm?>Y8-6DlAK_M5ErV|aRHt&M~2Ef8t8VfVl14_{ipj-l_HuU!2wV+BieGCntPMF z25pJHfkdNIHv&Vmk1pI^o5u>jWA|IeL5a2ejI@5k61S$uAhW!e9sHl@J9h0 z+I}mlXIWO@8ogx@XKd0)N(@1=vwKxVMl0d;66ZQo4>)N!rHTjW_1_Yty6vJ}&lyy| zXFtNg5W?)>xj)RsliH@=duA&QxKe_IdjqTv2LsQ#VAlOPQ$EUzPwba)zye$`tIcm@ zM)LGJ2y9m?17}B(PJrogTJs#LZ{YZTuX}@+S#k|lgzrQ`_HYi3=P|Y=yeBDyMTm9e`+?^$Fzzq^^yviTL8XK^)FpSZ*<(emdPMv?VpKCa! z<|qJOetdOqHp`3C-3b3{ffb<8Xc7R~;tt=`fHHA_O@z=}>h$r}7c8&0o2{ev4B2(< z93xO_hbt&Q?smFGp#pB2_rW7P#ZDP(@n6nQyq)`zGO0p@KNK1hAihKZ5si5e(u=H7jvSLPPogN5P)E*3$XG*ws@BqrbGQsc z7y}v{mvn-5J{x`-V;SdHC;U0dxXN4k?|fE;;#07hP8b?K@Ea$#S25+IAfd*u!5^s>nUYMPbiUcCeNV*>bLV@tb$Z?%@dGkG`@Rxv z!_2(uXs9Wz6k8CgtnDsmF9;eAATFgb2tXPl) zbNGO7TA^e7(?|GPpTW}z)Q@vQ^Z(b6Sh8MJbc)Ooe!s;7vzVoF=mF~^jQT-FfwhRl zohH^-s}eN)G^CQs?&RDhjRg^t#&f+E3tKE4#IMIr7F@*wNhEZ=e=KIT7WEh2R@ym| zFV#Y{-=Fv1%4!?LTvfV}{)>x*@F=z8PiF)aEghi|WGWht)??|=!Jg-W2P?x+D_S`? ze;aSv;jHa@s#fD*Zd+p~Jdk*l(#?%C0RE;+jBiKM4X3q)`@0y+$n!mOL>;9QlW zY=3}<`jv0c0W!Ea9VI!fo;6=e3yQZJ#SbVCM#LOs%_<((?4#d=mR;FeygfM!z1mJB zkVJ|TNnDb1e-;TPZCmd$9)-sD8v&-?6gi?MtXu+ zTz|@qoWGlj<)13kdZ*XtgCrBc={!mRa-x9Nr~kitf-Z4~%evTnn2oOIO*SxT3os;r zx=n?9;elDLb2sIHxmT#0Rf6$pr!plgf+smlM!d?h7L?=U<>vX>q`3Ifon}iV-)%fx zs-dO<&q+A{P1;kEbISFN`m#TiDAeW&C*)7L5brgHwKKy+H2~@Gdw?O?NGi@i2n!9wOVX4QcCFHTSjMf1Q>3MJO>9ZI&7 zq_(!0?*&f|&Q%joP*l6H9UbJbt!Uye?|Z)z9iw6AUuj`# z0zzU&qf3RUP_04m&A31Xed6e%V>AP=CEtKn~)>U=gdk1~WA^ zn5bLCFZ-}64rasTj%v?o^*&W)f_C0op^6fHnp2%rayPwGCt2Jbg4abP2xI*N3WD-C zM@y$j;GfcjX!)F=EM2ayqz(F58-4KVGx3spPz2ik{&Lhc_5@yG$+cyZzO7&6w>&^u zRM)ApPI`79CtCuy`;+(Ln+`~P9{)S+p#uY!c=O=_oLLuwSJdBhLdyaNNJ}hfI-b5K zk>qZi7t#tq;ubL!9-GC;7H~5t+`nYGil)B3r&|NIuQgeeO90#T1FCkjS%g52jD=AZ zsLo_P?{{5Q55rEqkWjF|YFB)MvtxKb^;dK7<)e6TG2C(6WIoO#cv&s_wD`8w2XAxA z7WIy`%KSNaVE%TA8}?m+YNNW(B7|w6eVt~$_O@KkY&h{J$MwDdCm)Mk2inf<2``?jiJmviyNy}zZyA+dHQS}ua=J-t6P~pwU_yv zJP)p4UymPRM=?!3jL$#PMQ@{7+LdMpY z2W;M9-J%)1ay=K`bgtO74`A5&0v4E1ayW>G%${4J_VqqIP#Gbj0;EmX8*=wd_W8Mq zE=R^Df*02*Hbf21k2dlBBd<0iGGEWsJ4+`c+|A7nHyvc8kYXwa~9~8@6f_gp4zM zq+gj|8}I#2D+D657YO(Zv9MaLYvzEiH22t#lr(`Tx`?ICx3n9W)$pb%#$C8U@>Y{`HaNACA;Q zn+cn)Ddo%|=mDZl+nQHnxBPrTnZcj`u@By5)gQ`o$h{khjD}bTPhh2nn<^>EU4Hd@FersD(c5A`P$8n|3*l*+|9cxYWApGMu!y`=SMJ}X_di zt~62X^x9oGaz76@JU72-BK99|jlW~yi!psyiR{T-ixcZJ3OEw4O-!i1)#Cnmwi?{# z0QXV;mOztL1!La7!1$5|*EkZ!+O7G?^-W#I26x&9h&=Mn;bxDuA)k z^?}7w@$HqDdYOoO2eB5a$pdH+R=uT8V#lRY5U$`O4Yp~5gj60YpX#vn)*6=)Lpt6Z z(*-BF*L^PBBOxcn%6)Ha{}Jf6nVMH6 z#N=Vj2Z$_Oo{wQQt$*)W0yI4i47cD($Xw`~(ryCfQqoWV3yz?eSVa{qma&RM+EmUJ z3H$ZUi52pjUSaT8v@K#ob)BZUOexm4tkJ4Cm0OVLc;?Pjy$qhf{fbx4D@*I*(fz0O zg+T$i!{GufG4}NRekwFVfe>&#_L07)1X_)iLFJ)fVd}G&QiY!bFCPYioTbZ3g44u! ze~&vmvCsE^+bSt>{y!)FItSa;oNoRR&+PF+mLwwI&Uqb~X||&}e9u(0&^%rvzy-?$ zkn~j(rHCon7xf87D&b_Wa0`WOo0Oyl|G@==hOB!)?FCEjMg*aB%pmr5Eh_qzTA+}= z-4wb$w=Vff(ly>FcW-8_JjXmRu;Fk_71ZAMs-%l>D|8QvME>Qa`1vvigd5a~nY2oI zg|)1>AQ`Req9$2$Oy=nKRz#oLbMpZm{geygINIhF2`nR|1OGufT`o9tE*>HtszJVH zVf(Q7uE-WA8<@)t}aX&uA^dTW&MU)>9Tn#7V}8 z=RnnXx=C)m+xUBX1o=mbb^C^REk|qeQ;5c4C{@mr?KwX85fS z`|{OO(A?k+t_FLWFjC@bz#_%lTwxSUP{&_Oo=Q64;Xe4E($-yCEUkNpJN41)A`J@z z_^YnX>O^NbWLO2Jt5UG%rwXmyy6D9Q_3@~-C|%LR7s5zgo5@nJLeV;ycy zCks_ez_VHfy|lxfZYd%fj&1Mp%9dL7HoqmmRL+M|{@opM+8XKf4@YfHFBX(sA4%z) zR!}?WWH@{e|Cu%LgsNHGj=y*jK%I@RWU03jNgFINQh9F35si}-1TdbH zj8i!NnIAf@G~+$?P#yndYaRx&pB;`;V;(PvZu*J_)H_@G$=FshC z_!B~TOzwcrnU>yJ{_A*p$ml*@+15Tnt7^Z*wFL{~EcNz#b+l$(mXw>^`_P4XJi%b& zd2miW`im+GNy#>$SkX`MD=GN6wGgTy-0w6^i7l;pJ+L4@FZG-~vlm95KPBeNXaF(Z z|2X-8i!Da8H~u)wT*Z~=p^i~^v@)HdgP$0BGx*(tyPZ)qMjr|DClIriyo=;ED%@Pn zo6jm~vp?ONhUp=B8MZOhc=%zyrQRgXt&`A*{(SS74)h!Wwp~NVfXN-p#K~z&ZY{IB zOmM&6?fo( zBb7A0H~%yOt3+-Yy5C?x0BNxRok%RoI~9PS3)UsWSFmJWjg=* zB*T`|TgIi@2CEDiD%LIg1ncd%97?n=T6Gc&LYEfj(4sAzA=h2~ylRQfSxE?ji>C8% z28VFBvAYsB`|yn0GPqd&vC!Pue21h?iv5_3RB5Y=jR5S3D^KM=P3aTn)(<9^tx|;^ zY>xdD^{J#KKzxqM)o#bMo91 zu;_;?JLO2nij{*HlUGmpv??N3A?v3zDHdEpKQ#{R@O=}D_LRebpl3bzZlK!@jJtZ} zl)y2s{gG z8cyZ5aBhf14d!$(G`EjO%751XBx|kz@~#XnW*jGPCsAKCQq0i@?41r?l=-bs4xR#% zj$UWa8qqY~8j`b=T5%vVk|!bXjl;qD2hDPkb4nSMAx+;KnwrgP7erdjG~4P<FX&NJ!zOd=juL!lCyg_Hyh zzk-Fy4Ejl)TauoD#D!lc^uXyw(#l(sqmJ}LZP>7o@lnF$6gb>(Os#5VU@Fy87CKS+ z3>>&$Wb(yhMzRrO-g2y402wH|zmMn{0?$t-KT(UW@erX7c+M(~uDMSjeEspF1NnPD z?mpv4Qecp=s=+5$UpVL8_(a#VFa^9y0C-g?kTAF)bK#ZnP*tFwQVLA@q7(k=N``NEyAT9|;t^VKyLK*W$<$k~wKx1^- z*ejPGbT|v&=<$y#onDTPRxWAKgAz=nC3~yw%ok(&CI|r1WVT_hWWe=h-tPr=nj?ZV z<-dPr6p050`W_|SC+$dA_d3>cGg~E8`1CB@)MVrehmN)?TcnQ&vObJ3X!#TBX(+|T zj_L#}jS)OYxG>&Jzza&{0OdxA`uE@!ilh|$EHOas)cK_WSW}*#yad3Gq&?j8O8;|d z=8IUbvdo;B^=lrhIIWj&4#~p`H-`kxO94qSt$#ZPO!mbp*9-uV(Q8ydv9%O$o^cpv zirg3b-o-h+qW{3vVLC}^s{DOu+A1T^H12s4sBY{(amnPqZ9Ir{P<9h{JxS9hDcdl? z5j70W-rtaTxJ(VJ%wWR=axjEDixmon5%Z`LIV0}lrxw6%ai}n?1(aLs>)lgfxQ!k$ z@Kf$#%$dz8r%pmnYo&kq4DBPPAH|{j{%te@36Z)ybK_VY*3yCg+Vo*~f)M#ax9M!# zVCYx<>6BbspzCp1X}ytS5GeD(3FXd#q1dsH)1#4P4Db>MEIvSU(VBVowSS4{WcmW6 zM`xm7W5&P|(1mRsO>*xemYu5C!Jkk_j9y|{^15zk^tWrOVi-Fb#_gw%cU_#K5Y%Iz zBbxL}{L*iDp2#x`pnQR4vTpM3 zIO-UPQW+_+Z`@`;ycFR>l~wiGnwayzgmeP)0&0pZfeswtcBU|{fh%4{)LukOsW!`9 z!oihhLz|3OvSKm7(#n#BQ(+q*Akhv7pb(M2+qdUqw zP1u{t$EZAp`U}Rd%WR%C^?J-G3qe`TGfW+h4r_<4#nRXiM1|~I01SI>Ck0ll@X3#u zM|1AJ`0%Z)4=*2Loogv1#i80-l-LW6*HHy&u(9?K|7FRP>DccZd6t5$WvH5hqc5p< zQ18YhOUXX$FVawf>AaPAaQ>l`B21@Udr~^{8>+eT@*+Ba6rGJ zDm+Q>^=`+IyW}rE8V7$5UG#sx9FkSVVG=US{nwd)zj#J`{kKzO61%P}Wc2c?X=Q%XZcy}revt>nUsJ4KHE3+{fb|@eGs6#RdXoPn#bdV7tC@ZvUm7I z=1WQGS2tPEcpLiJ0T0=nPM|z-23);ZBLj!*Q+a%_z$=ZbuxCyLKh>Kwvp1{5WMsYh z$g0)Z2hM8G<07$+ITK6}_v(`GfliU%yrTor>~YJM8OyPnJ4ueLZA<|WSLh5frK)QS zu(gFnKm7y$l&Sb{8*&rATi~d@vo@es@ZUm+JS@*_H6w5s%K@pmwQ8a`sCjEwZVfc-z2_;lp8t?d#{-eF&~ zLpIcaar(NqTl;BFg2rl~KHJavb`;d)S3XQ`ps+BwNjM9kIFKg)N0Bcgag6*c!LRPv z1juhR=f8n%3I6_DRT4j#2Om4amD-se#~C)T5Mo?jyoSWzb#2EL&0;)uY18fS2vXH? z+l%gJW-^LrE-!WvD6%W3`cu$1-Q zU55^9g07K9@00w#O0s5(EWd$4>xP7@+b!~^&qxG$3zVT+6oLI(B*PJjduc3lqc8#x znL0KiKL|b>gT}&4?QeD;Z1XTcvId9JvQjprScWb>hgwSX3p4bQE^v~>KlyRaWgz^$ z1H2m{qhYH^`{pYyqm4c7ioEibbg&kfSoS6#EgWORs+A)a4Co8b>sy@{n8EyCcdkA- zx@!e5Lw3{f2dDiga(qEC>9vk1nW!f(42NITl$Z(QV(ysyj4@HP_q$ANDr~)spPUc`H0=8_&h&V0E z25m0Eprk1~{T25hVtv%~=1~7J^GVGC4eOvP6*HKCUr`Ljt&G!rv9zbp?Ycp&dpO_7 zyxZO>E5_IiW8o&6n?63jfzq}oqs8nKC;9ZT8Obe}+w4DG4@7epkR6qa^kF0GpKENL z@ACm>MGP2cLa>og*>(>*n*^^&3~jc4$XvE3azVjgar=scb$clvc-e$SlNbmm5D70h z#BciuBc=RXzs2AxZ>d1eOl8xD`W@Y?q}61c%1oEI3X2Ko%+}%PFzzG3{9`NfY(_^q zUK7Z$P(&o4(6PHKQkX^2{KI6dwkO4Pw80~=?m4Q)dNr)qmng^(SUIO3`PnE_S_#+! zg~`DT4+)xl8*p(a--x_-nErm3O63JpFSe#SrFmjtI{1Icn8`I0dkRze{$NNaqXgfG zc<9WeF@7@3U}z+<)^{NZBmqVh-t)ulAP}}&4~%40jH)`FKP-%u#juuEP;TekvmIG% zn;HtCR93Q@=B|B(LO|S1o`Q@AaH6kv-3zS*lM#na- zuBPJLpk9KdQK=K9k5`AcVxPIX@~wg>j3}VRu=dsW6l?SpC;}G%7Rj5&jZ@vin>D%62a__Mn{O z(s90n-P_4kJ-B-b-Izv;@+&v(+|zv4dRSJh z{>jyw>Sw*Txgj+B|_G<^R>j zn}L{lXgtFE9Q0r2_o}>SrsDm%4`nWS-`3zW``(cQd(tyb%IQBiNTg7>SaFof{<=@(%{L;3P zdjYAP_9LmfjwQDL=v+Dr8vBM0_r6~EZ!4~%KE!D!<$=fiCRaVM2}!<$BVUeD->DbA9^>NA;Q* z@e)*@Ps0%x1hvn<_K0ujm)>bE!Z8wCE`_lu8$g>)%8Y$oTNjOWy}}q`32utq2PMSKd=RaQ#tbOf>SpcdXVGGZW18UdetwT3x zo0&bft?Eb{0R3KFDtULY2uR<=0Ov?|D*Q(5WQY?>fYqBq{N(w6q=gDTL%rD%8>I%8G9A*4np`Mt&F0 zx(gmLcEY2rgfw%KVn*Q~k16Q&%K-mt0{)Tbtbe3;eG0lJXW0=m!PWs$DXJi0c|@jF zl=8D&=C8NHluCeXK!dpfi)HzXuQyTDTlC*4yw2D8woYFbqq<|2+?|f}xT8qJZrqsO zg#=2=jjqO|T-o;T(?nTPN$?Tp#$1Snkdd|nH9;n52e{iFzONHcmO_|ko?l9lay3{e zxBpOZ;M8W>KLf_hqC5Mqzm}*a8GQG)<|;(Kjnj0sR)4FCib-76T3S1TmOG`qhTXIQ zZIW6U=H1GiJ^ygewAij22IXcRG$K;;JV){nWjFndS+`1b9zieY=@^eC2l9`&@GmnPD?3!Jt%XmYtJOXU zwX@;6UvWbW&hRX(TDNjQ3aNV(!Im9YUE%hF4M>ReKg9Rf$z;bA#dBvlow(#~GHF?u z?pcZbfcw=?IIC{;>54ZFq|-W^IT{gLw)*qbOHVG5Bpq`rWEVB-vvq+hPNCVge~HyB z#$p32-7wflw2;?G=Q*ns7t*1Iss^la6On!>W%Si9|AQ)%E_b<5QVC~_&tl$f6aeC0 zN3r<8#~78Hzb(BW2c=8e!i1qu3T>-0$z>9*T_>o9ui*~gfVTOldPX4;KREIu;^gqa z=-GdGbSA+*QRa$J+yfTv{VyLx4%rMA9!~o>`|SvrPT;Fdf#%S@9sKoGMz%B(P5U=e zGx5IGYgsk-0%M&bb#-{V;`shLbA0mW_&B5#rNY){q#BdAH){aIKQ{gmEaF_Un8;6A z4WLyye{7_~YVh36V*SeFobe(Ntw5xA5~K4UC8nnZPlR#Rf(Ll6HP?q^qq9m;c3A6@ zbsl=4W7F!is@1e+f~st&rkY98S<@H;I<;yvE0^if1(G+C{zD{}+p)i5RBZGq=tiBj z_?Pqk^D|B@HJb1}DeYSs8*3}LRI{OIEqh-^`NDr@fwL`d~U zkJav)Z?)hpPb}C!KQU!^unka|dslEi zmu;x*wcPx@K=(QScU$N=#-mlR(Un-HMmcodv$2TlRu;^b5sVr|7`LYz*caz_YZQV* zP^X{$;BNpE(;A?9U{VFWGYe`nFYIOF0bx|yjIjam5y_CIU{L1j?x67x#X4Fl??@AsPxLA=a$8g4wMo*d+b8NQby%MVg6 zZRI%9I`a%@NJe=Hvzb1bx`9ut-g7Fbnd7z;=k2aws)Y zMi34B_Oo7p#L20$3}=CM@x$D9Z@ovH#lhT`X_uCojGKZ|0-JVk(^a9e-xa*}T z)}L!b7G&67Xd3SI_)gS7{H>hrL<>jF=pd$cg)PRz*smJ)ys63XMdUOH6W_17U-{g>=!6v zLD1WBai+{t()Z}mBnFPUNvE?LsTHKNn{Oplbz(guC8bJ$FQp#+TXViZs%Be>3Dp}k z_t^g3`bB(=h@)`}Sqs}>$?Csg3L9KaFk6G8A{d_gm7xeeWjdc?6-w}Yi6zGoQzbx? zWT!AnpR-`R!0P&hee}hfkrGH>);{1j1X@vxdP_rfGUf5HT{xK3*(=l=Hw^IMPMo4vM=Z+&vo@4Cvx2B=frrPQ$ zFlhJlur_CZ&*f5;~7Q zts8Q^Gxxm2d|#@)9xTyivqn{alO#uHoVVeqY+pWC%$VSa7&;~dNR3FB*8tU3$4zJ) zJ)x%K7HKBUh$MCsuW!4tV2q%hA6h>FPg$O8ztiqIu-=q8AJ@^zHn>-yS1CFJNWfD_ zy%xx)DTu=|6XiB+h0_IO|5aN!Eh#0jf|xVNe*Mk7UcqZjfVTOm1x~WezWr3h9oYQ? zADxgr?1P4h+-=Q33;86s&0n~N1g_RHSsWZXAfydLZx;!K1jE`x)n-65jM4uu4Bub@ zE?VEEv~abz{Sxp1omK^whH2Hskb)cCs2?ku?CvVR=Pp#rt@cLFJ>2e|%Fg{%C?RmS zAfu~XbQCSVfSgxDZ5oS2fvS>o!K@rX6I*4~{vhP;If4vTKLWmeW1EtZf}O09roWhP z9Ocg*YZnF8_els2!!yw&NWL~86D4h?WmA{esRR!})$ZEkF;K2{kX~zlZ?9~JckDD;;|*1t2n-(RcQZ9+~o z!SJI6-483Mmi!wBit$I#w$$`@hFO#KmyeFq?;lsYT)UrLChJmHfp3u)7hMg4m?PAL zE%dZh-hp&eZ@ic64s=atoW_sT%hjTL4)E@gTQN_04T(f3QUcNEEh0p1yfp3Ofm3MA zYo0HP_JL@D_^bx3?=!XR(^)v@vQdXkO$Y~k*R){+V9nC@R-^nQ-#fC@QjH=RiA<6h zZc6|`K)%1784s;#PP@WQtD3FJBK05;{6y>sY%x?aFSg&;BgPwW8>kef2MNU`1FmFc z5QK~L*Je6y4=I(SdKovr5+CfaYqS;(0mmQ&qIBB`vwqz_BRn&Pbcy&U3L~V1XG0Ep z?dvMa2|5Z;xmGhpX_@vY!!WV6drCo8+w+3IfsT_{&WGrwH}=xwCw1@O!4Ke`jFMBQEA+c)OQzoLkGl0@ zuBaW~tTnB6LjHkg)1npCYzqBO#$~!|I&H{vinrNi1-kkm)P<+2FzQ9;5zT2WRCx+ve zxMml{w(h{%NmrgGy^vO4cgW>!gjx`L zFM;7_p!dTF_Fl><93P|{{X>EUv;wXB*?mbyuqq_-aC|`15ElEMef6uyfAbHt+L%KC zWSgD1Ar$^@wv2F@=-=5($dX*>xSGr2P?y!UNc_sN9j#7|A%R@+NeM;EDvCzoQQRtR z7kMk2#m$4*o^>6F2eIs-ukrl&Q3gKH_gzIdr{12mvTt#3X_<{L|G6r4+R^L#?s0;@ zk0ZhRhk425ayFk64z_%*JcqABN_x?k ze#tJ4CLRZ@=DtDM$h69>{o&}t1n5*o{<>6a}FgL??ZAT|0po{l7 zz&n6^MrzCW?<3J8b!mLmCBlEek|2!|twp4(Iq465@A-;??*u;l)=+L@+O z-;1`O5uSwJm3w}Kd7np^Xa%B(*U~h6pudDt&2X;4(UoNzCe9dGihhH%fkXP0e~u8! zbPzgo!I{S=je%<;UY4D;JVk{=WLf#-h3RvyV8xVPC=6`tp*M{qPC@|?rw_96aF{`4 zbHB5vR3$$+HIFCM8dNU^!%_!}T81Z5z*+}Af~NG;cjqmmuWmTE<>miqdK7Uu7sHpG zfc=KHCUA2?WuVdcfT{Ot&yY?a9F8%aQ@2wx7gQE_HqeMAWYyZiNRJ<`rB}(nbfdNK zd%MDb_Wf9+4a(J)nLYnB&PJzY_#i5m%U<)=xR~3&o_B17o2IbllboRWn9Q(oTG~jq z+EHxvXTEvH3NSFDPnWYqA!{+OlFW1Q4CK>gT}_yr;3+W={PSZ?k*4p@+8yZps2-pv zWKfK|DOlSa zi&**lddL8KcQ|&g#Z$cgfwSOqqN&mF0s>-H-Ie-Gg+$r;!^MM)kAaWwmOoMj0+yc1 zB!<2j_&~LWYZ{2jL^hLkzGr-+^pqMhItkz6x!uZJ1^!lfQca3@Od?nFo)W&~UF4z%xE)F{2SZshcHsf*! zIy}DM>>(U3c@5hkVja#Lj$fD4NW&s>KfwQHo>>e5d9Mz8KJNrD_A)?G7a$yOK7*%iD9^n;v43D!0y5 ze2x^mL3g{0|K}c?yBH%USLZveX*Oo{a3dox zdHzbvjfb&=UUA!6{JOT&R9D0S(}#F0?X8q4GU|KQ{yqR(`%px$e>~KivmdbeerV+? z>zQ|M)x#YUhiD?syy3FTUth9niVC#9QWA&;Fkgdio*0<1aGrp46I7xoOqt&1{0KSK z3f_q#X|_XmS^N@k?aRPkNVdd1lWBB$5MZ;m4wb9P*0`KtTs`-Yr!dY8jIEwq=;&>@2R;|vN4N7tAJcV*cimyfVADWdX_YN(rpV`Etu zHnEy67VY8P7sPkkAVLGQ_)H|7R{NZjzu~W>o}3`bEFP!Uk59CoiBsUj`5V}bGZFim zulA_KoMQ1^bZ}Q#BT!@Eq?WMy9z)c4DFJrKaW}waEQf_%HY9Pe0g|c&?wimcLQ-0* zo{Zn#I|g7-yj*RV{HR@%c~)12z`QR&2V&!8BGu>#H{Ca0F8nyqaW$?rZo7~S%jibi z_9@ymNpN$yJtUci1}f!8v#1%* zPb%JQ_2u_WvY0|PFAA%|eXV^jAFD%I)PN+M7$C9F9OiwgEE`IrxKb(BM zj+g!9&_c<|5qa>JE4P~)Y8&i|(D3}yW(FBsR%u-j;ad%970p&-c&}!8?_@l$aDY zZC4`QX}CiFzgc$<2jK=+oBb+zP7I-5uI#XR0cGMk%D7a7RlTrxK?a3kB&|uI-3!Rk zzRY|$5BRz;I_RbJ>rvlXMG|x@6l9}^9~Fj`N4l|kKR~L{MmI-{_4stE;ht@o=XGRR zo&$cUX7>dS5gd;5hFSxM^5Rn&PUR0>ipID&})o=WBCS=V*3 z4tOhoiI9#jdc$>$*N8!-su5Il5^4zgj01%r5}osaZ9w%K-BYDgtg zr4&n{F=GD=1c~%5bvkRN(k3|zLTndsWj_PxD4!5Erh?lS>Il(!A0-;p7WK7Ax2vL0 z*Bh3A!5TDLFWNW!$>F|-GyO#zf5-pAVR9>H5_Zr2YZ4?5tU}q!nH@aJ$B%_@jxTv9 z-wZdSJPgivqiJPoIh}QG`;QwYWmPI=0MSMf556W4)Sx&|N)#bu1CtyUt)jovmvhD? zD%vq>^dG@Z^ANe1Odhke_~m15=g~$<+tJ=)KNJ0YdCg5-y;RDu)|@W~<|at;(nD^G zNFIp1G_d9usZiXN_>1fXazuA&mY6{;D0xKsppf@L+c$ub8->JyhHC7Wwi|5wf;tSW zAKgEbcV{SqwRPsPICji_P9-*X5jm&BUsxwACW-SZz{E((cw0Igua#qjv>yjS z8j?fbzgyQFadao=WTbgC>;MpH)HFA@Cq7p}v9%X8mb3EWQXeLo5XuX7xavya)qdUA zhq6`taJk$i+-P8)m@dBQA~PxO&lahTupOPuXt}i+7NzB1%<8w>nXmYM^cc@@x@wOv z&qF7iBVmA^W;3q;_?K9~_$m-}vV@He&bawX012{o8zdw?8RO!zqf-MSWXxUE|gKLNE(QKhuwh=sdn~2!&jwueC4`&ZT>gJFTmot&eQPj{b~J8nMqRFTu$! zLu@9Uo{Q|vx(K1@-p0Gxqnz$Op(qO%9nc+l)T@b@%2B_+PO|U#iT4T>$q50gzaVo0 zX;fd~6R*>T`<~Pano#*hZt7J`0^K_fYo?y2K0CdG-&BQ<5~YZ@blu@v@_2+XjHFcS z$t*EIqLLQRC+i<_W5Rl*bl^CRSo|SAB;{F-z@UfGrU71L=%B5^}Z zEh}}xm43n-YGq}(!&nM~QThgAH*SD)%?!WO6=Q?>UJk1qTQ9tP!z0~Nxjmdr+AVo7 zv`os)aUXm&Creu~jv@T$mvH-juX`F!FszEZ7aC-n$LF&hfj9>xUGRG$kq27>Oq-?h zAMsbO`>|?v#%c}4(vv~LSv-%*su|XR4QIpxN~o^^`vU^c#2>Cb#2o`jV>2`L+@g#v zl(q6L^qu5^D-(Sl1K0mtbt4|I1*B2xm(0clsw01-Eo;#KSzeI+p|z))OK1&S$<1E> zEk48z1WjV9#Xq!l`p@@M{d|~h)I5{Qt^2AngTL}1^CkRCmbWaNb?}ep0LYd0zkO{& zl>jp_%HT4KWM4R%Xylk2_ZW) zEF+m7*e2dExU-%jNZ}c6GXw5V|2CP1-BbaRXwwj`*E|*5w<;d(4Ojmm>G=Ez&|SuBa64ze$A4$y&y5I{1AhKedql=L+-T zvqz%sxT)X?1u}}+L!7^}-@*lRzU&qh;6o=|EIw{5lnz%6RKhFnIIg= zSN1qX4FWN+tP4)e1_THFU3v|znUOx0!gS5Ukim$Z;W36Fdd0-tPJ*vv)>zQV7$fU? z&2GjD?z2Py0rk>=94>NMbO?dG%L5kmWo{(nm@dH!$FO=nAK++ef()6oj9D{+nA0n#lOA?B}aaY1CMeaV}~E z5fQp-AI*k}4JqHblFiHqA_lD7`B2v;s;zz@x7I;LD+kiTTSACXFk3 zJ!vOEn^w_xi6wRJyYAz&I;F7{jIW*Dh5O|4QPBlf{`7Y~Cf&RmCMCYHe?`c3GIaI8 zesW6(_-dziUMlX?5?}IJPSH72&xL0H%LLe&PTw*0bVh<1Q{h}ar~(LZ?)nDmBXQ6n zqg<4APB@w4&7XUj+I<)*B_q6K7Nc3+w;`GC?aXPLSGb?H6EY|N>ifTgbxiOJ2clZx zxDZtA$9*Kgl;{W4n%#@d$z zo=({mZ&*G<0~=nPpC#LBf)F9OTgB9lBb{&0-hGcv!%~l%vF(p5RjXiEO5f`(bpfF= zOPdNdM$zfQjUw_i@*6Mr2p)i*7y+%cZ2cus0C0W-ho-f^Bd+?!Q{t|;Ajt#SsorOw z2!dAFyhs&*D*KMnoBEVi+w{7ohUD5UbZ0%TE;{j%Ec;c(30FI^pkEx$L@t?MoC^yyL5;V0Az6nl3f zd+!&T!Q_1Hy^`eFXm_ydGG89s`55bcWK3}16+)$S)okF#>0lN`iQ4@c?I?m9R;#7Z zU^fu#Jwn4W@MnNvZ#X+D8Nb_WFdatU4@*ZP-5-b5ZymR75^yhr5eSXPI%0b7W2<YE1XD;`B^)mjX@Q|;_+$3KR`n1-bbF)rK9q>DD zfL;v{$U9(o%#^^M5@Uo9)HbnTjrDTe8_5bVQtBs*RFqaOam9#WTJWS_V7IwC%hhbI^oNO#yh>v zH%fE)f`7T4jVik_y|ZyYny9u>yeT2K8${P#<=ksf1ddMBj+_}`ZDHL%|wb?-1yD06GtcsI2IiXy9bkOFE4tqcXe&>?-KTBcdIQ_p$ zyc*XtQlM~GKUee6W5>z^4xP2{%UoQM!P*a~Z&jRy+%c>|$)uU^)j2$KzKx09-!T zZ{`et(~P)~q{(P*supa&DBk;|O=(OZHr{5z{z&Z)4q+@8D$Qu5cH$?0!L&h)p+k?l z`s=$g-MdE=M_Nz{5cL!7LI{#q~Q=pTr#{cJXi)M;b@3YZ|s6Zc^gKhsPgu3!A&f z^PbuQc7%l1vtjDQ*Ec~v0=gr%Mp&RMF-dGjQ9^*RYbCDtw`e5D(dITJ+$Pob1f3M9^!_e!k<}#WkLhn7(vp6`2(%}+}hpNItH~O zY`RuysF<}5kHHscSuhk=Y%C$~ki_DATs4%AU9pK;3{v4#%LYH>5Zah^lmrRDL|Drj zM_)RU4;pEb9Y%Krzqr8eEC)uI2$QH|e4IZxOQy8T`+D8{l}vUyz_m+fA!{fyzr=*+ zbIC=V%}tn@XuqIhAO9y@KqhY?J+qSFX^f2fFAETM|Mve^Lh+qG+H#0D?Y8ah$RY(} z{71gGDOgqlHIuhZsK)~(Nv3{a5*P^Ntz9HL^JwymvRpJuNaShVT*yqVoO1%6#L(dVD0AkoioGzeJgYs&W28u1XB@jW z3(T8bp2~6T(SV@zUd&TyrHnInFgjP=Gh)tJv?wD7Y{>(~-F|crUUd8{5-w7OF(oOG0ULTLqu0^dPo*(O~h8L4{pPu>wx6voGnn|>TK)Z{Z1h8DlTwo zy)7kWcS(`&83XelifV)xIG{o_+u1cecayr{VlNbG2{-4hkqDX53x=LU#s?h9-TG3g z)0T!fW>jw=UXt;I?)?7XFkk>wDWo&xN)7Neeo&;f%3e(^@OXBID$KKp_e^M-d4mW> zn(Y}GFk4g=*8^I{wa5s>!lH`?ppaDck*Maz-v&>X^6H_4QB9z5iHqZdpfz~siK;;V z`sXh`l*F7>2X5FFR|u9&%8l*VP+Ii6c#dx6?d>+OH;MMC+hQSold96=>rLoy?sKNL z#X+49OXBZC0-n~miarqMR^ci+N^-i6 zOq<`@V?Q++@^(lLR|q6T=mCl`7CLgAsg^RXsa6RJ+&5A7pi;_S z5s8p@xtUd1i2|zBk4YzABu(YoBuu<`&S&7(xH@?$59TBaz|kE^q7S7f==1P|E$YHY zGRmH-Au(HMJ)nj31omyRW5uo@DR~2YHSfRwQ*2AI2SZ35;bN0-qvtN*w1|;=MKDop z`p4cDaCvRjrXZn&sRL6gGcPPt>Od;aojRqp!x4%kr%hy!OUFemFLGgqO01Q!y`A! zN&gPCd;y{@xKK$+AZv7%ithh*OE)4qzvQ0Us*>;-epa<0ktK?o3IY2$PWYoY`P}y! zB(=%n6O&NQu#^i&0fSqzkt+{rw_#%jQCHghcF!3#rdbn3w6Ytv8Skz}@94+Gf}Exy zy5hE>Q!zWZm#C(y28kCKtRM{V-NRJ%kqb`oA zN3?5qTy+8TrT(8z0-r@}%t1r)4*(?T%ehN)BFq{S(K2!Qt!;h$w}WGyniDPNz@{yaC^vkcppj z&B*&p*qPB^yUOoKo zLN2gtloY}*q}a!JCW{{Ah&g_mcO8G<&-<1J_Z}0cv>%!UVMEdR=QZ-QPR2v-pZC23 zuLUi^t7iv=9IICB%=OB4i3gQ+9=8CmVvUbr*FaUb#vh6`qZ@0O8rxjKBAAX2t#p9a zHqo)m#WcB7D1%TiU5B%02&zoIw#)bHE56wlf0S1E6}=ZY?3|9R74WuYY|ypy(E46_ zs`1tNdYutkS!LFN{SfNdRVRmj#d6mmDzOXI`OHE?g_8qa#z}Y!pN0r;o@eaA>`Sf) zGv^OO;Dmk>!x~$5WAFugrwl$iw!x-R@#<6tER^2Va=R_ZU}aG@aI-JKLcJPW=9qCN zc;2n>pt^Obm{++sg+QqB@bcg*F9e~1TxNml(0_nP0Gu1Tc_3QvVYhZi7_96>jKfv6 za+4a_vZZ?LsT)mk40I;a7076(Axz0CEtL%cFa=5HX>uj;v zz5L5FCCI!A)ZbU}tIuO=k$t%E8Ix5jCKXdO@B6F^G>QhFETH^&aw`e6byRiuESXuo znpA7qWPMK^nUyqf4)WHQ{IBm$r;Yf!<;&I0L?U(lfuP=5hyqdlPL5K;#`pGcZDSxd zSek4XV}hM&`}*MA9zAqEG0x`6w4SB=g z)XQ~e(_0YaYMFMF*_R*6p|ACJbN`3;C6crk4id5|Gb4jFOFhB*hY%^DYRExAtRmB^ zTlX19DJKtFUH+w_Y-=m~m6?f+?_nyfYplYlk&9BiZ!fjQSc z>=F~)g&|FbkJBYCGf8bQ>pw*zAZSi$s3FDo+w%tWv!^vgwIL-u$X9u;?(v^aaapCL z5|e|*Z%MTfNe}*388uvRMTWk5{70Zj_5(}cd1u&cbU(JzqD|Jfus(J$H%+B`X;3aX zp(~t_ZhY3rCPhtvB`|4=sWT+7?6tVw+z3bgV2a0*4%lEztzUg$)hs#6@=}Kbo>6I& z)TU35Qfv8EJe9xhma?g{mrZCcSHckO5SiTL!~UBxhMDh6BV+lZF#QM&XEq9;Vsb)@ zd=s2;&XcF599H3GsD0lSyY>c5DGqrg>8)cRQ#5KphITK}lvUG^^@%D7`gnt_lqfHMyG0Sq$7*zeWv-w(gb>kE- zvkM4^EmM5_+qt(Xn$5N_AET0TrxWC+P)l4#81U!C*)?X0#4Z!$W=il7BevGs+?qmP zOMBL%das+6=Qi$0ZdOA>U3-O>2&XO;>d{DHV@P~`%^>Fg^5lBTOUr^AW>Gdh2!k4 z1dHES;qn#au0kcf=#(MseOe+;8~Yd(nyJ5!@CGv z#-U!eFZ34?Deuo0OcPFJf?s?V+v)QgkA_>@Cg~Z5D?nD-vA2EVQ5#R1*_9$7EuBPg zj`1+~@QU*o)y;-mKersvh!WeD5baVsQppYWLz-k+tde_eU6}xFTYT8HgVmz2y~8kz z=}Oyj+(VVt4t^g{(WB=LawZ2Xgb8t~p7SwLKC{$hzh`&cnE#K~KeN1?>cL2i?JvCU zGo{X&N>XFoV1Pz3da6m?`}jmoDMl|}7YKpVxfK0ZMH;CEn~XhJPZKPjs_FU%zd`fr zUjf{8+ZJPQ!&*p3h#M)0FV5*!vyKq{c6-~Lg{>?bDE;ivuFHslk7weM8f zsYHX$TWJCMmQqtdiqEN>AZztKk%ljJJAOe8DJKN+wFEDE zM+l{2gGCcf&YpEva>U5p@Fta4y{5?FS<-1vxi1OXEK}w@XLi7*`%AtC}!xdi+IB6u{~<;BQst1{MFlkstQ_Q2dp2)J;{=c>ts#h%CA5Cd z?RPyJ{N(923yQSLhVcm?LmwMKw*RBotZE5j$s*%48XExuMJot7ydSyw4_FNX@Jp+u zX3Bt|21Fr$CR?Uw%nPMSlUq3$m8U{02LQ$zrlb*B5bQ}Sdu0ZO>7!Rf`&Cayfgq%y zQ|Qi`JuETbp`S|FT#R|{ahhjl@YUQmr4uO#)=%vNIh>>;C&(}bvN2o5cNE5pI`X=m z^rLCv40Ir)(AiYrlYZ6C zyiM3Ti|PTWSv6p;s2W;lHrtuL+^(pFg7^6K9aGUMtXWs`+qC{sYqVD7VwAfi3yKOQ zJSQdrIZCBGF!lUjbI!lRM(`KrA3j%x@a%EA@S5>C3dWP;-G&*X@&bBMCyugpOV^B1 zmluEpL#jVv5z0$F5a^V!r=POiLaaURihMSquL=Szo1JN!^GA?n7nyJ;j~4T>j*@nC zB3ZA$-7SGn5<+1ECr#C;ZyIpMJ8+r;s9e@r!IR76;FEwD+x zMxQv|cc1BKA`*;#N5BXg zWhdi{$MG#NM4I@`=Noy|5O0!l7(JV|0QkQ+J~E8bqac3sbIk+E0DAGa50o|&xn~6x zfCy`O%iw3P1(M6qweMFn9*v#K{`snzVVzzxQP~pN^)BOHvWTS`n#WXHN;L&|-OU$E zJ`XS0?#O1$$eHf=@Ba`AMa~;SnvqCvgzQyR zjKY(>>=&S;OpLd_4cSthuzb6T67eTGVFpdxA>C^35z22N51*Snv0G=p(QX)k*xUMY z0j5%R4^y0?@U$JxzuC!#zQgK|oRInr!CgjDroGR*YhlLN32f9DsB}|J6h4o6BHOP! z)1hsjPA60Upx%FOBahC8M!G(u<9=fJb{AFV_KX!@6-{7-rwRp1_z6WVZtOF^;ih#V zzQ9IF@Z7J!yUnZqCLf7}Ps%CnY_r591{QHnKjH!3QrN@%3v+7v#Viu>rXYxY-JX%gS!W!_dg(trH=z~r`Tqr8HAyu z3{Aczm3-CR!_t!&b4_Y}ySGTk^=NOXe@^tusEFTwLU;&_3- zp{GGk(;agKqhqVaV+YR|;FW!e2|C{)$lK8}!cFmQQ(ki)4fpPfOO+NHO zqIw#iYf61i&^`P?CP<2PiH6JUcTIO!GJN^{zF>s?^_kWU1j~ISK8t6M(dY5Et>}? zPv1yYib~{awW4g4%)r}}@D@Ru=Eu5rA@K1}#>I06a{V&>jn7VxnRYfKtUactYDt;& zyY&#z(Va@mIC7=o06(4uv(EJLYXL(U-|Dr)!+dR&G9qeH*EKUKe)fsO2AmJy>R#3~ z|HO}C7bb&GFhndlrKsp(Uulb#Hy~-L4&c};q)7e9eBH%d)2#5pLjsM@XGqaq1fS5t ztC18-iD+Y?Ea;&iAK{f?gQH$~4!(_R55A>`CqQ=7)$YE{rYU(#M$}}9dYue z4TUZnHhN*|0COIBXf(`cUP547p>rMqGu|LvC$9ws!(l5_FzCaT3P;vru3wMAtWY{& zay=2McqjxuU&X=X=~wqbdP0g4;^h0*;w-pf{jS8P#xIVtx=kcF&a5wj>LvRmhblv zmmSQ(|Bm~mX!!&@C>Df?u6qX;W8o~WYYrYjeh8EwZsYv&!YwI!#B;6<4g&+m4b z^c0lt+k4>;N3p;m|EOKKH$%+Qo_B0lwT}bu3G(MbJ6MMWsNduV@231QyNOvcWEucH zyf{C1MY>8Pux}xigbtXfX#MZe27^Th4Yb%_NuzqwiOPC3tOs|`Zif5d5v1ZK;!dk?SCx0`4jg|0ihQb~`uGikYnsaFy= zx(ZNrMs-JB6ji=iz_G*7;YnpT=dW4dtEQjvTU0mGLl)rfivTE;)$f=4bnGevz3&TN zcM(fc01YkAQTpm365NSjM;I0_&sY(q)wI71yw{f8lnLol)m=#aJ@WQ`B1xw0%5q6Nu;O9Ghc5-Cn;t>y zls&F!b(*3#L^Y0^6YdqvU)yV%A>U5xPzFjAz1P_+9s>FOYW_Mtv=489De)6pJ|H-` z9xw>=f3~5DCd4;&2^-{49No^BSJo$tVEmg2B@+L*{f`Wg$4g^CAQqUHDSZbAz8NU? zW?v=|>9tSx`Sj3yijBvY7W`8E2I_*?8ecXbM02_;0(HLPG`1xlI!898#q_~c;i!E| z${CkS)LMzt1kNnC=hRC3r_GX?#Jv+*2F%iKBU2LdxpV;|%|;uuSDibEj!adT?RkuF zX|ky~I)=F=;6vK9m~Sn&o{RTci#Vd(V{G%PJa;t;W)UL^k!2=v5K3Q!>rjeLjEam8 z$^Yv^uy`Nuv2xNr*u==XG{eCT(B0;te&#G46?uikCO#w$6SZdA=c7?CQxPOHECCR- zuf{P-jo?C?WU=wQElPxE*+-jIp-{t#i06ivr(=Vr@ACkFYpuaF0KJ{K>6g6g zS*=rW8P9v3;3mSRcEHI-ZhPMa*_gaYP0n->aMh^*qbN?z3`~`}J$t#4@OB6XvR?r& zd~)qW4~)10&v|(RkCy2xgY3|vyKGV zNE=0`9&SazCe-Qq)ISi+*jT`H8hHR;X9FWhIh1(@@fW*!r=V47+VX9%?w(gB2f@kx;>$>D&aF}4#|Q&Ws@!;dC{CpDt0a(pa=3GQ!ztVt+BDJ?DT zwSs67j0jG@5O)ip00!=H;1D0zt*V3`vFLCHYOh{a1Y6SkOdYizc&Unf>;-$%9 z-`IjHypGy$qaYWx;gb?L0!^Mbfhq4E#0}eSle2L<-~xj#@QWV9uzat5NC)ffQ+^XT zd|JN}Lo}!I30EFZ_G2Di%Z+6#ads#?TpO(}!qXA@YLeW=Q9G2V0CQ;CnzdJxDz%XuQSUZmR1bnCVA29o$m zjs!GU_YF~L5_BPPyYc{|9)2;A1gLrU)@W+)dS~btYaS*icVIN3*h!CRWR|S5hz(EzZJZa4g#M!!b>&J-?-Nk2ePe2ERxNlMsC}4uMMRExu zPNmof?1mE;Jn?g}W27j&veqNHfE`dk82b|$l-og&MSzOQa48hK0eqTt2IW$YxiJZK zaPK~LSoQCEk*q5W;hPea-Yc}m!ZlT_qn~oMny}Rb|K9B_{AeYTu}KsIF~+8S?`|T>PX%0rzyX34D#?Rv(j!{K*$=B0L>b@8n8%()h-*V z<_KJ&RQ|tQqM)y6!)YIyfHT*7X^Jp=QOuQVI&CZhkP%pFaHZLLw>Tk^M}@($t!r(q zdB#}K$%8qb=c^Gt1^l`HNS(NX%q!^wqLTbvY4)|V^!8r2!V{Jwmg-QMNX4Ra-EgW_G~(ncd=+uc32Wm>P)wq=e4MW178fcFu?4inBmQGoYSiAK?3g+ejfGC@sg zm(nu`&%`F^;suS;|4#(kZszCoPSLtQN zeDf&A=-Pp*&y+Ovp86L>1#K@aD?=3M?XGZyLzK**b^jXfpHDe@USm0KNH?eI zkyKyAfOoQv)kyGbM>g+A;d1Jr%|yY^EoGnA(Qi)`$~CY$BYs0;hE^DHK5%HFTC)ne zj!*2VVDwYq#tp#6oVnZL^$O|eNQx?fV{V0)m=j)70nw4n z)tM)3mC;&wuN||d%m7zjk|`UsLUF{VCxhMf*g~ zjPO-cv?*S@qNVgRE|%#>-Q<86Wtt=pCsjLvkJ* ziT%*wAX9a$izQ)Xzp2D&Hocu|YT7=}JEo5jBco!wk#;w-Y_(>-%^?E91Dx2p6>Pl+ znTiM{1i;(dtkiwG)$^#;*CTy3y%#nn=V~pKB>nEsix$iL$`~#{1~{3Sc>) z-&=Wp)}b8JlQmoOMDRC(MuqcCQ6C#~!1oFQ0GEvG*I@Q-9y|CQW@0PNPTLhYO~48N zGtdMY=v2kR7Mi~?U*bJ0s-SxGWa>}~R=ntxQmcUoi17A3{=*i=+e7-&Ne`isE@qxs z8a|(UrEDcl4d=?9O`BeMvR6Q4y1zjr;SuTN*-)#=?7%#0iNUw`Ib%BVI_ID$@yh9}F$Z2rfz1m!Y3TeT2LDY(KIwR0@BnXM1{k zAZ^cYu;vLUGiAp-`XYeYTKa&;BizH~v-GiD5Ds<6guPoNZ*#69QlIZr4n7wB5JR)OE<{-1#^{zBd0H+XB^gJ1&H|_Brb;jK&X||Cj~hr@I!1v}v);oD z2Iwl)YX?R9q6Y{32PE==e?dM|a&rAQ=sSetk^NP>7+b$~!#~rCnYU~EJ%7Dck!V=n?o0*r~4bt(@=Yy~2frtS+F8{pNPSYoH(n$JRN>WD_?lDz&seUw0b^e^OW) z=QLSq!xFu_N=@=}@^Kwj=rc9V*uP%8Ur%&NLiw{Lb`p=ORNcF@vzcN&_`RO0nefJj z1U$P>b3*!Hd5e;ZsV0PF4tQEWECb4?7Z+Q85GB#-%m`-WCWtQt)!1ToywAe0NbT(Uk-XvWNJ z`Q+F&9)MCi6H^PsZSB~4$p$j8%IFCMt=sHZ%96=FdKeBB3&m|0a9>;>Fsp-6bJI@*_4 zUb3G7C#o=dUFvHfU86G;62@0jGy!qh$b_#NbeiOPDd*i96kPaslIoV1vg2c5t2z2o z38oFF&dP9JuD}qL5($31!}a9b`90u?_%g-SG9Z# zwbtu(Eb6B!C~vSvVGsw3!BM;cm&Ni+053q$zqf;M--o*tRXtV1w6;xh=iwf4XK}Bu z@A~J0Qv9;?VUBAp-=MwD0~Q{ijB*DZSEjRJk@4FQ9aY6?^B#evCxOpyO|Y~hq=ya* z63T62{rXZLE@h16^FY+DHpTH}u_E|+=#2q#&3G?IItK0fO;F>fZ2l!6#e78P2}oBK zenEk)rZQ>X#|T+6EYOnCFT4N#W5k6LDHq!`FMlQI+i|R|K=j+g_t(6cErru znr@Pq728_N#RyajDwXLr9uoR8!>`p+#chCM_AB(#M0*Z^6}L!j+BP%Bj`cZnQm8V( z)jk!x^F=&wfB7z@$nA(3D4Z7&0@2pbnjKJ(FX#TobY;LWgCUg1)HbTw?a!5eJR+luY zQ4L%XXiX4G%?d<8!xaB9DYeG1cRH*XM_B#^yKWHnHQL$4xXbwY3;-g{OZ#>#nz5`ieF5v ze0hXuHT_@ z2c0`YuNSP~%^pi@-e2x)v!;HgmK+gA+fUq`D$(KvbL*?ueLrKiuQJtEc#?p^6_uRt(eE=_qW_|@Ia63^bo}BL4bA+P=l>xCA7YL zL59C@O7HR=poyqD@e(ZeT@=z#uh)9xN@<&wa5H_-W(7Xa`@l6EDau&K__xQi8pJR} zy~w5O;3kOXI2$^AzDm&4ecmPVbEzE{uexnc{ZUN8(|LSXorkAQ@ILWt`=&1Ws`j2n z*}zIw!0!oQ!T?i$in7+0lj@6_G3*xumqAr0?HCtTHXl(1qV%?UtVyd9c5mT?x#7lD zrq6g%;@xPmbz;c0eqkSD8DG?k&_ChkX^0GharXvCw_k6gkJeY8_7=<$(V^7(mzDo_ zu^mD#jK|j?VaC?5K=_Y{{4DN8eZgQEo}bmq%MF&eHFtWSN!5g8kQp9W+6{QiR;mNa zlON7K6Fkgfz)Khz7IOKm#EZjIyX1Gw_{|n`O?}m}qrOLa*FxDE-v=p>WF(1g-z zstE%o!jokCp<8@n{jTY-NY%9nV>)*t!lFB}dF0dS>+v(__src^Q82fhqtSLZXIap& zMl~X~X90EfY($zyq$};r(}oR=8&K@3C3~3PxK^;7@;-2prGwXTgHd5tkGIbuC%x#) zN#vMxXkBV$E^mzQKEf&mZyD?FgS0SsDrUd%QaEJpR8UmC!a7w0$Xq1z+X1Qg9egpy z4IMSeq;Q$8a%a}j*Ul|9*TaMqk|zacJxpcnHawFLP{j%!aC&S}`7`WduRBPjD%j7_ zTnM%?a5lp3674!*DM<;AvH9ldS_{mzpR$Z%E(wWIEeIj$CRo$^4ui_Hv8^8RcX-LioWMS4X}5z8DBVAm&>G9?6g2euOMT8H2>B1#>El+l_!j z{qBmwL5K;@v$8eR)2##=zTiRUHA4cFq1Du8q}n5 z-kcy-61*7feCYhoNUz;Rq{Pw8&~BC!O)pJCyH6+wIVWulUq-NXPSQCUCm^5*f##Vl zaP}38n^&GOi)=&bL?0x%cP$Cp^g+9A^o3uQ2EaHa2o8ecNIYW<(3V+o73qRaya&o5BEu;BB1Z^}BG_6YBkb z1f1O;l0!lK;QB_Y4uD2f;Db=dqrq@M%;HVg$UDMSdLH*E*E^q?$kF`Ax}1(BxWy2% zNW}^)6|rm}g6?UARP5mJMG)uo`5;zPqIo?HHAmTITFHh>$XsUpi$BW zk-)c!9D170vE31l7_pB;3h;Ja^)qu!L1;30F0It;yT7Wpe+bfLvBn@*K6tt8LpHBK z)!7=v5kr_&vY$qvvP2ccowws!5)B`j3sKBdt+O!(xu0^^C}9+Xqzf6Y1(g`wApSme zvR2Bt#Vd)@>UPVi44vV{PYrFvGC$*({wI+!GHGALogb`OVR) z(*XWEH_*&4ky9QY>Iy-h)gck0Cz_>o>Dpp?HN?95e-AENbs1Zq-MwlVyhx#$BY63u z34)7|gQ-$R*4!q)r8krr-ll#EoF5Lw5*OWwkZ7X4lvMSrP6F zn+T31B}ryv;R3;Fa#_$a>TR#OObX>7W>1l7m|kLOFb z0KH9!crz%_PgZYHth<+n5l_G@P=KaR%-#H%W`>u8^(Jv0pfwBvFMmZ|h6?!g*4WYq z9YlR@8tNI#;{3M2$e$U0ldfUq&m~cjkCd;t|yPa^JT2F$p%@&%%qzhulK zGc~_MZ6=pyar1i0L7~vC(Y?=uIh_kl=0UMJx+U~j7*m@@Tzd+CAdrW6OHR}kHjs8i zSlxecWjh0y@L`{)#rd_)S^p0FG+OKM%5hs<*3p0q4YoxrcTSmRqhHHRJd zSA^gaU)4O8j2pv&frM=1Kmf4njB)s#aUK-YQ4``LW98sav%(yj9f*9-MpNR!=Y%e&6 zix;o;T^d>-Gx*ZW6662EWn@y7vK&;m_Trd- z=`8E*O{|7_mp;eT>++Er;7b$o-l#}1Cbt(Ca6r`W%$^qb;ubfc+!`cC0lDw}_5UUW z7y4E|-PhIL7DyHaT_NgiO zpNv=WiQCRfBDwdaCwje7;(oLp5h<1K*S)E1&xZC>O^!x+y^V2+(P;k(P2esbidx`p zdc(&U=oHJ&S!akJ3(6!RF>U;yC)Cb?RR%+|`#Wq3-vzO$_APlB+ky-8Q8Nm5$ zuoJ6n<*fig#NYwQa1-H2Ljn=N!$LWU-nvfJROzrJiv<(GQU0;4y>ZG1eaSbRz^Ei& z5LzO*ugX7dJ~dofZtoRc`b;0#UGBTSpAE}3dsAtmd#=&2bv1Njq+%#Jm_@yBeB2~- zGqoJ|kLpHHMjpzyiiyYv2R;z)gaEHD@D+@XYbPtE%J?!s8UX!_&~7I3F0(ISv_<|s z&L6(BQyqiyJ?0GRXbpZ;(gsCsJFL3FK@=|7DG!T9(Y_*BQ{4cJPTLDERx=lUx+c5{ zE^N!k*7YrBtjr3TzzK0>@j3pDinlQ@kCbQ%;q=YuTf0o{-i&L8+8Z+=iv{m})Ddq0 zFL5+;%BUVLM{;7V8Rmm}SJ~5t4~CdT|B0?Ntdd#4b($HWa#wh^5cGQe@4dnCsO+$b zPPI9hX2M4=nd%|UszRJRtI1uF0 zKaB{}3tKn~@m5g3evlz?Cp(UDbq}+1fFJAL2AqH5tVIKVqw=^@MM7Ph^Q&utd-!`> z25%R7-UR~^o%Fp0Eg3J5tByn|a#WVA0T-;P9;pBP)8saloPrZA+qT~RKzut~NjE)$ z)0To6q~#dc5|*wfalha^Dmv1E{msAVEXQS> zzX2Qk?~4 zS+?r`RDTYn&08L-k#k>2no)C=yZGXba8}S4)_)yBME0*Gnq`i5I1YUMgJ|Z{$8_n5 zg=CP0&fwT>;`X+kYCc}y@oR&k-=Hdhsu)%l*eCfUjd@e7-(wE1c?(U*DlL{<{J>Rm zuLw4^nXnnE=W6N*bt>AA4zGaV|7vw>k%wet47c*dZ?H5Cg0GUiJ73`qq1%f65;!z@`I4ZcIy9q&6VeLCg;U zHn1|9Dg3E7X@yH2ypi76@)Ho9F`$vgc6{>}^|0BT6>Y0M_*n@6)J|&r*=Je#U?=6V zw-nMstpIDiyMT7VXLTC?uRzLHgppIpOzhS5EN0PUU&tsqIJ-?gbFE&;)cxELMJH{g zUtM>%^XDnz%HJ_hw|W$aSk;CGdl!9Puqs0+;hGPO4Wtr_o^XMQVkM#- zYWGu%ySwz?qj8~F>QL+)PSK7WJHdn_1zbvYN}Z$N+uNLGx%n2>Rdc#LQpKb$+De8Q zOmK&s?7Wp#%eS)+_CZ@xaztW?VVer-y ze@Iz9&8j<=K`bevL@n18-8V(5c2vJq5NZ9>nRsvvixWvUI(nTG@QzzH zObg{Yj`X?#NgiR!fN5|e7rVUbJdD|wFed%66nxcA4?9baTrtB9v?n7gRtV|O3u)H8 zb&yb5pi~VkXfFgV=f&O8UM-vS>CqheyD~{nRj;|C+_Gr?lMO#Yb$@T6QT5=1hZE8# zM%q$a1wxVM)BwJZ$4O#b+cdpKKzqhVdxLncKOxd^ike=NFEPk6L6{h=z!$%5u-ub~ zcTxWyB^Y({z%zQpZH(>kvnV{F4VW^;;6XtdU{@Vhb2YnU(pe9h3dES(z`=V zmVODB6^J8sp(W(ID8~D{hBhb(qm#1KSMW&pyDbPCBqcsbuz0H@tA$`MG4v~#s02L- zQ{_4jdzVxHh*RNO{WLn0h9lwmZYaKA?TY+=Ijzzs1^)P)+Gm7TJlrPFVyOT)Tj!}f zPTZmoA+BSOO$~7NYgQFU+(4*-A-dm~s!i0@EdR4G(-#A$p2exQmDBmY9jPCSRlyx_ zL=(m7in2Ff(^NJ3{(lE)$vVQ6Aa9wvobM5Y!php+Rv62inf;r6)M~L7Ka75-C5D?Q zQ0m#6P!m2vQee9VWn_H^^*?y5uK-72o3EU?b=A;#ggl57OWUwB0h)Mvz>wrDnRG2?AwfSYm) zVF%@OEDi8{(fT-(NcwogP&joI^9(c4dq9_$V6v>dY`!y${*3>{syc?-4h|4KeCe547iRg=DUy$FI}*fwEDmBpgF`Dvq{u~d7rzPf^VGgEl!qhrp(%eSL_hwU%o+@F7lyYJSV z?S99PRlewRYH*-oASrBBao;9=Te@2${Q%O$Yh>NWW*fjaQw9jT03VsS2>z>$*2q>; z$(SZ$RO-l$x68C*KQERgiN5GbrW?oAVQ`VZTuMO7n__>3BWtKLF)V#$*7;C0Jr{_H zf{UaOlZO_zPoMz9391vbDjnq!{(*Pi?EGyVO2v9C z4}yS35(FJq5^Kv|TC5a!O4K4DgSaAJ;wlUSdmS90DKPmRqGs+Sr=w4?!gWtv3d^t>a{Q#sStFZ&_zSwe0^>v8@gES8YHV;4af zBjRTE(&X5d*U=#|i&E*RVam?yQ6W1$jW7b+yeh`hO;kj5U5%_Q2F!e?dk;G_DYe4WkJ&OAHu_g%zLgLfQmGbjf2>qLHd|s?<@H&$sq0 zReGLjmPJ!|R}wc-`c)O8ADKw0zc}Q@-a8`JMxz6A1l5jWjSoYa_F9(|F9X2DgUG%U z!OeFW5G;;_Cf?3|B(2d|h2VdN*zBQv#95)C2{KB_?cZe^4-qgGRngN16*hD>qg=~Q zc)j<<>LA@wMzCxJIBqZ>0J3beOf78Rb~H^=TeOy0n3*LDFBjxJ#kbcT%9QF5a3fY( zU{ZGqOoVWo9uoIjUg%o#&1~VTfLQ%aTZX)n-~uX!tkkurcy;fw6CSnjlEx8G@iggb zqOjyY-3{pu$L59){w=;LH)))~Z1IvLb_uw-S{6TeQ9v)Dbv5%5YNda zFgjIY!aN5ZfZgn7-mB{uy^15xrH0R7UDZ8 z!N9zt&U>c^CvV@PV|zH5!DY$+<>%VhvlAY)K(bKhzb(Gx?B@dI_{TIlEc;qWiG^DF ziUt`>vFg7>i>Q5X#?V^JkpV1Tu&VXPk5n`3j<9W1l}pFCQ3Uu_b+d{}4}EH~oNBYK ze;D10qhS(UD+yZF0>6nCQ_~>`;9yL?7x48a+vMBMi{4zcXWE?U!i`*`aI>Z9uiM9v zASA(7s}Y@F0qaSkz92&J3jtO_5&qvRAm-p436{My=yGwg;K5}`+vdan?(Zz!1+pMg zS`n3*9_vdn!0O-kdq4yEz+!OREbs&Zk^^Xv_n9S}4~az*Y`%c>NouQO^;ysp76xam z@p(C zPw4JINXb74SDON@8!5GY{Z?i-Fn|N50ApXb({xR_b#BN22un(D???GTPJ#ltyE6*{qtg}AO0P7Ln5l4SO#A9x14M$`g``fFV%Sx}sL#%s*cXTlcconax4 z2@AKD&^5u0Bz6g8Np)8}e!Zd_wFpYB_cZR3--IbxcCA%AR2J5CeA$H21-2R7sW9uW znfm&OE`Fe=F&u+n(^+jMbg)vfKgD5bXVpe?bpnhp;j^h<`;4P#`X*c=;v9AN|LiF< z0hMdtRa0o>WXkj_zz`S@pokZq=v#Ew-?IJva``DUo zzy|#-0m1Jp9H0E~iZI=FwfOpUDihNHR!*sItwHo~-~KsBX;2kAn^ME6nSGIN>SO#^ zl%Gw+1MS0l)w@%U-ej0FI8Y^ieji8cIm6Um!m0GWoft6i3o9}GbfZ*!2bjyi@JA$` z5Mmo~HWlTz+JC4TQQ^lUl}?Zh5Jt`KWFT%-=)-4P@Eg4(`~P@7fZ8<*4Zexjm{mjw zCsPUz>~<3(1dM!IQA{H9Qfx{ta@4+a2fhdBf0rG#fL0NGk;Rx9j83buQk^m0Rx4yf_%BG)O@_91_B8#BK~s!rgu{&7kJj2U~`xa2&UkvpCRl;Z~40 z`IF~y#anxkc^#0Mb>kv?`QY|fnNC38lZj}bMdBCp9Ue&u$rW>SQVFLyJ6T%22bVR&9Ve@a1>g83?ljzBLRy&`*@<~rn&F^Q*4L9#&l>MDdCeZSGP4K~iTu$DClCn5pa>s3(?Fi6&i zRA;IOrRWv#y9%yMeCh}<7^K>Jh+>thYPJRf%oZw`FsYE(iT>*oCKzb*x#HncIzI}+ z3x!T%$VLG7D)*@Hvb7m@vQFdSHcv`sRjS#TcUjf8Ox7Eq7{C|(kJMFgO?^kj#wI`u z>%zE`DI6#w{>q)9Wp~y+$GdtY&b)uVeB6~!PxV1%mLI+Omw;T}hI368LCUc2(UyQ~ zE_6PfTHGyY+m%XND87d4qW@6xcjdMp*)h9oA6aeSh-WEucFHQFVpsBF`5p83@CA&JY(><^mQ8tOr;}d^U zmy>J3#}XoO3o3x=iyhoEUvZxULj)gqSydI~Q|b3?-RT4{r?z=2Zu$Z*@P!H2AFWQn zS?)-CBKjN#p0DZ%H!g}$tgaCH<&^7lWVRxblw|@A;sD5li-mo^6a`i*%`#k+okd)wXx3IJPSe zGxUcMgHmaXMS^zfS5#|g{gW+KR%S6Y(8Yi@F4~-%eRxl7F+!)#HKoVni{>glM63rg z&+ZD2m&HsaWr^O_8(5RprvxUVwTn&?1B0T>s^^UNVwmU`1;4l6o!Q;T2idLp4s>P4 zk$95c(F2UdX-kiX4COJhfQDI}R7~N@pKp!(8pNXLIKtuA~CQhpe|g4Xa(OU#(yy$64F+a~PB%phuBPC&o;4iUE?ly@W6mpB{r3 z-^?G{^^p5Ws(&}#?GwSmJb015)y`Tbdo-FpDxHa~_;hsgjoOUvL7fW$&O7a}`M`*c z*WH}B0AUuUPK{0mt_RKmh;dPAu9b*a-e;@6YGJTO%SF)Uf*_V-^zKRyQC3D@6i}mG zCk=oG5bv|G7JYXNR43&lFG%Gy-AUM1w>HeN9!U!Wm~?|Re|eXQE#9M1WPg|u<*A@> zva9$%s@><_kU=c7yh8cd(*s<$6pau|t)QwE7gQ@my)k;aCkFQUTRyjbN2GVY!R<^q zwX*ckKkRN`IzUEmC(>cN9rSBo-&xs&($aG~Ap3zoMlT94PF5S?0oOMqTDh-OqaJ^4 zcvoMqgUZ}~7KUMhzR)D`g95n-)AKRPVVUvqkE&7aH7p4ro z5~QcGw#q`2b~E5qqV})3D=Ma}j02@x96LXfNH~?oiT@ITGPe#0s4ADWY9BskTpu*R z=Jct7Uh|SQqqe?}J6pL+fK)enRwp!j-4FUU7?zi#HP@c1>VmpgbM)HDb#6 z9XBLM7}ukGTK%zdhKQRKRo6jDd_SrVLc|STKPGx8Uj+KnX?U7PNPAIOyej$Nr~$fW zMF9J-UrCEbL;(B|f>KPl)C3@9$PpctEwnmTGs1H15h`Zc1qsZYXU9e03=QdnFGJT) zOG!V2Q@T#3gqtei!2H^z zY?X|bel#^wr$aucu|^V*7l5G?<0h^BjHDQ2MHlTWJ8q@{QYMaOr+$n0tIerZxGfD7;6;#NTuCOnb}lMh2|m-Kab_l+ms3 zGm6BxSXI;x_BQqan7nz!`KL09zm0;GH$f+0H!?zU=dzc%&h=~CopY@G6qjH_?i@RT ztkg@&J=0)NC-n&vnc&Y#Iu=klVCGCLJVj7N-d*S{G?HlS0qs?M8@pZ` zJ$IPH&Rk>e5}LBvt6%TGZ}$T_dgHAVcGu{xgFDN&d35Xn?kF0g4WvwF3F#>I4o7;o zN@V%Qr6?aTla|B719Z_I0RxJd)sumHOMi!^yPEJ@MmnQpeBq5HWAQ1yS3ooA`=W64 z6wv6bnvFzV5kl}+Tn(}-ByIU*DvjkrNhdD*)26);IrlAWczt-oV#+X)4)H@Z^8l%! zH_jgI^{-ynny+BG>hFoU2qeH}!r7lXm`_yGUOX_qQiBliZTXGmqB&w2r9br+9JTfV zu5Z%G)8hJeX)(1F^XXdPpsD|SG7~%uD0O;p50@&%X{D0(<(Oe~514!k_62gK&8$z3 z{M%&s&0)ae8R}o#{2;eCZ@v+DNMk>GpCg?R{aQ*zK8(z(8H&wTy{vHNwFO()YEpDG z_OI4Z7bUBWLUvBPlmyD8Q$~aTld1VReG#rdahxP0zFOC-w;G(bcVX6gp+2NGK7z+#JM0rQBJjVgAx0mbc+XxV*$W>q^r`{DR+(yCkgd*Zy&A2yS%JdL7cK2bc3Rb@P%4 zOsOJu#|&M;C0a`t^N|Fb&LMy(isVyTmv5lO2{lVSzT927yXCHXzPyZPJ!Co(Djp~M_1KI{|4kQfn0ZCptz%%i> z?bl*Bny$d4>$o8>L##|kKy(*>wJWvBQS3uCH1mE(PiD!czL%;-J#t61MM$o~53fV8 z5a>dxZj=!l5UxTu2Nkxb(aF#<(eqg#3|}@<;UNJM$YO10b>N0Sv?cZi`Ti-X*M*id7~s=sMv?Jvhpj#tq;7m=F5cZBA&pslxl!Sh)o>~D`L#W z%zk6Uxz9uGy2T?ufg@}-i}|ff#s0aTE4W)6p z#tH5&xn7@C9@Au5)W`$SlI0X6xL6q>#}i`W6&o^$9s`}uJapku9jxs{VPXxOeh8Xz z#?E*GO_)rS?nS8SbHVWPT7Y_euj z^_YIx1`VIGwQnAhc!LUp(=}&#Vd5K|5>W$-IkLaP#1|VpU9fY^spWFF+7SpNox{yk zA~;Ao1q-q*{ZxKY4QwQ=N|%=;9`F5W3ZJvtLkh`cz@Ox{osU1t5`!*#XaXfP`^BZQ zF41)DR~QNb#!9pd=)qF>8)wTFNWBRg1^q~#snvg`9lTrF*hVAXl82P#KD^PRgS&CC9zwA1T|7vXKr5(-!6D!rhhr557+6QD2vz{ zJRwBGG|>er-!9}Q1Vp~b>+OHB;RSb?nLP=iO7h76bWi4yyYVHa69#tw} z!G4wCVjSHCj#VY-nl1WSl-VZ)P37>1wsrKMCly>2%=@&fP6n6yi<@nZ4GzW~0dzvA zB3nUtMtlR2ZT1j1zM>bOK3CoLWGWucGvlA%u;A0b2C2W*%XqmsrC4Uwa3)>D#-hj*3kH-QA#_*~_#cKZ@J${?^MG>Wz>$ z#y#zYFti-gjTScn*loEpQX}53j_)r zs~{m1xv}kXF;SoCgwBFkm0T_ni9ZI~WtXJs0<2jYkd;QHkq(*Nub#*)=g``+CdAm}HjqLbA3>M>Xo zDAJn$TgrNy)&|5M+Iq7PRUXY`v|DeeTh9ux&f5Nu>{2D(^+re!jzr-9NR;nCbzSF= zYT!ev@;rg6(`6!oKv+-Jl*6T7av~jtU(+nc;z!?r%TC^fyeQ))x)((EfGd6IfD{_l+WcS zHS)Jb3LF8(DKKlJ6Z4_xCdkIUb;}J@iDoWvN2ghBd<1Sgvm6CycLGxl0AW)hls5>;78}GzPFt<8-zU>CC4czmq!yYGPU20#LTw&7U`BTBHDmxJ zI5tuF+eV|mR2X1plhwn8{{-|MB+!1G>0}*())t$y1#6>q8)!x|2+7hA<~1o=lRy!* z?c5laY`c4iS4LGjQjxCWdkr)q;M^t20Xt`n-PH$|XR{QgKYJSYssvP4mNAaSm2%x% z%)?9C8JT>}l?t<7AhE{&1Ep5zWG-D$i>4a4?RQt5sZ)NvTk)Bt4#aP=-Xo@Fy?s?- z?0}VlI7Q+%08oP2k3xa#I(GkNHUFDwoi)Y|+%%%=DNM@s@5c|S!-&Q%eGjvgNNpOa z-;EH>a8z5wcPhOT&qZW10k0PrdF1WF)+GWVqVVRY3EYJw+C@Ce6MGqucK4tpKq^`$HQ?(ujg<6n(AK0j>$QPkF$iHH3vYju!Z zXXbetYR72JyFNfzg`Tvh`tD>wmf6vc3l%h+gC7WZU9&`ViEdXK&PAwTv$gL2`x7_n z9wq!2D_U38Nn3J%p5gS1s=K=KlWGL)Qs2`v%DST#P`^rSb{Rk)4vfgz4WiBbue4=k z(6o`_rg+i;MYXcJIAE2QVN;diB7L1?vOuIkC&=ETo!g6C@?9dOXROb_EOTMQKY4ec3I z-^T4R^et9)!HKWKsWT)-@%&dr6wpSC6Lp7D?N=nUJ6tWBcA(Xy_5~QhPs3p)4cXu| z=48KB_&1pmg&U`~0Dm>TmuLL<)K749(x@!;ZR0g_zH75OSD1_%mzGP}2S`dmBLDO` zjUVAeX-n$Yo7HtZRR|8k#gk^3l0U}Iu28{w>DD-S0~#BDD9Wy`b|#W9ov4{r*q@75 zQ4w^dC(8&(e1&}}i$6FInL>TzD}A=~3H>?zUKC}!=$clzP(cM&yB zIyiMHR-Td3c(lz4ocj7l`+ZZ&@15=qdQoVX%_=B$L)sN zdg_I8Tj$iG={7HnUUff|)D{@Po}nSqt0>38dn9sSVt|DI(p9&Y`Dak<{{h%2;ek*i zI{EO}&Q)~3y+Ao;53rTBfcA{24<|IoJ*53oD24h|(KH7X+S-(~)Z5pe1~CzrH$&PF zC>s6RQ*D>CigPl}|?7w`=@}lpDMVY_&TrE@t-6VX} zE#3<3aCW>O6|Wxn{|{$-gQ*ekx>-6u1gHPl#gWv%9<@d)gB3toAVK1m>WD$*@CZu- zNr;N}9|Ngpx=kC&FvI?2$EV0b2Hc1+)iGa;zZyd`+LJo+@mobl}K7{))DzK z_*bcoE6(X%LO%FKL0xmWx=ZAnT}A7Uzj?d+r4#4ITAK5OmZV^?KTEu59v5>BF=M?L z=55fg-*2gYtYfwKg_fT0kwGv}i+SzToZS~`ztK_Z(0vK-?nD0a<$cFxo39_FxGlV0 ze^3jF0zFTee4J4({7yo=&$86?6msfiVwBlZTvnXt**|D31|g`OkCNUrSC$ph@b+C5 z@gfLYS2SB#ml>o8X@YLXDyc@F$I!34RMnKegvCK3MGtm9YusDgd!k%SG}To8Kxad0}_(v5AC0 zf4H4Pr<5-V3LX0`s>;ELV1+Ec$}C}z!%~h#ir`)ys7o-+2`<*zeE9ejxMgGS6ObqS zNfZV9C62|VVPWVZgi%RK(h1tzNAc?8A=b0P>l5CA)=3IFY?oe1;B_9j?g=CQXas|- z)T697m3>wloZ->+2jR9AI`L;sZ(Lp>a9kCf@3fEF8Y~0Xq6;Sb$kOk$O2S`lSDV7~ zG;*HY2loH~glAUb(PGszgfeJ1p&@=gfsh_ffq5@DWx+~aEnRx)6bS7LE(QU}KY?B< zO&eSYJ#~0chC7R-uK$>_P9@GOK3<35b|hHg7L#7~^fyxA4zUqA-1=?LZj09+HwbL_ z0V=unY>V4;sMEAh||oW0sfnvlqrf}zUW6l@V}SNLA1z=XfD5MxI*`>(O1(O zBvr^ALfu|*YZbylxuIuugRkwYBf$d&**4%`Ag@wUm$*u> zrK6k5C5;VFEk_e)-8v&Z-k!5vUo*gT_K6z!p85X@#=z2&{4FZX&@{QYb35G}MhUaj ziUCX@OKy%Ez+VcFBUiUomUC>O-z+UMnHsud)J`dQJ|)^x?|DbsSNZGKFg25xTEw0` zPJDK*n&?e@po$4#2k8qnNb;xrUjm5za114jOd>MhYbn;U<_TSPs_ZJOjHY+gI#&+) z2Wse`jT*-H2%Zr{)-o6Ua0;%g-@?S!={^A09S zB&PpU_gu|-M@4~g)Yz0pAtbb|TE=Porxs8kpOgWG-K}6ec2`}Wg1HbYy^qLdC1DdHavgM74CuA-;-aZDT_2%)|FuE|{! zwYXYmF+`r_=m3b%Euo+y|hX#JBhf z>Aeb&Y*q%*9=v4oq^eIaca@>)jrY^_z_f)z55o4=kJBDk;9LHLot8lk8%3luT2uLD zX&b0ep+6TRYnj8LBDkaN)n@YCJB4Ewy`nh3{Dbrv*~IcR?%f{}TJg=5K24?oc}@d` z8gy@8I_vv+vshOCN4`X2(+BY_-{<5nxs!*%`>%?+nQhe1j^la*K05q{L#qWPmx@U? zC!Q&Sn^>fK7`icpVkK9uk)Cdr?P2@(rM#Uqk_#}slZwTPs<6Fw_ucu3tB1NU_q(Ts z8;xG3=EsT4&*Y4+%$1ZHq+kSQ;|ai9UTfvF^mtliL(| zbBNh_=VAPCGVYpo3YT}V*P9!!omJT?Yl{toKV99FCSkJ=xHQx14VBqZi}5E|H?k-)!g>T zD43^mrd|(T0kZx~%M49&08JUjw|1|eBCI<;EpDa?- z8$BRUFtp1|`Duky0Tkew?*W6RI5*N$+xBusXuMC)7)Jr>4tULtpU9LI{@$9>O>Wzu zOKw4u%=UL~SfXn~?J`4*z@7vM(xNPWYL z#1SSoSY%{|RT5M^x^ntUKwniLf{K~n0UUPvJ^KD5n}9B0Fq8Xm-`S4?`+iS_ur&bP zfta&rymlfa(=P}`Zk-Yp1NpvRPqlBS1Y-(mJe#h57wogDF-hUiEq%-*a*P<@MG+~= z6Vos0xaZ)PX?@#yZ!2^PxcYZBlhmkxqS_M!9d%p6ut2UdJto2}9PI2k@%>&;duFav z!J*(fCa<5m0#t~P!bye(rT@`WIO@}HPay0Qr0TzJP|p4gDd{&9W(33&3i4G-w`r_|Bb4FoD2?^AbfW*s%c1z zoR6?ZwGc68zVv%n4^O%&g0gPmd5-eToz9}*?Ugz~r~~ zQS{)6x0R4YJ?u!D&YfS+U&79Vj*%Grk`aTDdaagGuoeGRv#j4IIdV-4=d5yH5fF1jj>5L5L77vOCpyNu z;gSFG$3@|d05%sbdt9mohaB)kSW)L4-S(Ob_*I>Z0?rzq-5bCd5xCz2{dkv{(9bvC z!yjp*G2&^wq-A^xEvl^^71{2lJ9z7ri`xH?8x5;t)2{CxoE3H4KUu)9+Ns{%?*r1X zRH5~gbJB;uR(=jvQ}c2hk}pmIrY>-NWafUSDyYXJTqXxJR!JVEZx$TVXNzAL_j;P# z(ly7%C9E#Y_%hG&p$reQq;?o?{(pq9HlqU0gO;b04-d;!_?1H)P{}ghD};U}5Lc7U z_N#4=|9w}?SZ9mrHQQs)%yyM-ZX^vu70q~Z!BPx!%fTLO3F<`x1Z>a7IUO)03l0H| zmU*fUifoq^BJidwP72-^X|_f_x~$fCQX}$M7;D1qfUK)_#%oGV#lvJ91)M6m@`uJjKI@{B=o4K-6WjY?oFH-v z{k6UUMjU=!@Aa|&uL?V?q0`eOKkZ*h_?!UBY=tMEwzQLV_XXNX?ygp?c%7Atdix^g4nhJfuQQUk+%;n*h5J%7 z>EbAXi9;53sN1#vLIl=pm(*MA^lwmEE2h=c5^)_UiuqZPK=G8@CcX7o{Q1BZ>b zcj{5l*yGX^DaI%hjU?_Pr1*>a=IWK{k^Qfk6QnGc#E29^P+%%X!zaDE;*cU4s9N`0 zX0e51ex%3O52KF6W+rP3*=T&HS0~W8#zO-8MOihd{4#raB8`f2(&-2XsaMvP;Jq~F z&MMRZF#k0#V0`~cLiBQl;A}OwPE<~BBW1NB%u&zEwZlR979)#~KPS7&iMt^_qm9+) z036?eiRwTngaP;{m~T$@yi_IRq^JWNwEGrD6i&#a7Tw%Y2Wi*p#RC>RGmZ2Tb*Jo9 zLfn!pi-Tr~a{wK0MGn2&{a^LxC|w29e$) zV=Q*2oir_HWJfm{qcqxl%3Ajo?bOrv@4nt%Zqb=o{keyKTl34i^9 zd~wxHAJB!-FgZ6Ankrz&A1S!~rkk&L3IMuBt2D+eq=qK2sCdbd(crpC1)VKht*R}- zHs60AnPvbrUxz|tZaNhTUuKBs&UljL;O( zGriNrAv_2n(U_%@sn)yo70WZtU7k=9+h{z^^wSN@>%{4y3t#Zd0SGRUfQWqHupxuN za?k~}VjP5ZN#v24fmab4CS;fKPC_X&LZy%IuwcG2p{;p+H}(p8*&%|yVWtJCP1q3P z4Y~h>{b#rf)4V21f<*8a38R6#pfZOfDkhZO&BO1Rj3-!p3VqV?|C(duWtLg5duPy2 z*VcwI8A(&ix0kS!4&T^vckt6Lj|he}iQDR}^>jaRn9ZSw+M<=KPwS`Rb8Vbp1hhG5 zQjH3xV)pZW8Nef)pW>1gYM!p9qtB23GzUx&rCdOnKLL1FX{0=+beMo9yh+U_53X)a zytpCy@5o;wd`BN)3=Pk9w9ksqc9?_a4WQ2>4K;k@3@P5OEoy5QEU^{$ll~pAwbynn z>%_DV^%D>cS&ww~ci5S3%PQ@4U(<6J&VoK1i3QTg zfxjG`drw$mEjgAmc3x7%bfj4}S=mnICQ;gz1X)Q=l4(53uYGZPaQ_lK^%fG0>SHJK zyb4Dm-pO){3Zp9*`eb`tfG}^k3hDVRV%U*nbq&U}9OO)fS4Pg3E}F&_%x$-jE@)eK z7ulmj2bVxlqT*{Nny1ytmh?tx#u?wW=8p}-T+4SQ5+6Zmcj!v3mHQ;tu9$BfkZxB`zLe z+*jD2^)u-$c-Vl6Kvd`vv}cHeN#s!BPkpoTy(}nTt}yr3k@dgEglD+br$>^Rk%nNc zIfwJ)m;8Ee!MDQ80XS%rXI9 zcI!67#qQtAV;U(Xn`47KC6A6WXdqX(Y%l1!ZKULl_Vw>dIka@Tmu}#Ud3PR%5t_Y< zM{_Y8fT#?w4M-jv6T`)Z+Huhg+=>k)5Q!8d%SQ&{?_bQ_#u51;Fpr){A$|7rDE16q z0}C=k^+slsO^u`pcI2!!R^$e2$1Ij&GP4A^+LXg*u1DpjU?T=FV@PaY=Ox z>R|4SiD@h|Cx43;0J+g`PX3y`YeyDiJ8Axsp*$*4sA=Mq@i}ilW*Qyb^W}A!b#D!2qJ{v{3)$Rj5Oy@2B@6{3d7 zj-K-B=wsvZ4MA4{@^Njyvsl%z@j{LSUPi7xZ>6XQ)zOSxjk zN>9N4PbiIoRgQRNDAnGDWLqZzsl|q=_6M^Ry49(Cy0ag^kRc}(`T&S z$;^zJ2Td51P2A>KlcJ>Pp+`9Gb%U<$Qpy-(k0e__>{LI7ai0PCA{DX2qe_!|A#bLF zN31&P$xk+8y#}713L!~@|B3Z1sk8?|r~j%mwou(Ocgo534sv#PZ|Q*bUdqi9FQm$$ z0rwJ?61~9yb>fxinMdSRzE3 z5F>kE5MOjIgZt_3*L*`8vdR_&%1CrhP=fW|R}=_gA_;}1>X<{aMm4jLol|c*Xjq!4 z$)HfEQX^Jodl^eqszWF4A-99kBo?^TA>_|fiH-ayB4p6w%KQ`FW! zZMR}J_3sVVy5&RsJ%W$1q|FJbef~oaL#*t z<@0m`@A~6?H~Vsh5asbN8H`^myL2~<#) z{FqCIpjH-P>qd3Doiq3@hPydsJm0E)5~M~htvS4g4@X%Rl)b9yN|wc~#-4g&z)L zD0KiNa(g~9XcN7FO~C$(#Y;HQRlY?hKeslctO*0|B64ALnhZz)45E!94g6FbLXte{h zAV5OUK1Z&(_>R~S8Gas19GAodbmg7_sek1&16B}5y^n+-0z@<+Hf!}>T0_>a|4c+#w^5*xg?0do$m5VD|s@UAU>4bITkfNwi zCTvX@i_g^gJ(Ho8CNLQt=91*>3g6xR>@0`p-DA9yzPofROS9a?U~XMT+}(nAEUk4G zSj$SERXPfw9Q?DrzD>K87aW)#uX9&L9`*uDun#THoy0esIOXYhI*2UTs3LH&&1&Bq zwISSSlHs9qCNf-j6!~qQyBX=#)AZ!$XFx-eM(?~(n4nyO;{QN{m&9i57a(D7&F*{v zPS!=i`4(_=1`t!(1pP9$s62%@q-7`GC7Z2)NGxrMu&+uXB-?9GF9fqhlfl(M)@dX< zfl!#^`P8MmVfI;9;uA9N;$3(VXVh$S3w0ZRt}2`=tPt;jR>|lN^dS z>ME0qRtq)6fw2l5oP*iV1ye_oWrWGATI}lkbtbwCHK6K2wYsaLt>WX+z2hh7)h&aI z?btB1q54!{eLz3m#~j5Y*o(ntd;SnUUA=R{!Y(RfCOV?Is3hnM=p6sbP@-f4hW<)N zIUe)KwQCu7eTp=Rv>_ldxd5ncykq3r+Ieos(u{`eAN(hMRIX(omRk9`+x;`0U>V>&x5+KWyba}C6V#QW+JW! zg%!GcYL6Ngx7fmp*>zFQSDmynY_*uB^%f_~6(Om^)IGdPBa8h?<*MPqPxNVDXui~r z%B(NbdA%!wToO@_tOsLL1BDef5^wHn8nZe+e+TVq%GbVwDpuVUAM)>4k9ag{PxA_7 zk@jSKf)eGYz<$Og=}MI2T4i-<*5DbG|Cl}X5vJDFqZf-DC&z8a?8#FxNJ)`eFw&TU zF#~wL6o$0^u`u4ttHcXp#~m|Jd%ym3Rjv);+8+eEJCs5<{|T1*PxxzXpu)IVev+g3 z=P5nPXCJeEvZ1lQj}-5V>)8F+^?1g4lVo(a+%j*;%rhgW2i(&7P~pWJ+&_X!*)8d7 z?80$Jtr&KR%MBXc#Loaa^787ksC+-7U3|_x=}CfQT{PhMP01d$ zUj(G%i-=>58V1R(VfH7p1#Rts9E?s*Ae~Mc6UdcZ

6sn6PtFNNO?_@?*aM@_-RhKVRJbMW-B|qlH7c(rt9@_*zivR zDJQO>4ub^LKoA=JsE=G7K%8Np7?Qe+1JGVhKF93`aO25nnkel?96B;P`K*`Y?@@ai zj+x)4DMIvj1JU$!kd&5|719u6Dxump{zfp!3@RrOp+2{m9gMh;jQc zt@v3xY_hhpCmwV^sR@30HfZTUPF1^td)n885HF;Q#tewMj@EVKG-LO5MBlK4eNe&0 z*q3SB0UWgkyp?UvWzBCTLA?`8Z*b+~eQKQA{o3FbE)%I>{N|7y#XFJd&-e3>urHqp zjV1K~5?I)hj}glaGSPvp&WoUTA{7jF^$D>(1iG}+Yru%`iBf3I3 zeNJ!R3czyDRWmWsYKvEu>MM2|I$bBpWIY?It|X>M-Axvs(`fEzL|TaeHZSOQ&%2n@^!23}+rj6Snq z9SyrI&Uk^YsFS{A?+0L3er2l!EZQH{x-pz0EA6n$I|YxcmHx59i(P96!PIhQqXnt) zeAS+vWqJW>J@bV8MVZv^J!Ay&b)1vQ_+fd4=T6IAa_9+sN7S{p0!JJL!6aq45|6j- z5WK>@IJo3h=3;?iZ@?!F!s=^|wceB6F?G%rFi@WrPs8K$pWWHN%m?- zV|l|!RIM#;wN><-BEjHdI;_)M=@Xt8nZVTtgd$TPW+xPKu-q%|sG!+XV}tw7qd@+` zOWS{>tclV|B==VuEw#YJr5@rd?vEYMT>8B_I^Eu5f5Kc*Ijv&XW8)7gyx!quI|!*d z5gk9Zo_+@Gs1VpBg}Wr1cDtu>pz}xPfSV0h90s${DFUO~SR%k!ET3OuF7U-f!FJz< zP(L(X_rS)I!{!`=WoH1?_1v+xyY2P$>SBTN1_clX##gLgArY-9W@EOY2D7>K}GA#np@T-1`%KoI? zJpX*sp$|3d{G~I2eo8I>OQ-D`6+sx{l{;NH8lSmJfT;4)vNiI0n|u)5`)^a#NyNB4 z+~X?;ol;)qFVRZhw@i>r5u`Ow>cWRXsIEmC0~+u-r|l&hmL_OK!Ki#%CFTicLZRRE z$ZW$u-PN~J#e|`V5d26+a2JB7!_VuaEtu7oDBO7XtQz@?;S2j_g9~NvYazll_N`Lg zWNBb>cqH>DYCSljH?^!(A(3SzlZFP^Wh0ViLHB^W#zKFrp7i#J3B=LbO*{N2gmauA zDoy44iQ*QU1~Uh47hM=SuRLH!ph=la4?=pvK@ff&fG^U*&0Fo3qh8B1_qTm!h?jk~ zL4Qdtq=uoj<*jieNL)hvTD_QLWa?eRVSnz>$&WaW%uCwBPj0{;N6!^XTSstrl`F{* z+!QCezV^#CxyU1N)wFH>%%y^u7%_1?C%Zal45><{twMa;cXWCOX--+fw$aF-B&$*M z;G19eiE1U3{Ji?V7FZz_0mv{@fOEx=RQ)4GR@%+h$qjIC@QaS%X|^NX?QaTZ|m*L`}wwf*r z@@nHlOt|!v6rA2*81u$gmoyg_f)bD!*LGxd^76mRw07AtymCCujg`t~D@wld*vD0& zTVf1hQ~_iq?JbPU7TK;Eiu8&>Yv`7S<4`uuT8&YYX7k)sq|2vtavqoBHzhX8QepjE zE~2|{D)yn1tUMrV(&JvZB5z3B)o<1&_=|yImm*6B<$3k9_U|MJ0p>z$4@VA0ra3AEW;h%|N_|Ia|3CsAz1RP(P_YI6H?O&$ZK!0@U3z8R3j zW)}uE*B{T&m+b1l1PO(<%qB$hNGv}YH{B-O+}TI+TQ|jxcQtPPB4Wni$_vYJe&h8t z-m9^P*zO#utXAO})hy6wKk1|xIX_NdOm%hWQZx(@hs{!sLy-YONC7a^*;|hWuP3u# zK7V)D8`kffc;AO9Iss6eLsi(Mjy1yja8$pm#K7)E+m<}yYFQ3c9cKq}zjPu2)vT;_ zTcU15MB_g={#~v5TY>Kp+Qv#ymdi(E9WbOG&MYB|2buuXIENW0F+)2aY7 z6}-V%H#)QXlp`vNx+dUtl}xq_kS&eCT}yM!PzQdI-85_PZqTT1cP&b|BKDo`yr=O6 z6^9z+RiZ!JX8lHLv+Ux(4)mP(piTFQEojxI{YkFx*JZDW{`)K7mwg&Kw}Ph=nK;&_ zWJmPJq>Q+NY?*Zrk#y?d!hu+mY4!5x`pJO6HKIw_?BzJW49cja;YGqpiUK5pvpV51 zifrtgRz@qIO>ek~Z$_3QGPC7V?5CkX6`t9$rT7m-l5creAP4)VL5d(`=WU9MSkpiz zK#s(`n2RQ0nUJ&gRa#9_Q3y>k6jv@+twY1EL!=S03(*1VU-THXw{Bj@&dUbPTV~Go zbtw&WI@Wxc6~MLQ@m#`^%f=Yf|o)!oL}lnZuxK1(aa|_VDlTbd*xL#*|LkW7z{UH8ei2xg1Gs zA@bcd5^j_}+UB+&@Kb#IRonSWBIIicKjd}kY}!u)xoqRR>d1(xS-eR@Q@n?iK1Jb@ zTaZIkog2W#b~Ux-D5$@dz;qC(0fy=p#YGpq#M_a~k%*v_9lwuN8Bd#1WR!DEDP9y* zBUAT7fVt-4jin78jRyam90UfBZJF=x@qZzsS?=xM&Terspc0!?80p8Hbl7Ewq5m)s za+H~mrAS?|`*i)8p?{7*$!9kKu`pkHq2)8Z^l-gRogFAOKU!nugq?dfH|Fq(ReIU2aFLP%=PuPye)hy@|rzN4{g4RG@VU+uq_fQU@LR#7dmi)i#Jp(wxj zyXVq9K?JKh7vrdnyPIab4``a!tHnAv^>rV$zp%z7{zJP3ng+3K*j_Bsk-& zl1S&BqN;djlH(}W+E}U$9)_GHDTQmCju3iw z(5`CEv5hH_b|TRAqYr_|c_<<8oQEYhje3XFAYU$U3k+X7aKKE6$q044kKugbgl$DD zYG26vNYfbIN1XQx8q z)!HUGm<>*ZF8pCn^uP|LBvT9Tb3B-V)RlQ$tT zGBhTK=3xraEVL1tnQTD*@TaI7gw*RQL$mhK0fPE&ux#mW2#!KRmZ=tt%6zdn0f?S1e{R0dr!{I>o)MGW!-6X|8YK2Kyj& zyu5+2TVb{dDNLHHAVv7#@O=T{ef4KC2lWBo^n%`1QYf13=i6A?KrtUuHB_U2&VWCw z5us_1v<$f4z3iDrKPA{%pxmt6{$7>a^~aN!U#}Y^?Jno2IHMI3vt2E(ER7rGn1z7k!0ynJzFpeo8?JzX6z)H4Do}8vE;xl~XxFeh12E^nl)l-Brhu;yjUa zW&)4+6l~RKWMa<|L~&k~uf4(~upa=P)nC3lBRxk2lHgF6wNHQ_Qgn#4di`}4W)GOU zw?hryhY;&Z`S&lFZz2Q^rx^Mo&zFgplT4LL@b_p@;xrF{F7*>w@NHUT+sXLY0p^Nn zeH=bc<(xPOIYtIXe#Y<vKm+`d3CzWRdCD& zeh4%>p354T+uRla4D&78NJq4iFeL-`YF7{@?sW~X*|)=ipnVJ@jauN{(2VT-0SV#s z*_#im80EA&YsS-9FBZ36k1HA67JOs%8wlT}HepL-5h~R3P#EQ-+)O-=MPd^iKl2uB zH9V3iN~QgTgcDWe^NZfLqEX-9F3nv@s#gD+!GLi>kP^^!?A)L-1BBo~Rp@Ixn2(goSRL6gz4-`J z>`4Dl9_nmjCgSbA;11-qitSG#)=`VP)<~Tm^m{x9JskYI8s_l;YP76nBL}v_AuHwh zbi8kp7zc3(h2>6JR^!x_RcII znm>xr34glu$GFhq;skQE-M5P=D}xf9Cu4y{?O_Nz3NS48<%fhQYjkVpj^eCaV+)h5 zhzyv5zE*}&hOFIf4v==8n;t@GcK&%9yx>H`6v@aM!G&*~xyjK;x@pE)!47}NCzKin zC|P?jr+uC49~&av0P92EqhxZ`Kcxnw0UEa=hY4~wg=mLt#wT54U4Qf;TQ)Z-MD-ww z;!v9TwKs{Jeu$r7GDG4cizqfvP(*>O8Tp#`d&Bc@!@nmoAUM1d>XXVzW=6nrB}iBD9zP&hQN$JEfHR4snh2!wC)fxBnR@s4 z8hHff-XWv#S~U}Dk(b7sASysYF&!F-=okWwvUeb(kBwyq9yN>%7x4X*d>x$>@(J<+ z&=^D-1aYo>YdiEyX@Ir1WFfQrNNuOI34x_iA{^l;szgnh(z&dmC~;0XagV~hLE%+E zd+@Or(+0yE4#}Q1<-^+w0S4J##sL9EvG_cA4q&I9@2!B5d@_;ojQeBf;>a3}L5 z!JnX~{9ERe)2)v5krr^vditSk=(Qc=MNwE8L98pem;9gK$-(^~e5X%WFF|8gJO3OKPW|8dW;5z%}hq3Cuj%qr2NFnF_!aJIj^C%)XzpJlUmZVj*uM zsl;N+Z)w(B{UwfTUkr&5OR4ekQ{&oDj$0aD;SSYDQT{8s1>nu(4|mUkqk_J?r)ewp zNRi!jMBajT%L@3+0%y8(X2(Nzmno#k{=T-xd}+Fob?RS{Ir&p4;lqri!s`ozHx_#v z2hE|bXp!(3p*TK3#&B0k5lbTkY-#35a+?QdQb??Ph3>Z5S~D@>q^<@PaPcPnpEnVC zHra%6;9JV4dE5W!VX5FeO*X~vv)Xu`N6P1qr1h2(S~q8dx59Kb6IWo)!xjqdX4ou) z%xKe-dj4OSZ(WjM;F7U{dl#{WXT0w<;B}&7%%x`{cZ?&q<}>^ND4ZUOqIry!oy!wk z)c)>JRMQ%-QO2|j)3!c}B=E-Q@%g_}gap_?v3TQD4=3VLR+ zLaxrgEQ{)xvf5|~&|d%u&Bm*RDUcI$#$jBR`m62%Zhu+quhv`|rj2t3Afvm)E^D3k zTApPH+Fjcg@M^L=Wf$yh-){){Zm%(PRCS0;p^*k6A%%`_s4PCZ3K>qU;POEt*%}#J zVUhth+Asb^HFy^F$&{T@q7p9zfJ6kmmi?@|Yz7lCfCP2_Q@jj((E|p|WyK4l5Y~!^ zpb&X|)DuMrc29|z_iDK%M2RH?c|=6e5v5R0#|y3b12|QD19sLR3H!q!ofuSNVBire z8AiQm1bXsKp9(ir0S1M|CilTP)oI5@Xi;ie+v5xs<$Rz!6=}A*)1;ZAK%1$9Hja{>ueOA zq7{LG%zw0A4@E-Y8rtkEKspQweIYWDq~dW)`<*it{y%o$+5Z`eH)-^;HT6*NG-7H3 zLRV>_Y$*XMOz~*Dgzq%!c{qP+@1uqB)`t@|tO)oq)Vg<&2hVBM`(CO#jv_Vmhi>`r$=-V? zeD=wI`4I%bX*KNLz)usk|I}QGY_seK!%#37B{(atm=PxnH&TtJ6ZtFFOF5T|&2}GUCzzcs7r0w@HLe;q!?)X=^5N61^0ESyraKgI)SX+zz# zF2lO58p;4t^e4Dfm%frEUAEfUuzod?h0JQu5@!^#o~*Uvjm(ipmHU{sBv7Geyo%KS z6Fna4AY5_mLv&w0Vfo!Ju1+`aPNHy;oCzcsoo7=Wi);C!6D;LZiom&x)yt15?HA5& ze@A+c+ohgBM0AYdAF9&nA80`;aVm8;)wMHqqlBsKq(~d8??9~X*THX6STw)y418uW zH|Y3ei{zQt8ciPsv&TemC9y`czS9Y2ccKdLuGKl4ws+tR>m}a6(Fad|#zc|#+d4XA zCy?)EJK zA>DQ3lUD&tVr@$|H#sjDz%#c&_zAH>=P!Uwsp znCw#0C)rMRdiJ!#uMA=V6bGDcOQHjk-u_Rmm#Z+m}1LiA$ry)#cF}q5c;Mn zyCk}XND3KOTmPgOHfw~4$6QhC+|1de!#v@t=jI`Ly znp%r+JLOQ9)B^n7kUi)J@qycV580cNN9cAxe!h7aMn73Jb6HH5)X04(FpF&jx)dzL zjP%t*3t#B~V)a)~FJ!2uXB#r!9Mm5j$lSUJXh1AOJo@sprrwzJ6R2koZeu6yi(GI^ zJ#zR1k8O1o?QB!wCT9`ROn-LnjHydRL#+s@DiB##KblQr`Cq0;^(yHJC>Uyf1TZJ5(@Z7Da6iXmW zAcYzv<}+?Z=zXNuGtKcQ2bVhs=zt%=2I8|u&_MC`;&8i#ou-s`GSrR;>dNrP5xO|G zg0S><1pcv70f<%4RdF4kx=ghE&X*@16w(ft4b3K(99;%rh$w8y5!SYNsJ~7fVxUVO z1sy#FWZ)U43|Feijt09w1er$JQe^cD&@fX4atQ)%-UVi274Ki%HRD^ zAyX$wDyuAO1I$2c{MNTa{5Q`J8P7odF@bY8`h*H*v42Z~gL%K|dKGt_{wDyzov!Wg z%gQR<rHdA+Pv?jw^X)=9?p7>k%M81f<2j? zozFK*;`L9)1&KCp-A-kKvl} z{ssb8DoG%zLEs0dMv^@pQfZc)#JC+~{LIvD5lH2DgcAqxIz^=@t2?P=qrrZg7nT-?+^8S|-uwU?-NcX`?ojaxrVow5P(LpU(e6jo=HJz=GvI=F(y_va0>s8}O;GKAv4*07ipS>2@n_SO zZL7jnQLcH=K*5vrg{Q3I^IbMnq5Yl5VTu;03vEqLG48AEE-?X>mnva>Q&-IZTNToih(Jqyz`fJpPxG*J6Uj7oVL0eU&H<;d zuag<7q_Jzk-h?FZRcjRoU=+SL#s7(VxB)!ow;@5^7n{+TN<-V96y_jW=plxzj`Ef% zX2#q|j`1}3lxlI_*k~uPY{SvUk@%|Xxj7?G!`OAA3Cq*iK|s^(DL1_7EV?i`@%`|Na z&`)QmN!^m#7P-CSL@Xb_#dG_H#-p{iR3|T@?9!=kSKKwjBCBs7W@`!RC>H^3-tqkM~c1OzQK{(4EZ0RAEFU>7O0bw@;bBn&h}bioun$Qt@FhIVgZ0e=MTp zrD#CMZFa4``XX?s1X$$BeE+W>sA)z`WsT#S9wtlmtBAn5VS%%3U@TAsCiBB+bW0pd z)&|R^U{QSvdkDXq4xk$oUTaqy9Vm{%RUfZ!w7{ zsA+0G{z~|Xa{|;fzAyP2g6IQxAJq@P{5#WGaNwXT%LzFZjY;Prn10R_EI41#o|*s6(}yfgD=Evf@czH2_^IQI=HiT% z^X0QEmmtgmN5}FTrLNu76_#3~;AwnqLp7 z5FtWj(05FbDpvsK!h$`A^E-gccML1%%zjT~S~ZU_!JjWa@kiP9;nN6)v*!MY--8`P zA)mfJ(Zzl}nmVa6ja{gd>`S1&(ixn`?R^JS6ic^mO&}vlkf;npMuC}O2!kX^f|3ML zP(%h85G6AN5lI4qijtIIASf765XFd!D1ss;R8Ws11~4B{5i!o)JuvF=_q_kSf4#fj zUF%Z4s`ppBcJ11=tGc?Yx*6v6Ob!oSCpb;fnpe0_KL3t+ zq~4+;*Yp5-q+t&8OI-Z^K@BSWgjXRgWOt6&wyAe4P2L<8?6OiF{36&AmF_$FYjA(& zr-POc7Hs8s2N~tF>o|$Ij|2Jz{Td(i(Py{6^w^Wu>2sXeIX$g%%17Ll=>p|l#p%!M zMM(HL7g@f64SI=o&mVqz_^GPz+)x&~E`QFxQ|i4_wwaZ`5qa1(rAJQii~E#^iOaO> z4Gk``7N&J*+4+cFv5c&)zbK@Xu-6uyZVAl)x;-zu2{E_LD$`|>h(&hxFTM)uc_!W^&)j>UL*I0l?Bt2fe9udktzBVY#FUh_ zq_CUTUtHIGW~uPkZP)(TH$SOWZD(~e%}9r+G24<~b!v>v(!(25__8M@PrN_q5bx5O zMtbHx{g|@WI*!vYvx&NV-k&}m#P|0$eq+mj-a9b&Ln+^bCFGWqshiia1e*@;ztU6E z-B+}A)2fqs-XRjpBwh}U=zdw98Sz2XEBvZEdOnJ-#ts7P>vjEcecy7onk4_^CK~{weq#DqgJo;jrh?R=w(~ z!L@y#ny25L)g~Hwxiw4Cu07ZG<8>z^v@v3*Rk>IFhtmt1Lkm{Jpr}-Ft-C zbvY*f>cLs%nUR#%6BX6vB562@#r=;GUbmlqum4eUSHRn6WvlPu%#O*)9oN7~x9!w7bd@>N zx$VRYmjumEW$ER~F~pm%G%( zU)M4cgOgozFaFhry~0PF9!3|)SS<~Aqv|%jnuABGNBfJE*CQp`V|9xII}EAY<6JJr zWQ#gx441N0n7347)Gl2Vsdyv*ad^T$*`e5_rU{W|Q`%liQK3J4eC6{inUC|=l-Opi%=b+d2;5qy zeXgYIu;VrFf$K>Xg$w%=SM&y)WE&S;SgEn(dVO3GrLs_@UH@DZXG7D;sZ))$HYJ61 z`XRp7Crcb}7GIXMaXs?p(U-g@HJ<(R+dI9tK3Eo=ATKR+ecFeM5rs2*+ZV(v%9%CP zcwFLk^*p1`H7AUVgI|j*K3aF7a4!3K%FH=6jb^duBj)Ls*-RBwK6i2cx%RlN%QK0S z6ejFVp`ECfitDact<-#zYJ912NHX#KnxQFI(ln~xylrlnU)FSVD@#qGDAc>fJ7-&* z2ia2RMd@R~yBAXoR`xufp2OadwDIPG!SbPqUUHESku~A-G$jQw|9j7RmoFv~mP%~t z$=h{qrsyoc9S3>^uU@(x@=)5$U;JcL&bC^Tzq}oOqUQvuIzij2!xi=Jc`2P*LAi@Y zYIUn>+`hIp6j`=&2KVw$T_oof{f6*B?8rxrZ&nKZDZwgxi(dzdz0=%!@M2VerDM&N z&`Nx<)gx<#oVnLZoR){VG8+@tseSv{xUOGiSozSaJ7#J)+NtcM!W}|Y+Y0c8ou`iCZ#rJ9%!B_yVC8+JQC3=O|nqGUS?)? zzEb%Ma@EyWTg&Ba*I75ZQ^(Nn)N1cxw?2QqMq~BkSs6}}k#cuh znTcn~J@k=2;nPtsE=*iNJh7stCL)KgY_(ORldju~W5lC4>-G!#tt)nuEvj9NTTT=DV{PZ3!R9+3aMgGtIupv`um9w2P^&I$Qj252-!U(~NIvTAessrV`!@ z>&Lg|mpU?I-ODbqO?B|=bMsncuYNY3!&tMe`aYdwY<29yRgG)Tm5V*K`l`|kTPnP- z_2j7UqI?=?jlmUqx=%hTM@|WecWIekP?0HJ#u~n`App?` zXv2vwv9Hc#yskVl^o=?x`DpQry%x0Fj61gv_L$DHVeeQMrn&Ruo(zQ{FW(eghwaC< zG{T`ajmErYh2q&N=d>@CdfxU6O6C80nNo=O2B?ecNe&Vta+{96%&rvXR}bn6tPd-i zoGxE?d#{38qs3BR_kx&>!ijdcdW{8&I{X5!gWH~quOmr?scblR>q*j-MGXP?l2+N7 z@|0ZFfmw5(ogeYqjns7vGK76LhS~pFZm)CO-YY1(%fmvk-AwSnu(9X*R*wVPZ`P+; zU(Ng)QnKGWR#0L013y|o*{7xRGjClS4*lGyRG2`yJxNhwXNK1)rw#ai9hIw*9eyP* z?pbG!GT-ozx!y*l>l-`jEGWV4XX;aHyS$tOSLxvWI8eTP*UEgmp zz1#j^q)^_<3NNSf&FOT(np-)gvtP{rvqn3x>3qFWPi4x-^8$V$u?ttoarT~`d?}aB zKaaJwYuN<6V^Z{q;IlU_-fG~K#D1+7edKayYUU@jesxtJ>6XilWWJ{^!V8UG)v4r9 zb03(ZinG@-J(!*J+3u4@M@RZo=462Zjr@WSGTHV9=K{2vEf<_IQ4-mh*X3@r#7%sS zTVm#|lP(jM6`yge%n;HnxT#*CbbjrC4})><&Rd(qYOfAg?3?#>+u56SjjpqmO~2I4 zU9_9fi7U6RRQ2j|dB`7}{krW)Z+M{mTIr-$IghunKNHgZtUiWTDvXG&Q&rY656+k} z!{=zjj@%Qi^OvSs^sSE@>f0&FDf=XL)k609r`v%cyY{viXdL>mAJ;lGXV*d5vc#MZ4YgOfRTPe*CuxT4W+iw_W65kSd3mc5+T*mtB8%(-6nktZm8`ub=-VdpXmSmofU~vW-tv$X z)`m+lx7~8flJ+If=*~|rDPLi+;Byk+?57l?%E4HV_aRd66+&7KuE(?s#bxRq>^vUx z5Z9?@Q~TIU&ss{f^2A$Q-G|tl#^TH3CJJQ8Oy01~wDpe*ic8Nf+B|C|mE$AtB`9;c zS8Q{G$HWxcwnRd0j7Cx0EETz3lHaBuw>bLcygE zD!#eai{I$z>m6Kg`oSST=1g1sC%(gHvbrbDZ2dzgq28(N&^sH$i|H+I#g%U$%~_p= zyOiv*FL9oliciZceN+|sQta-H2$h!HZH+|3>YdLfs~+r}Gohm|Cv$UcF44Yll~noD zhLzMxn>TN7F3PPan!so1C78mP>MYo9yt(*Y$}FMog__6n2C{mRJ-hNWeJ^}?$)BTk zas2eIT9`T5o%v_cYiE*T^kfDs%%)F!!K5LE5+X+ zBud0bMc7Zw$Exd0F*PH8hxVr^!Kl~o=aAp4Fh&kMYZz|hYnZ;JXQcT4N~gh-X%Uxa z4<-uJCpm8|dmMMK=ve2rJp&gV>;vU;nP0q~Z)2XArLk3mLsUmaEdSv&dT& z?baOBC@pH%rMx_0<@%PQhT;6q<5Nt6mp;52-sh4(HKi`YFeR&{?o*^w{j0l4+8PSA z*@K?cRS!ZV4t6enyzWg(reN`{A+rRdLzQw#)k;0xZQ18l3NnIxRgL={l-6zc&AFoZ z*}_#d({<6U6tm_t=~_1Ohb-guZ^;{+TqBU};dPmXRg~E6Myf}%d^>YdX@$>T^~52N=+_@--thTnql^;K$`jRVa((F zRg5h5{O`MHW>|z#Gp>**e`X^xEu28Y6Wtb~TXG?rHF;iwaq1J(N&Z z_q)-BzBw40JF4qw^$X&zz>ltOx00}`$+bHDu@h-$-7KJ8lD(Z+B@P8<0M<)b1;VX(aAT=eY{NwLs?>vjoJrSRm6%fgv7K3hpMJN;sc-#Vv04-N ze% z0hN6tSMjV*vbk}LS=Ib9pM8Z{&vtBnUzZx}`MO6rf6|w}!6lXS8Oy^8lv0tZ>8?|# zI)&Wu{(~daA};I+DRllr72&kpxlfR`b9&IftiwjD~xD zbzzQq2WifyGl^Rz@^q^gzL35UN-kI;`Lc3`h1%QRSId{Zp@{O)9Cx2mPztzXGNWL< z(UzUB--IE-x#eqQE# ztuL0)XRh#1OndA8=hwZyo`M43ghJk`EO4vdsM28@)UfP+z3N?A+i&(l*IU^lH=OqE zjrO%O?4LO^+6RAM+KgcJJbC7P#vPp`Z{iy|DQOoHIF)QR*bl!0D=fatw(j*VFR`2p zrTrJhiaq-Cr35nC)*e$sNKnDlHdU{+T{OS%I4*5c_R|{*vJR)}XTIKe- zu9LfjqVqb~r)U$pCq0&Gz0asNsk}e$$eNDh%MQPm{&2XvXUfsiK>n3dXFitF9^L4< z8zzzQFu1d4ju)snP?1aDft)`l|s630L25p`}Z>FZMKZUY^=MV4To& zi~gm5P^h%8;Ys&_nwsY|UK{0V1!mJ(NbuWoZ|6uSG+3oKBBXq5*0#neOl#U9>$G-( z{$u%Q<;?rGf@ld-ZfTb^yLat_Fvpumtsf{C%}$TfX^TNB&sqxUPm6TkQSMu}dj_D1 zC8a7?g8N#mT&~85Ya1}tMJoc1mVos2zRd~H+1*_GxU@k=EatQJpotT~O4otLA1hbBUfjygyXAtZ(nj)-u8 zt_lDg!-jka;c)~+0RCZ!;y66w2YLdc1YmKXXCO*}3|1D43OGJ4?Eqt&Vk`)94;yB9L^$G}Np`LtBtr_t z79j`7$L!$InU2nGB$^(TqGw7zDBL&aOia3WxG z_78hB$8ZJcMtK5=2!ukTQ3-jY_NRk9aSU$)jLRRD!C`GG5a!yn2l)7c(Yg*`@?-qt zfCUOh>jIY}p)o80Sa?kS49FxE2%v7b$T|RL0mgc+0(_EJfams+u>nH)KjDI(Fsc}{ znM$GHDn{$V{DiOg(eH#YjP<)%)u^4jK)?7H-Va!!>W5EoJ4P|6LHM6A;U~=h6UOAQ zI;TKXg(wV>MxioHDJG^AV-gLzgKBC>`z;S4%rj6LY#-G!dX^kZk-!54Zm+mO*T^G0 z95B)#mH@&$<3r~FgBV)0ZRfN0p-zvWdOee{!+-C1Q;8sz5)oz0+zz$ z0c${A6u`-VCjiD2^#aCO5zr&h(K`{LMyM5QEf&Q=#t`U^$p{rAunY_m12+f&mIc0; z26zx;peWJ+%nvE->e2(e39t}g3&0xzPXp`#cn`?)17-u3fRb1}?s$~C3ZyZNg+7qM zJd_GDqGK{nx5V-!^1N=h33Lqn@2?YSde1WV069JO} z`vCqqP)OVZQE3d)SVW_ov7FKT@$>%{4?yozjYw38|2hDSjDKM=Xe6o$iAtwqgaO59 zzX<%Rj{kuinA_-JH+3|^T*NRoVHiSV=u|_h0mH-)`EjpoA(SWOC%RvPBoc$LqY9me zIEqUVc7&jIh@-glv+q~mucOym6}}1|443W|8D0B+wUai|Fn-1nIU%izs2--Uh)1b)jM zWxfW|0y9%59K7&X`*_?R6o)uJ5c2#okdIW&H!jjM6=q=c@(y_WM`>wM^MPn3d^kPrHRyuR~)D)I}& z!xIPg%z?EGi&UfscX2($08B?SkQStU9xu%s zFMmgQ{q>Wo{|J8O`Ua*I=-+K)efb|L`ZtA!eyXQuyq~-! zG>^W9>u?|Hh52KY^7wx@kMQJplqZjkpx*_a9FP7^=4T#Hjz@pa`yJ-V@hDG**Ipi< zM|t_bQl9*;{J%^8cgd$gg}jK>%^5rX&W?Z1AHBx0>wGl+^OC=p91S z{_~Q*m*nZ;(ceq`b1qL0kN&l!1F}K0(IRwjY;MD(e!d3(U3yd-wu1d@mtR|)suL%SS4U2QcBZvtCcf{JnRtc#SjBo}x zCOj)R6C4Tte6RU^M0`c25h}241>#HMYxy5&jvxmtx(K|<_yS@9@hE|yFoJDN5%==B zNlOS}Xn^RYn87V;&KD`G&2L6DBhC;^6%`P`5phIQfj`B5lsLkbGvJ#ocay6{nSY(s zkKF$=5+Pzim)IfpPf_i+^|*FIkxt9E65Jkwgyx5Djkq8}C`p>rinAqnDcW-$;KT@# zvP{k(ZV=xmlgz>6yYOz(J2@)&I=qk69~^sp8h(j{7z)GB$KMj0j`Hya_`MS%&}sYx ze5zcZs96RQofgJ=K6 zXckh2Jt^3Ug{X~m;h-TCkYK>mtrkej!66F=wil#^G|^O$nv5nQ8F+@4hf=Uz#mxf( z(q!13Q-<^eIK+WsyFHTJ{V1&bG|+5@ykSKeiK1bhnhNWU7^rCmo?6yM0f+KQ;HqC^3w1B4pEx>lX zbhx^)Hcmyx$ede$1d0L+lFn@Ui_ZEMWD!f?w6a2a4bgRfw2ZFx^F7iMNpuJ8Ytpjc7^?EUC@l>U_F7Y0AwIy!4fRC1|KVfye!m+ zQEW#O+b877U~>Pz!XTn?s6yx8jNjFf}$HNj>+e%Oh?_74egf5e_GdG|)bq!)r}e5bhYAn?HD z0}1T;1e5vc87md`GvI1KM1Nt9*hKjq;ww43IOoOuB?_QFJYk@|gR*Z96H%BD5!Fi* zkj(*1nyU&T8(GmpFZp@mi=c(=h#VZ}nZ zMI{gkS;44JMW?xGbxs!N3FjNfg|nZypEyiBN?b@ZCvM=&hSwP!0yYOC;(nw3CK8&k zWFHUX9vJt)xCj2m12Ru3Tikm#^@W;Ba5 zj};vg5)n?K>QVHtmt(N{j~a=$`Sn|?ITVJWp%D!h-g9R-ySuu;D}G%A3MDLzWUp_a zXQ*qWXF#$IAvrpd=Gl`Nn8>3GIKIkl}!W;6S^K`#5D})Iz>L&~5vv~-hFQy%j$zxyLE$koek&a_ zcX=dB-<=f`5gQ%AvWsJdvsHP;0|UO7jf{;B)_OcPK-r&F1_0D^Rx{zeRD5Y5Dp#`<2~H97=F95eK1doVqLpvRa_ zGoc2uf^_Ld#-N8nW9s@F1R3ZC1~3?g2AC~$12QQvz|=k>I*bWj781q`X6eVX{3FRE z%(bR7+#JoxG(E~#(k+z94gy(ovQtQSY{D3KZb%r*gU!S|M>VD}sB|L+-H1jtrcn*Y zB*vyTOcnQ=P%;T~yeZfY9%N#p4vKO;Vrmo3VzMKm=SD?A44A(>;lg+ec zvRR<(`)8$dd7qU|g^x=qU@SPm)HxzBBxw1+6UDAVZhtz2#6Y#n$F3+3R@4{@4Iy#I zvnexR)Xo@Y94nAK#tc}(3=d|(bq-@~R4n8-{b^!M^EYDA>AEb#AR2TA^sIkifPpT> zkVXkIpwW#WlUF__B8ZLM4rT;{Yrq3Aw76f=lC-!k*XGH^FJXbxFdyhrU}TwaeE{Fs z8jbltAMDr1F6Ggt=>OVEZr)FqJx?6w5)6Kynk-1;VcY}b9vJt)xCh2PFz$i>eIEF+ OxM79ElTJJ=UH%KnCt-{L literal 0 HcmV?d00001 diff --git a/app/src/main/resources/static/js/authorize.js b/app/src/main/resources/static/js/authorize.js new file mode 100644 index 000000000..1cef693e8 --- /dev/null +++ b/app/src/main/resources/static/js/authorize.js @@ -0,0 +1,10 @@ +document.addEventListener("DOMContentLoaded", () => { + document.getElementById("authorizeButton").addEventListener("click", () => { + const checkboxes = document.querySelectorAll("input[type='checkbox']"); + for (const checkbox of checkboxes) { + checkbox.checked = true; + } + + document.confirmationForm.submit(); + }); +}) diff --git a/app/src/main/resources/static/js/main.js b/app/src/main/resources/static/js/main.js index e7e70bb69..6456c3ba6 100644 --- a/app/src/main/resources/static/js/main.js +++ b/app/src/main/resources/static/js/main.js @@ -1,22 +1,6 @@ -_hyperscript.addCommand('reindex', function(parser, runtime, tokens) { - if(!tokens.matchToken('reindex')) return - - const expr = parser.requireElement('queryRef', tokens); - - return { - args: [expr], - op(context, value) { - console.log(value); - - return runtime.findNext(this) - } - } -}) - document.addEventListener("DOMContentLoaded", function () { htmx.config.selfRequestsOnly = true; - //TODO: Enable CSP - htmx.config.allowScriptTags = true; + htmx.config.allowScriptTags = false; htmx.config.historyCacheSize = 0; htmx.config.allowEval = false; htmx.config.useTemplateFragments = true; diff --git a/app/src/main/resources/static/js/reorder.js b/app/src/main/resources/static/js/reorder.js new file mode 100644 index 000000000..c7e4ec890 --- /dev/null +++ b/app/src/main/resources/static/js/reorder.js @@ -0,0 +1,9 @@ +function updateNames(key, ...queries) { + for (const query of queries) { + const inputFields = document.querySelectorAll(query); + inputFields.forEach(function(input, index) { + input.name = key + '[' + index + ']'; + input.id = key + index; + }); + } +} diff --git a/app/src/main/resources/templates/common/alert.html b/app/src/main/resources/templates/common/alert.html index 6b6bea7bc..6860d14cb 100644 --- a/app/src/main/resources/templates/common/alert.html +++ b/app/src/main/resources/templates/common/alert.html @@ -7,7 +7,7 @@ _="on load transition opacity to 1 then wait 7s - then transition opacity to 0 then remove me">Successfully edited + then transition opacity to 0 then remove me"> \ No newline at end of file diff --git a/app/src/main/resources/templates/common/error.html b/app/src/main/resources/templates/common/error.html new file mode 100644 index 000000000..499d34c66 --- /dev/null +++ b/app/src/main/resources/templates/common/error.html @@ -0,0 +1,5 @@ + +

+ +

+ \ No newline at end of file diff --git a/app/src/main/resources/templates/common/header.html b/app/src/main/resources/templates/common/header.html index ac0b5db47..292faf626 100644 --- a/app/src/main/resources/templates/common/header.html +++ b/app/src/main/resources/templates/common/header.html @@ -1,22 +1,3 @@ -

diff --git a/app/src/main/resources/templates/common/input.html b/app/src/main/resources/templates/common/input.html index 3961767cc..ef7e2a050 100644 --- a/app/src/main/resources/templates/common/input.html +++ b/app/src/main/resources/templates/common/input.html @@ -1,7 +1,3 @@ - - - - - + + - - - - - + + + + - + diff --git a/app/src/main/resources/templates/pages/activate-cid.html b/app/src/main/resources/templates/pages/activate-cid.html index f34703827..dadf9905c 100644 --- a/app/src/main/resources/templates/pages/activate-cid.html +++ b/app/src/main/resources/templates/pages/activate-cid.html @@ -1,9 +1,22 @@
-

Enter cid to start process of creating an account

-
- +
- I already have a code
\ No newline at end of file diff --git a/app/src/main/resources/templates/pages/allow-list.html b/app/src/main/resources/templates/pages/allow-list.html index b1a278939..f27a5e89b 100644 --- a/app/src/main/resources/templates/pages/allow-list.html +++ b/app/src/main/resources/templates/pages/allow-list.html @@ -1,21 +1,36 @@
Back -
-
+
+
+

+ Allow new cid +

+
+
- -
+
+ +
+ + +
Cid
+
+
+ + +
+
diff --git a/app/src/main/resources/templates/pages/api-key-credentials.html b/app/src/main/resources/templates/pages/api-key-credentials.html index d273eebda..1fa518555 100644 --- a/app/src/main/resources/templates/pages/api-key-credentials.html +++ b/app/src/main/resources/templates/pages/api-key-credentials.html @@ -1,13 +1,3 @@ -
diff --git a/app/src/main/resources/templates/pages/api-key-details.html b/app/src/main/resources/templates/pages/api-key-details.html index 8df09509f..dd4320656 100644 --- a/app/src/main/resources/templates/pages/api-key-details.html +++ b/app/src/main/resources/templates/pages/api-key-details.html @@ -1,44 +1,3 @@ -
@@ -67,7 +26,7 @@

-
+
diff --git a/app/src/main/resources/templates/pages/client-credentials.html b/app/src/main/resources/templates/pages/client-credentials.html index 5b79e9432..1bf3df0ec 100644 --- a/app/src/main/resources/templates/pages/client-credentials.html +++ b/app/src/main/resources/templates/pages/client-credentials.html @@ -1,13 +1,3 @@ -
diff --git a/app/src/main/resources/templates/pages/client-details.html b/app/src/main/resources/templates/pages/client-details.html index 11e7880b2..5a401847d 100644 --- a/app/src/main/resources/templates/pages/client-details.html +++ b/app/src/main/resources/templates/pages/client-details.html @@ -1,47 +1,3 @@ - -
@@ -118,7 +74,7 @@
  • -
    diff --git a/app/src/main/resources/templates/pages/consent.html b/app/src/main/resources/templates/pages/consent.html index fc84cbe90..3c02d5cca 100644 --- a/app/src/main/resources/templates/pages/consent.html +++ b/app/src/main/resources/templates/pages/consent.html @@ -1,23 +1,4 @@ - - +
    @@ -49,7 +30,7 @@

    - @@ -57,7 +38,7 @@

    - +
    diff --git a/app/src/main/resources/templates/pages/create-api-key.html b/app/src/main/resources/templates/pages/create-api-key.html index c4662dd3e..abac5e4ce 100644 --- a/app/src/main/resources/templates/pages/create-api-key.html +++ b/app/src/main/resources/templates/pages/create-api-key.html @@ -1,13 +1,3 @@ -
    diff --git a/app/src/main/resources/templates/pages/create-client.html b/app/src/main/resources/templates/pages/create-client.html index b16adbf72..1885dbf35 100644 --- a/app/src/main/resources/templates/pages/create-client.html +++ b/app/src/main/resources/templates/pages/create-client.html @@ -1,36 +1,3 @@ - -
    Back diff --git a/app/src/main/resources/templates/pages/create-group.html b/app/src/main/resources/templates/pages/create-group.html index 86c77bcaf..9e1606013 100644 --- a/app/src/main/resources/templates/pages/create-group.html +++ b/app/src/main/resources/templates/pages/create-group.html @@ -1,37 +1,14 @@ - - -
    Back
    -
    +
    +
    +

    + Create group +

    +
    +
    +
    \ No newline at end of file diff --git a/app/src/main/resources/templates/pages/create-super-group.html b/app/src/main/resources/templates/pages/create-super-group.html index f5b2929e0..94a2f56b2 100644 --- a/app/src/main/resources/templates/pages/create-super-group.html +++ b/app/src/main/resources/templates/pages/create-super-group.html @@ -1,33 +1,24 @@ -
    Back
    -
    -
    -
    -
    - - +
    +
    +

    Create super group

    +
    +
    +
    +
    +
    + +
    + +
    +
    \ No newline at end of file diff --git a/app/src/main/resources/templates/pages/create-user-client.html b/app/src/main/resources/templates/pages/create-user-client.html index ddc3bef14..9d6756723 100644 --- a/app/src/main/resources/templates/pages/create-user-client.html +++ b/app/src/main/resources/templates/pages/create-user-client.html @@ -1,21 +1,3 @@ -
    Back @@ -26,7 +8,8 @@

    - Hello + This client will be created in your name, and will be shown everytime + a user attempts to authenticate with gamma to your client.

    diff --git a/app/src/main/resources/templates/pages/create-user.html b/app/src/main/resources/templates/pages/create-user.html index 1cd6500b9..057f53852 100644 --- a/app/src/main/resources/templates/pages/create-user.html +++ b/app/src/main/resources/templates/pages/create-user.html @@ -1,49 +1,43 @@ -
    Back - -
    -
    -
    -
    -
    -
    - - - - +
    +
    +

    + Create user +

    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    +
    diff --git a/app/src/main/resources/templates/pages/finalize-forgot-password.html b/app/src/main/resources/templates/pages/finalize-forgot-password.html index 8d303544e..0ca1ff6d6 100644 --- a/app/src/main/resources/templates/pages/finalize-forgot-password.html +++ b/app/src/main/resources/templates/pages/finalize-forgot-password.html @@ -1,25 +1,25 @@ -
    -

    - You should have received an email with a token for resetting your password. Please check your spam email if you can't find it. You might also have typed your cid/email incorrectly. -

    -
    -
    -
    -
    - +
    +
    +

    + Finalize resetting password +

    +
    +

    + You should have received an email with a token for resetting your password. +

    +

    + Please check your spam email if you can't find it. You might also have typed your cid/email incorrectly. +

    +
    +
    +
    +
    +
    + +
    +
    \ No newline at end of file diff --git a/app/src/main/resources/templates/pages/forgot-password.html b/app/src/main/resources/templates/pages/forgot-password.html index 922332235..51ced302d 100644 --- a/app/src/main/resources/templates/pages/forgot-password.html +++ b/app/src/main/resources/templates/pages/forgot-password.html @@ -1,16 +1,19 @@ -
    -

    - Please enter your email to begin the reset process. -

    -
    - +
    +
    +

    + Reset password +

    +
    +

    + Please enter your email to begin the reset process. +

    +
    +
    + +
    +
    \ No newline at end of file diff --git a/app/src/main/resources/templates/pages/group-details.html b/app/src/main/resources/templates/pages/group-details.html index a35100443..c8d8f4005 100644 --- a/app/src/main/resources/templates/pages/group-details.html +++ b/app/src/main/resources/templates/pages/group-details.html @@ -1,35 +1,3 @@ -
    Back @@ -47,8 +15,9 @@

    Group details

  • -