From 780e33334ff7b372a2e7d42f23824d44aa9b2966 Mon Sep 17 00:00:00 2001 From: this-is-tobi Date: Sat, 5 Oct 2024 18:45:59 +0200 Subject: [PATCH] refactor: split docs between hexaforge and cpin --- .github/workflows/build.yml | 53 +- Dockerfile.cpin | 25 + Dockerfile => Dockerfile.hexaforge | 8 +- README.md | 184 +---- cloud-pi-native/.vitepress/config.ts | 40 + cloud-pi-native/.vitepress/sidebar.json | 68 ++ cloud-pi-native/.vitepress/theme/index.ts | 5 + cloud-pi-native/.vitepress/theme/style.css | 100 +++ cloud-pi-native/acceleration/mocks.md | 223 +++++ cloud-pi-native/agreement/exploitation.md | 42 + cloud-pi-native/agreement/introduction.md | 83 ++ cloud-pi-native/agreement/observability.md | 41 + cloud-pi-native/agreement/support.md | 77 ++ cloud-pi-native/best-practices/kyverno.md | 34 + cloud-pi-native/best-practices/labels-list.md | 77 ++ cloud-pi-native/certification/introduction.md | 114 +++ cloud-pi-native/contribute.md | 32 + cloud-pi-native/faq/introduction.md | 219 +++++ cloud-pi-native/index.md | 29 + cloud-pi-native/public/examples/postgres.yaml | 71 ++ cloud-pi-native/public/favicon.ico | Bin 0 -> 1150 bytes .../acces_services_observabilit\303\251.png" | Bin 0 -> 117620 bytes cloud-pi-native/public/img/architecture.png | Bin 0 -> 193502 bytes cloud-pi-native/public/img/argocd-example.png | Bin 0 -> 239545 bytes cloud-pi-native/public/img/argocd.png | Bin 0 -> 58123 bytes .../img/console_admin/cluster_ajout.png | Bin 0 -> 258201 bytes .../img/console_admin/cluster_details_env.png | Bin 0 -> 17502 bytes .../img/console_admin/cluster_liste.png | Bin 0 -> 12335 bytes .../img/console_admin/cluster_suppression.png | Bin 0 -> 11320 bytes .../public/img/console_admin/create_org.png | Bin 0 -> 30377 bytes .../console_admin/environnement_creation.png | Bin 0 -> 80438 bytes .../img/console_admin/journaux_erreur.png | Bin 0 -> 124508 bytes .../public/img/console_admin/menu_admin.png | Bin 0 -> 21915 bytes .../console_admin/plugin_configuration.png | Bin 0 -> 66299 bytes .../img/console_admin/projet_detail.png | Bin 0 -> 129382 bytes .../img/console_admin/quota_creation.png | Bin 0 -> 60648 bytes .../img/console_admin/recherche_projet.png | Bin 0 -> 11691 bytes .../console_admin/recherche_utilisateurs.png | Bin 0 -> 43037 bytes .../img/console_admin/zone_creation.png | Bin 0 -> 71994 bytes cloud-pi-native/public/img/creation.png | Bin 0 -> 15274 bytes .../public/img/environnement/cluster-env.png | Bin 0 -> 6369 bytes .../public/img/environnement/create-env.png | Bin 0 -> 72991 bytes .../public/img/environnement/menu.png | Bin 0 -> 14452 bytes .../public/img/environnement/quota-env.png | Bin 0 -> 18282 bytes .../public/img/environnement/type-env.png | Bin 0 -> 13997 bytes .../public/img/gitlab-ci-read-secrets.png | Bin 0 -> 13945 bytes .../public/img/gitlab-ci-vault.png | Bin 0 -> 6433 bytes cloud-pi-native/public/img/gitlab.png | Bin 0 -> 56124 bytes cloud-pi-native/public/img/gitlab.svg | 1 + cloud-pi-native/public/img/gitops.png | Bin 0 -> 121699 bytes cloud-pi-native/public/img/global-vision.png | Bin 0 -> 217145 bytes .../img/guide/alerting/alert_firing.png | Bin 0 -> 19968 bytes .../img/guide/alerting/alert_ns_group.png | Bin 0 -> 23308 bytes .../guide/alerting/contact_point_create.png | Bin 0 -> 42144 bytes .../guide/alerting/contact_point_manager.png | Bin 0 -> 5266 bytes .../guide/alerting/create_alert_step_1.png | Bin 0 -> 9485 bytes .../guide/alerting/create_alert_step_2.png | Bin 0 -> 74603 bytes .../guide/alerting/create_alert_step_3.png | Bin 0 -> 11099 bytes .../guide/alerting/create_alert_step_4.png | Bin 0 -> 43372 bytes .../guide/alerting/create_alert_step_5.png | Bin 0 -> 25924 bytes .../guide/alerting/notification_policies.png | Bin 0 -> 29589 bytes .../notification_policy_nested_create.png | Bin 0 -> 37761 bytes .../img/guide/alerting/policy_default.png | Bin 0 -> 30355 bytes .../public/img/guide/dashboard_infra.png | Bin 0 -> 11676 bytes .../public/img/guide/grafana-sign-in.png | Bin 0 -> 44364 bytes .../img/guide/grafana_add_visualization.png | Bin 0 -> 29191 bytes .../public/img/guide/grafana_create_alert.png | Bin 0 -> 15815 bytes .../img/guide/grafana_dashboard_save.png | Bin 0 -> 20631 bytes .../img/guide/grafana_dashboard_submenu.png | Bin 0 -> 4983 bytes .../img/guide/grafana_first_dashboard.png | Bin 0 -> 58877 bytes .../img/guide/grafana_first_visualization.png | Bin 0 -> 103242 bytes .../grafana_first_visualization_metrics.png | Bin 0 -> 28395 bytes .../grafana_first_visualization_option.png | Bin 0 -> 11689 bytes ...rafana_first_visualization_time_window.png | Bin 0 -> 6155 bytes .../guide/grafana_list_dashboard_final.png | Bin 0 -> 36654 bytes .../public/img/guide/grafana_menu.png | Bin 0 -> 1069 bytes .../img/guide/grafana_menu_alerting.png | Bin 0 -> 11167 bytes .../img/guide/grafana_menu_dashboard.png | Bin 0 -> 7954 bytes .../img/guide/grafana_new_dashboard.png | Bin 0 -> 9633 bytes .../img/guide/grafana_visualization_save.png | Bin 0 -> 3150 bytes .../public/img/guide/kibana/authorize.png | Bin 0 -> 71049 bytes .../img/guide/kibana/create_index_pattern.png | Bin 0 -> 99841 bytes .../guide/kibana/create_index_timestamp.png | Bin 0 -> 102619 bytes .../img/guide/kibana/create_index_valid.png | Bin 0 -> 94890 bytes .../public/img/guide/kibana/discover.png | Bin 0 -> 147951 bytes .../kibana/discover_available_fields.png | Bin 0 -> 17725 bytes .../img/guide/kibana/discover_query.png | Bin 0 -> 9892 bytes .../img/guide/kibana/discover_results.png | Bin 0 -> 84089 bytes .../public/img/guide/kibana/discover_time.png | Bin 0 -> 2782 bytes .../public/img/guide/kibana/log-in.png | Bin 0 -> 17619 bytes .../img/guide/kibana_authorize_access.png | Bin 0 -> 60705 bytes .../img/guide/kibana_login_openshift.png | Bin 0 -> 17642 bytes .../img/guide/project/create_project.png | Bin 0 -> 72397 bytes .../img/guide/project/monprojet_secrets.png | Bin 0 -> 74533 bytes .../guide/project/monprojet_tableaudebord.png | Bin 0 -> 63938 bytes .../img/guide/project/monprojettuile.png | Bin 0 -> 7621 bytes .../public/img/guide/repository_synchro.png | Bin 0 -> 18926 bytes .../public/img/learning-process.png | Bin 0 -> 189016 bytes cloud-pi-native/public/img/mocks/add-repo.png | Bin 0 -> 71244 bytes .../img/mocks/mocks-argo-app-details.png | Bin 0 -> 36422 bytes .../img/mocks/mocks-argo-parameters.png | Bin 0 -> 4587 bytes .../public/img/mocks/mocks-argo.png | Bin 0 -> 26639 bytes cloud-pi-native/public/img/nexus.png | Bin 0 -> 6338 bytes .../public/img/onboarding-process.png | Bin 0 -> 43281 bytes cloud-pi-native/public/img/repo-sync-01.png | Bin 0 -> 99604 bytes cloud-pi-native/public/img/repo-sync-02.png | Bin 0 -> 72130 bytes cloud-pi-native/public/img/sonarqube.svg | 20 + cloud-pi-native/public/img/team/add.png | Bin 0 -> 20226 bytes cloud-pi-native/public/img/team/members.png | Bin 0 -> 27347 bytes cloud-pi-native/public/img/team/menu.png | Bin 0 -> 14469 bytes .../img/team/permission-environnement.png | Bin 0 -> 64049 bytes .../public/img/tuto/1tuto-connexion.png | Bin 0 -> 119833 bytes .../public/img/tuto/2tuto-acces-services.png | Bin 0 -> 84640 bytes .../img/tuto/2tuto-commander-projet.png | Bin 0 -> 47990 bytes .../img/tuto/2tuto-creer-projet-termine.png | Bin 0 -> 2125 bytes .../public/img/tuto/2tuto-creer-projet.png | Bin 0 -> 11045 bytes .../public/img/tuto/2tuto-mes-projets.png | Bin 0 -> 11869 bytes .../tuto/3tuto-depots-ajouter-gitlab-ci.png | Bin 0 -> 28992 bytes .../img/tuto/3tuto-depots-ajouter-ok.png | Bin 0 -> 1387 bytes .../public/img/tuto/3tuto-depots-ajouter.png | Bin 0 -> 40111 bytes .../public/img/tuto/3tuto-depots.png | Bin 0 -> 15629 bytes .../public/img/tuto/3tuto-environnement.png | Bin 0 -> 93474 bytes .../public/img/tuto/4argocd-app-details.png | Bin 0 -> 63129 bytes .../public/img/tuto/4argocd-menus-bouton.png | Bin 0 -> 13218 bytes .../public/img/tuto/4argocd-menus.png | Bin 0 -> 50043 bytes cloud-pi-native/public/img/tuto/4argocd.png | Bin 0 -> 122607 bytes .../public/img/tuto/etat-services.png | Bin 0 -> 54467 bytes cloud-pi-native/public/img/vault.svg | 1 + cloud-pi-native/public/img/vision.png | Bin 0 -> 242341 bytes .../public/logo-marianne-gouvernement.png | Bin 0 -> 25260 bytes hexaforge/.vitepress/config.ts | 42 + hexaforge/.vitepress/sidebar.json | 196 +++++ hexaforge/.vitepress/theme/index.ts | 5 + hexaforge/.vitepress/theme/style.css | 100 +++ hexaforge/administration/clusters.md | 39 + hexaforge/administration/environnements.md | 24 + hexaforge/administration/introduction.md | 19 + hexaforge/administration/journaux.md | 29 + hexaforge/administration/organisations.md | 29 + hexaforge/administration/plugins.md | 27 + hexaforge/administration/projets.md | 20 + hexaforge/administration/quotas.md | 26 + hexaforge/administration/utilisateurs.md | 20 + hexaforge/administration/zones.md | 27 + hexaforge/contribute.md | 30 + hexaforge/guide/alerting.md | 115 +++ hexaforge/guide/archive-logs.md | 203 +++++ hexaforge/guide/best-practices.md | 192 +++++ hexaforge/guide/deployment-with-argo.md | 30 + hexaforge/guide/environments-management.md | 26 + hexaforge/guide/get-started.md | 47 ++ hexaforge/guide/logs-kibana.md | 57 ++ hexaforge/guide/metrics.md | 94 +++ hexaforge/guide/projects-management.md | 44 + hexaforge/guide/repositories-management.md | 74 ++ hexaforge/guide/secrets-management.md | 189 +++++ hexaforge/guide/team.md | 40 + hexaforge/guide/tutorials.md | 110 +++ hexaforge/index.md | 23 + hexaforge/installation/configuration.md | 196 +++++ hexaforge/installation/debug.md | 32 + hexaforge/installation/installation.md | 93 +++ hexaforge/installation/introduction.md | 27 + hexaforge/installation/prerequisites.md | 52 ++ hexaforge/installation/secrets.md | 33 + hexaforge/installation/uninstallation.md | 70 ++ hexaforge/installation/versions.md | 345 ++++++++ hexaforge/platform/compatibility.md | 19 + hexaforge/platform/glossary.md | 16 + hexaforge/platform/introduction.md | 50 ++ hexaforge/platform/roadmap.md | 3 + hexaforge/platform/skills-matrix.md | 24 + hexaforge/public/examples/postgres.yaml | 71 ++ .../acces_services_observabilit\303\251.png" | Bin 0 -> 117620 bytes hexaforge/public/img/architecture.png | Bin 0 -> 193502 bytes hexaforge/public/img/argocd-example.png | Bin 0 -> 239545 bytes hexaforge/public/img/argocd.png | Bin 0 -> 58123 bytes .../img/console_admin/cluster_ajout.png | Bin 0 -> 258201 bytes .../img/console_admin/cluster_details_env.png | Bin 0 -> 17502 bytes .../img/console_admin/cluster_liste.png | Bin 0 -> 12335 bytes .../img/console_admin/cluster_suppression.png | Bin 0 -> 11320 bytes .../public/img/console_admin/create_org.png | Bin 0 -> 30377 bytes .../console_admin/environnement_creation.png | Bin 0 -> 80438 bytes .../img/console_admin/journaux_erreur.png | Bin 0 -> 124508 bytes .../public/img/console_admin/menu_admin.png | Bin 0 -> 21915 bytes .../console_admin/plugin_configuration.png | Bin 0 -> 66299 bytes .../img/console_admin/projet_detail.png | Bin 0 -> 129382 bytes .../img/console_admin/quota_creation.png | Bin 0 -> 60648 bytes .../img/console_admin/recherche_projet.png | Bin 0 -> 11691 bytes .../console_admin/recherche_utilisateurs.png | Bin 0 -> 43037 bytes .../img/console_admin/zone_creation.png | Bin 0 -> 71994 bytes hexaforge/public/img/creation.png | Bin 0 -> 15274 bytes .../public/img/environnement/cluster-env.png | Bin 0 -> 6369 bytes .../public/img/environnement/create-env.png | Bin 0 -> 72991 bytes hexaforge/public/img/environnement/menu.png | Bin 0 -> 14452 bytes .../public/img/environnement/quota-env.png | Bin 0 -> 18282 bytes .../public/img/environnement/type-env.png | Bin 0 -> 13997 bytes .../public/img/gitlab-ci-read-secrets.png | Bin 0 -> 13945 bytes hexaforge/public/img/gitlab-ci-vault.png | Bin 0 -> 6433 bytes hexaforge/public/img/gitlab.png | Bin 0 -> 56124 bytes hexaforge/public/img/gitlab.svg | 1 + hexaforge/public/img/gitops.png | Bin 0 -> 121699 bytes hexaforge/public/img/global-vision.png | Bin 0 -> 217145 bytes .../img/guide/alerting/alert_firing.png | Bin 0 -> 19968 bytes .../img/guide/alerting/alert_ns_group.png | Bin 0 -> 23308 bytes .../guide/alerting/contact_point_create.png | Bin 0 -> 42144 bytes .../guide/alerting/contact_point_manager.png | Bin 0 -> 5266 bytes .../guide/alerting/create_alert_step_1.png | Bin 0 -> 9485 bytes .../guide/alerting/create_alert_step_2.png | Bin 0 -> 74603 bytes .../guide/alerting/create_alert_step_3.png | Bin 0 -> 11099 bytes .../guide/alerting/create_alert_step_4.png | Bin 0 -> 43372 bytes .../guide/alerting/create_alert_step_5.png | Bin 0 -> 25924 bytes .../guide/alerting/notification_policies.png | Bin 0 -> 29589 bytes .../notification_policy_nested_create.png | Bin 0 -> 37761 bytes .../img/guide/alerting/policy_default.png | Bin 0 -> 30355 bytes .../public/img/guide/dashboard_infra.png | Bin 0 -> 11676 bytes .../public/img/guide/grafana-sign-in.png | Bin 0 -> 44364 bytes .../img/guide/grafana_add_visualization.png | Bin 0 -> 29191 bytes .../public/img/guide/grafana_create_alert.png | Bin 0 -> 15815 bytes .../img/guide/grafana_dashboard_save.png | Bin 0 -> 20631 bytes .../img/guide/grafana_dashboard_submenu.png | Bin 0 -> 4983 bytes .../img/guide/grafana_first_dashboard.png | Bin 0 -> 58877 bytes .../img/guide/grafana_first_visualization.png | Bin 0 -> 103242 bytes .../grafana_first_visualization_metrics.png | Bin 0 -> 28395 bytes .../grafana_first_visualization_option.png | Bin 0 -> 11689 bytes ...rafana_first_visualization_time_window.png | Bin 0 -> 6155 bytes .../guide/grafana_list_dashboard_final.png | Bin 0 -> 36654 bytes hexaforge/public/img/guide/grafana_menu.png | Bin 0 -> 1069 bytes .../img/guide/grafana_menu_alerting.png | Bin 0 -> 11167 bytes .../img/guide/grafana_menu_dashboard.png | Bin 0 -> 7954 bytes .../img/guide/grafana_new_dashboard.png | Bin 0 -> 9633 bytes .../img/guide/grafana_visualization_save.png | Bin 0 -> 3150 bytes .../public/img/guide/kibana/authorize.png | Bin 0 -> 71049 bytes .../img/guide/kibana/create_index_pattern.png | Bin 0 -> 99841 bytes .../guide/kibana/create_index_timestamp.png | Bin 0 -> 102619 bytes .../img/guide/kibana/create_index_valid.png | Bin 0 -> 94890 bytes .../public/img/guide/kibana/discover.png | Bin 0 -> 147951 bytes .../kibana/discover_available_fields.png | Bin 0 -> 17725 bytes .../img/guide/kibana/discover_query.png | Bin 0 -> 9892 bytes .../img/guide/kibana/discover_results.png | Bin 0 -> 84089 bytes .../public/img/guide/kibana/discover_time.png | Bin 0 -> 2782 bytes hexaforge/public/img/guide/kibana/log-in.png | Bin 0 -> 17619 bytes .../img/guide/kibana_authorize_access.png | Bin 0 -> 60705 bytes .../img/guide/kibana_login_openshift.png | Bin 0 -> 17642 bytes .../img/guide/project/create_project.png | Bin 0 -> 72397 bytes .../img/guide/project/monprojet_secrets.png | Bin 0 -> 74533 bytes .../guide/project/monprojet_tableaudebord.png | Bin 0 -> 63938 bytes .../img/guide/project/monprojettuile.png | Bin 0 -> 7621 bytes .../public/img/guide/repository_synchro.png | Bin 0 -> 18926 bytes hexaforge/public/img/learning-process.png | Bin 0 -> 189016 bytes hexaforge/public/img/mocks/add-repo.png | Bin 0 -> 71244 bytes .../img/mocks/mocks-argo-app-details.png | Bin 0 -> 36422 bytes .../img/mocks/mocks-argo-parameters.png | Bin 0 -> 4587 bytes hexaforge/public/img/mocks/mocks-argo.png | Bin 0 -> 26639 bytes hexaforge/public/img/nexus.png | Bin 0 -> 6338 bytes hexaforge/public/img/onboarding-process.png | Bin 0 -> 43281 bytes hexaforge/public/img/repo-sync-01.png | Bin 0 -> 99604 bytes hexaforge/public/img/repo-sync-02.png | Bin 0 -> 72130 bytes hexaforge/public/img/sonarqube.svg | 20 + hexaforge/public/img/team/add.png | Bin 0 -> 20226 bytes hexaforge/public/img/team/members.png | Bin 0 -> 27347 bytes hexaforge/public/img/team/menu.png | Bin 0 -> 14469 bytes .../img/team/permission-environnement.png | Bin 0 -> 64049 bytes hexaforge/public/img/tuto/1tuto-connexion.png | Bin 0 -> 119833 bytes .../public/img/tuto/2tuto-acces-services.png | Bin 0 -> 84640 bytes .../img/tuto/2tuto-commander-projet.png | Bin 0 -> 47990 bytes .../img/tuto/2tuto-creer-projet-termine.png | Bin 0 -> 2125 bytes .../public/img/tuto/2tuto-creer-projet.png | Bin 0 -> 11045 bytes .../public/img/tuto/2tuto-mes-projets.png | Bin 0 -> 11869 bytes .../tuto/3tuto-depots-ajouter-gitlab-ci.png | Bin 0 -> 28992 bytes .../img/tuto/3tuto-depots-ajouter-ok.png | Bin 0 -> 1387 bytes .../public/img/tuto/3tuto-depots-ajouter.png | Bin 0 -> 40111 bytes hexaforge/public/img/tuto/3tuto-depots.png | Bin 0 -> 15629 bytes .../public/img/tuto/3tuto-environnement.png | Bin 0 -> 93474 bytes .../public/img/tuto/4argocd-app-details.png | Bin 0 -> 63129 bytes .../public/img/tuto/4argocd-menus-bouton.png | Bin 0 -> 13218 bytes hexaforge/public/img/tuto/4argocd-menus.png | Bin 0 -> 50043 bytes hexaforge/public/img/tuto/4argocd.png | Bin 0 -> 122607 bytes hexaforge/public/img/tuto/etat-services.png | Bin 0 -> 54467 bytes hexaforge/public/img/vault.svg | 1 + hexaforge/public/img/vision.png | Bin 0 -> 242341 bytes hexaforge/services/artefacts.md | 58 ++ hexaforge/services/gitlab.md | 72 ++ hexaforge/services/gitops.md | 44 + hexaforge/services/sonarqube.md | 23 + hexaforge/services/vault.md | 53 ++ package.json | 21 +- pnpm-lock.yaml | 762 ++++++++++++++++++ 288 files changed, 5352 insertions(+), 158 deletions(-) create mode 100644 Dockerfile.cpin rename Dockerfile => Dockerfile.hexaforge (64%) create mode 100644 cloud-pi-native/.vitepress/config.ts create mode 100644 cloud-pi-native/.vitepress/sidebar.json create mode 100644 cloud-pi-native/.vitepress/theme/index.ts create mode 100644 cloud-pi-native/.vitepress/theme/style.css create mode 100644 cloud-pi-native/acceleration/mocks.md create mode 100644 cloud-pi-native/agreement/exploitation.md create mode 100644 cloud-pi-native/agreement/introduction.md create mode 100644 cloud-pi-native/agreement/observability.md create mode 100644 cloud-pi-native/agreement/support.md create mode 100644 cloud-pi-native/best-practices/kyverno.md create mode 100644 cloud-pi-native/best-practices/labels-list.md create mode 100644 cloud-pi-native/certification/introduction.md create mode 100644 cloud-pi-native/contribute.md create mode 100644 cloud-pi-native/faq/introduction.md create mode 100644 cloud-pi-native/index.md create mode 100644 cloud-pi-native/public/examples/postgres.yaml create mode 100644 cloud-pi-native/public/favicon.ico create mode 100644 "cloud-pi-native/public/img/agreement/acces_services_observabilit\303\251.png" create mode 100644 cloud-pi-native/public/img/architecture.png create mode 100644 cloud-pi-native/public/img/argocd-example.png create mode 100644 cloud-pi-native/public/img/argocd.png create mode 100644 cloud-pi-native/public/img/console_admin/cluster_ajout.png create mode 100644 cloud-pi-native/public/img/console_admin/cluster_details_env.png create mode 100644 cloud-pi-native/public/img/console_admin/cluster_liste.png create mode 100644 cloud-pi-native/public/img/console_admin/cluster_suppression.png create mode 100644 cloud-pi-native/public/img/console_admin/create_org.png create mode 100644 cloud-pi-native/public/img/console_admin/environnement_creation.png create mode 100644 cloud-pi-native/public/img/console_admin/journaux_erreur.png create mode 100644 cloud-pi-native/public/img/console_admin/menu_admin.png create mode 100644 cloud-pi-native/public/img/console_admin/plugin_configuration.png create mode 100644 cloud-pi-native/public/img/console_admin/projet_detail.png create mode 100644 cloud-pi-native/public/img/console_admin/quota_creation.png create mode 100644 cloud-pi-native/public/img/console_admin/recherche_projet.png create mode 100644 cloud-pi-native/public/img/console_admin/recherche_utilisateurs.png create mode 100644 cloud-pi-native/public/img/console_admin/zone_creation.png create mode 100644 cloud-pi-native/public/img/creation.png create mode 100644 cloud-pi-native/public/img/environnement/cluster-env.png create mode 100644 cloud-pi-native/public/img/environnement/create-env.png create mode 100644 cloud-pi-native/public/img/environnement/menu.png create mode 100644 cloud-pi-native/public/img/environnement/quota-env.png create mode 100644 cloud-pi-native/public/img/environnement/type-env.png create mode 100644 cloud-pi-native/public/img/gitlab-ci-read-secrets.png create mode 100644 cloud-pi-native/public/img/gitlab-ci-vault.png create mode 100644 cloud-pi-native/public/img/gitlab.png create mode 100644 cloud-pi-native/public/img/gitlab.svg create mode 100644 cloud-pi-native/public/img/gitops.png create mode 100644 cloud-pi-native/public/img/global-vision.png create mode 100644 cloud-pi-native/public/img/guide/alerting/alert_firing.png create mode 100644 cloud-pi-native/public/img/guide/alerting/alert_ns_group.png create mode 100644 cloud-pi-native/public/img/guide/alerting/contact_point_create.png create mode 100644 cloud-pi-native/public/img/guide/alerting/contact_point_manager.png create mode 100644 cloud-pi-native/public/img/guide/alerting/create_alert_step_1.png create mode 100644 cloud-pi-native/public/img/guide/alerting/create_alert_step_2.png create mode 100644 cloud-pi-native/public/img/guide/alerting/create_alert_step_3.png create mode 100644 cloud-pi-native/public/img/guide/alerting/create_alert_step_4.png create mode 100644 cloud-pi-native/public/img/guide/alerting/create_alert_step_5.png create mode 100644 cloud-pi-native/public/img/guide/alerting/notification_policies.png create mode 100644 cloud-pi-native/public/img/guide/alerting/notification_policy_nested_create.png create mode 100644 cloud-pi-native/public/img/guide/alerting/policy_default.png create mode 100644 cloud-pi-native/public/img/guide/dashboard_infra.png create mode 100644 cloud-pi-native/public/img/guide/grafana-sign-in.png create mode 100644 cloud-pi-native/public/img/guide/grafana_add_visualization.png create mode 100644 cloud-pi-native/public/img/guide/grafana_create_alert.png create mode 100644 cloud-pi-native/public/img/guide/grafana_dashboard_save.png create mode 100644 cloud-pi-native/public/img/guide/grafana_dashboard_submenu.png create mode 100644 cloud-pi-native/public/img/guide/grafana_first_dashboard.png create mode 100644 cloud-pi-native/public/img/guide/grafana_first_visualization.png create mode 100644 cloud-pi-native/public/img/guide/grafana_first_visualization_metrics.png create mode 100644 cloud-pi-native/public/img/guide/grafana_first_visualization_option.png create mode 100644 cloud-pi-native/public/img/guide/grafana_first_visualization_time_window.png create mode 100644 cloud-pi-native/public/img/guide/grafana_list_dashboard_final.png create mode 100644 cloud-pi-native/public/img/guide/grafana_menu.png create mode 100644 cloud-pi-native/public/img/guide/grafana_menu_alerting.png create mode 100644 cloud-pi-native/public/img/guide/grafana_menu_dashboard.png create mode 100644 cloud-pi-native/public/img/guide/grafana_new_dashboard.png create mode 100644 cloud-pi-native/public/img/guide/grafana_visualization_save.png create mode 100644 cloud-pi-native/public/img/guide/kibana/authorize.png create mode 100644 cloud-pi-native/public/img/guide/kibana/create_index_pattern.png create mode 100644 cloud-pi-native/public/img/guide/kibana/create_index_timestamp.png create mode 100644 cloud-pi-native/public/img/guide/kibana/create_index_valid.png create mode 100644 cloud-pi-native/public/img/guide/kibana/discover.png create mode 100644 cloud-pi-native/public/img/guide/kibana/discover_available_fields.png create mode 100644 cloud-pi-native/public/img/guide/kibana/discover_query.png create mode 100644 cloud-pi-native/public/img/guide/kibana/discover_results.png create mode 100644 cloud-pi-native/public/img/guide/kibana/discover_time.png create mode 100644 cloud-pi-native/public/img/guide/kibana/log-in.png create mode 100644 cloud-pi-native/public/img/guide/kibana_authorize_access.png create mode 100644 cloud-pi-native/public/img/guide/kibana_login_openshift.png create mode 100644 cloud-pi-native/public/img/guide/project/create_project.png create mode 100644 cloud-pi-native/public/img/guide/project/monprojet_secrets.png create mode 100644 cloud-pi-native/public/img/guide/project/monprojet_tableaudebord.png create mode 100644 cloud-pi-native/public/img/guide/project/monprojettuile.png create mode 100644 cloud-pi-native/public/img/guide/repository_synchro.png create mode 100644 cloud-pi-native/public/img/learning-process.png create mode 100644 cloud-pi-native/public/img/mocks/add-repo.png create mode 100644 cloud-pi-native/public/img/mocks/mocks-argo-app-details.png create mode 100644 cloud-pi-native/public/img/mocks/mocks-argo-parameters.png create mode 100644 cloud-pi-native/public/img/mocks/mocks-argo.png create mode 100644 cloud-pi-native/public/img/nexus.png create mode 100644 cloud-pi-native/public/img/onboarding-process.png create mode 100644 cloud-pi-native/public/img/repo-sync-01.png create mode 100644 cloud-pi-native/public/img/repo-sync-02.png create mode 100644 cloud-pi-native/public/img/sonarqube.svg create mode 100644 cloud-pi-native/public/img/team/add.png create mode 100644 cloud-pi-native/public/img/team/members.png create mode 100644 cloud-pi-native/public/img/team/menu.png create mode 100644 cloud-pi-native/public/img/team/permission-environnement.png create mode 100644 cloud-pi-native/public/img/tuto/1tuto-connexion.png create mode 100644 cloud-pi-native/public/img/tuto/2tuto-acces-services.png create mode 100644 cloud-pi-native/public/img/tuto/2tuto-commander-projet.png create mode 100644 cloud-pi-native/public/img/tuto/2tuto-creer-projet-termine.png create mode 100644 cloud-pi-native/public/img/tuto/2tuto-creer-projet.png create mode 100644 cloud-pi-native/public/img/tuto/2tuto-mes-projets.png create mode 100644 cloud-pi-native/public/img/tuto/3tuto-depots-ajouter-gitlab-ci.png create mode 100644 cloud-pi-native/public/img/tuto/3tuto-depots-ajouter-ok.png create mode 100644 cloud-pi-native/public/img/tuto/3tuto-depots-ajouter.png create mode 100644 cloud-pi-native/public/img/tuto/3tuto-depots.png create mode 100644 cloud-pi-native/public/img/tuto/3tuto-environnement.png create mode 100644 cloud-pi-native/public/img/tuto/4argocd-app-details.png create mode 100644 cloud-pi-native/public/img/tuto/4argocd-menus-bouton.png create mode 100644 cloud-pi-native/public/img/tuto/4argocd-menus.png create mode 100644 cloud-pi-native/public/img/tuto/4argocd.png create mode 100644 cloud-pi-native/public/img/tuto/etat-services.png create mode 100644 cloud-pi-native/public/img/vault.svg create mode 100644 cloud-pi-native/public/img/vision.png create mode 100644 cloud-pi-native/public/logo-marianne-gouvernement.png create mode 100644 hexaforge/.vitepress/config.ts create mode 100644 hexaforge/.vitepress/sidebar.json create mode 100644 hexaforge/.vitepress/theme/index.ts create mode 100644 hexaforge/.vitepress/theme/style.css create mode 100644 hexaforge/administration/clusters.md create mode 100644 hexaforge/administration/environnements.md create mode 100644 hexaforge/administration/introduction.md create mode 100644 hexaforge/administration/journaux.md create mode 100644 hexaforge/administration/organisations.md create mode 100644 hexaforge/administration/plugins.md create mode 100644 hexaforge/administration/projets.md create mode 100644 hexaforge/administration/quotas.md create mode 100644 hexaforge/administration/utilisateurs.md create mode 100644 hexaforge/administration/zones.md create mode 100644 hexaforge/contribute.md create mode 100644 hexaforge/guide/alerting.md create mode 100644 hexaforge/guide/archive-logs.md create mode 100644 hexaforge/guide/best-practices.md create mode 100644 hexaforge/guide/deployment-with-argo.md create mode 100644 hexaforge/guide/environments-management.md create mode 100644 hexaforge/guide/get-started.md create mode 100644 hexaforge/guide/logs-kibana.md create mode 100644 hexaforge/guide/metrics.md create mode 100644 hexaforge/guide/projects-management.md create mode 100644 hexaforge/guide/repositories-management.md create mode 100644 hexaforge/guide/secrets-management.md create mode 100644 hexaforge/guide/team.md create mode 100644 hexaforge/guide/tutorials.md create mode 100644 hexaforge/index.md create mode 100644 hexaforge/installation/configuration.md create mode 100644 hexaforge/installation/debug.md create mode 100644 hexaforge/installation/installation.md create mode 100644 hexaforge/installation/introduction.md create mode 100644 hexaforge/installation/prerequisites.md create mode 100644 hexaforge/installation/secrets.md create mode 100644 hexaforge/installation/uninstallation.md create mode 100644 hexaforge/installation/versions.md create mode 100644 hexaforge/platform/compatibility.md create mode 100644 hexaforge/platform/glossary.md create mode 100644 hexaforge/platform/introduction.md create mode 100644 hexaforge/platform/roadmap.md create mode 100644 hexaforge/platform/skills-matrix.md create mode 100644 hexaforge/public/examples/postgres.yaml create mode 100644 "hexaforge/public/img/agreement/acces_services_observabilit\303\251.png" create mode 100644 hexaforge/public/img/architecture.png create mode 100644 hexaforge/public/img/argocd-example.png create mode 100644 hexaforge/public/img/argocd.png create mode 100644 hexaforge/public/img/console_admin/cluster_ajout.png create mode 100644 hexaforge/public/img/console_admin/cluster_details_env.png create mode 100644 hexaforge/public/img/console_admin/cluster_liste.png create mode 100644 hexaforge/public/img/console_admin/cluster_suppression.png create mode 100644 hexaforge/public/img/console_admin/create_org.png create mode 100644 hexaforge/public/img/console_admin/environnement_creation.png create mode 100644 hexaforge/public/img/console_admin/journaux_erreur.png create mode 100644 hexaforge/public/img/console_admin/menu_admin.png create mode 100644 hexaforge/public/img/console_admin/plugin_configuration.png create mode 100644 hexaforge/public/img/console_admin/projet_detail.png create mode 100644 hexaforge/public/img/console_admin/quota_creation.png create mode 100644 hexaforge/public/img/console_admin/recherche_projet.png create mode 100644 hexaforge/public/img/console_admin/recherche_utilisateurs.png create mode 100644 hexaforge/public/img/console_admin/zone_creation.png create mode 100644 hexaforge/public/img/creation.png create mode 100644 hexaforge/public/img/environnement/cluster-env.png create mode 100644 hexaforge/public/img/environnement/create-env.png create mode 100644 hexaforge/public/img/environnement/menu.png create mode 100644 hexaforge/public/img/environnement/quota-env.png create mode 100644 hexaforge/public/img/environnement/type-env.png create mode 100644 hexaforge/public/img/gitlab-ci-read-secrets.png create mode 100644 hexaforge/public/img/gitlab-ci-vault.png create mode 100644 hexaforge/public/img/gitlab.png create mode 100644 hexaforge/public/img/gitlab.svg create mode 100644 hexaforge/public/img/gitops.png create mode 100644 hexaforge/public/img/global-vision.png create mode 100644 hexaforge/public/img/guide/alerting/alert_firing.png create mode 100644 hexaforge/public/img/guide/alerting/alert_ns_group.png create mode 100644 hexaforge/public/img/guide/alerting/contact_point_create.png create mode 100644 hexaforge/public/img/guide/alerting/contact_point_manager.png create mode 100644 hexaforge/public/img/guide/alerting/create_alert_step_1.png create mode 100644 hexaforge/public/img/guide/alerting/create_alert_step_2.png create mode 100644 hexaforge/public/img/guide/alerting/create_alert_step_3.png create mode 100644 hexaforge/public/img/guide/alerting/create_alert_step_4.png create mode 100644 hexaforge/public/img/guide/alerting/create_alert_step_5.png create mode 100644 hexaforge/public/img/guide/alerting/notification_policies.png create mode 100644 hexaforge/public/img/guide/alerting/notification_policy_nested_create.png create mode 100644 hexaforge/public/img/guide/alerting/policy_default.png create mode 100644 hexaforge/public/img/guide/dashboard_infra.png create mode 100644 hexaforge/public/img/guide/grafana-sign-in.png create mode 100644 hexaforge/public/img/guide/grafana_add_visualization.png create mode 100644 hexaforge/public/img/guide/grafana_create_alert.png create mode 100644 hexaforge/public/img/guide/grafana_dashboard_save.png create mode 100644 hexaforge/public/img/guide/grafana_dashboard_submenu.png create mode 100644 hexaforge/public/img/guide/grafana_first_dashboard.png create mode 100644 hexaforge/public/img/guide/grafana_first_visualization.png create mode 100644 hexaforge/public/img/guide/grafana_first_visualization_metrics.png create mode 100644 hexaforge/public/img/guide/grafana_first_visualization_option.png create mode 100644 hexaforge/public/img/guide/grafana_first_visualization_time_window.png create mode 100644 hexaforge/public/img/guide/grafana_list_dashboard_final.png create mode 100644 hexaforge/public/img/guide/grafana_menu.png create mode 100644 hexaforge/public/img/guide/grafana_menu_alerting.png create mode 100644 hexaforge/public/img/guide/grafana_menu_dashboard.png create mode 100644 hexaforge/public/img/guide/grafana_new_dashboard.png create mode 100644 hexaforge/public/img/guide/grafana_visualization_save.png create mode 100644 hexaforge/public/img/guide/kibana/authorize.png create mode 100644 hexaforge/public/img/guide/kibana/create_index_pattern.png create mode 100644 hexaforge/public/img/guide/kibana/create_index_timestamp.png create mode 100644 hexaforge/public/img/guide/kibana/create_index_valid.png create mode 100644 hexaforge/public/img/guide/kibana/discover.png create mode 100644 hexaforge/public/img/guide/kibana/discover_available_fields.png create mode 100644 hexaforge/public/img/guide/kibana/discover_query.png create mode 100644 hexaforge/public/img/guide/kibana/discover_results.png create mode 100644 hexaforge/public/img/guide/kibana/discover_time.png create mode 100644 hexaforge/public/img/guide/kibana/log-in.png create mode 100644 hexaforge/public/img/guide/kibana_authorize_access.png create mode 100644 hexaforge/public/img/guide/kibana_login_openshift.png create mode 100644 hexaforge/public/img/guide/project/create_project.png create mode 100644 hexaforge/public/img/guide/project/monprojet_secrets.png create mode 100644 hexaforge/public/img/guide/project/monprojet_tableaudebord.png create mode 100644 hexaforge/public/img/guide/project/monprojettuile.png create mode 100644 hexaforge/public/img/guide/repository_synchro.png create mode 100644 hexaforge/public/img/learning-process.png create mode 100644 hexaforge/public/img/mocks/add-repo.png create mode 100644 hexaforge/public/img/mocks/mocks-argo-app-details.png create mode 100644 hexaforge/public/img/mocks/mocks-argo-parameters.png create mode 100644 hexaforge/public/img/mocks/mocks-argo.png create mode 100644 hexaforge/public/img/nexus.png create mode 100644 hexaforge/public/img/onboarding-process.png create mode 100644 hexaforge/public/img/repo-sync-01.png create mode 100644 hexaforge/public/img/repo-sync-02.png create mode 100644 hexaforge/public/img/sonarqube.svg create mode 100644 hexaforge/public/img/team/add.png create mode 100644 hexaforge/public/img/team/members.png create mode 100644 hexaforge/public/img/team/menu.png create mode 100644 hexaforge/public/img/team/permission-environnement.png create mode 100644 hexaforge/public/img/tuto/1tuto-connexion.png create mode 100644 hexaforge/public/img/tuto/2tuto-acces-services.png create mode 100644 hexaforge/public/img/tuto/2tuto-commander-projet.png create mode 100644 hexaforge/public/img/tuto/2tuto-creer-projet-termine.png create mode 100644 hexaforge/public/img/tuto/2tuto-creer-projet.png create mode 100644 hexaforge/public/img/tuto/2tuto-mes-projets.png create mode 100644 hexaforge/public/img/tuto/3tuto-depots-ajouter-gitlab-ci.png create mode 100644 hexaforge/public/img/tuto/3tuto-depots-ajouter-ok.png create mode 100644 hexaforge/public/img/tuto/3tuto-depots-ajouter.png create mode 100644 hexaforge/public/img/tuto/3tuto-depots.png create mode 100644 hexaforge/public/img/tuto/3tuto-environnement.png create mode 100644 hexaforge/public/img/tuto/4argocd-app-details.png create mode 100644 hexaforge/public/img/tuto/4argocd-menus-bouton.png create mode 100644 hexaforge/public/img/tuto/4argocd-menus.png create mode 100644 hexaforge/public/img/tuto/4argocd.png create mode 100644 hexaforge/public/img/tuto/etat-services.png create mode 100644 hexaforge/public/img/vault.svg create mode 100644 hexaforge/public/img/vision.png create mode 100644 hexaforge/services/artefacts.md create mode 100644 hexaforge/services/gitlab.md create mode 100644 hexaforge/services/gitops.md create mode 100644 hexaforge/services/sonarqube.md create mode 100644 hexaforge/services/vault.md diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4b6e2af..4917744 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,16 +5,59 @@ on: branches: - main paths: - - docs/** + - hexaforge/** + - cloud-pi-native/** workflow_dispatch: jobs: + path-filter: + runs-on: ubuntu-latest + outputs: + hexaforge: ${{ steps.filter.outputs.hexaforge }} + cpin: ${{ steps.filter.outputs.cpin }} + steps: + - name: Check updated files paths + uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + hexaforge: + - 'hexaforge/**' + cpin: + - 'cloud-pi-native/**' + + infos: + name: Get infos + runs-on: ubuntu-latest + needs: + - path-filter + outputs: + matrix: ${{ steps.infos.outputs.MATRIX }} + steps: + - name: Checks-out repository + id: infos + run: | + MATRIX="[]" + HEXAFORGE='[{"name": "hexaforge"}]' + if [ "${{ needs.path-filter.outputs.hexaforge }}" = 'true' ]; then + MATRIX="$( jq -n -c --argjson acc "$MATRIX" '$acc + [{ "name": "hexaforge", "context": ".", "dockerfile": "Dockerfile.hexaforge" }] )" + else if [ "${{ needs.path-filter.outputs.cpin }}" = 'true' ]; then + MATRIX="$( jq -n -c --argjson acc "$MATRIX" '$acc + [{ "name": "cpin", "context": ".", "dockerfile": "Dockerfile.cpin" }] )" + fi + echo "MATRIX=$MATRIX" >> $GITHUB_OUTPUT + build: name: Build application runs-on: ubuntu-latest + needs: + - path-filter + - infos permissions: contents: read packages: write + strategy: + matrix: + images: ${{ fromJSON(needs.infos.outputs.matrix) }} steps: - name: Checks-out repository uses: actions/checkout@v4 @@ -36,9 +79,9 @@ jobs: - name: Build docker image uses: docker/build-push-action@v5 with: - context: . - file: Dockerfile - tags: ghcr.io/${{ github.repository }}:latest + context: ${{ matrix.images.context }} + file: ${{ matrix.images.dockerfile }} + tags: ghcr.io/${{ github.repository }}-${{ matrix.images.name }}:latest target: prod platforms: linux/amd64,linux/arm64 push: true @@ -48,4 +91,4 @@ jobs: curl -X POST https://gitops.fabrique-numerique.fr/api/v1/applications/cloud-pi-native-docs/sync \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${{ secrets.ARGOCD_TOKEN }}" \ - -d '${{ vars.ARGOCD_SYNC_PAYLOAD }}' + -d '${{ vars.ARGOCD_SYNC_PAYLOAD }}' \ No newline at end of file diff --git a/Dockerfile.cpin b/Dockerfile.cpin new file mode 100644 index 0000000..e2d331c --- /dev/null +++ b/Dockerfile.cpin @@ -0,0 +1,25 @@ +# Base stage +FROM docker.io/node:20.14.0-bullseye-slim AS dev + +WORKDIR /app +RUN npm install --location=global pnpm +COPY --chown=node:root package.json pnpm-lock.yaml ./ +RUN pnpm install +COPY --chown=node:root cloud-pi-native ./cloud-pi-native +ENTRYPOINT [ "pnpm", "run", "dev:cpin" ] + + +# Build stage +FROM dev AS build + +RUN pnpm run build:cpin + + +# Prod stage +FROM docker.io/bitnami/nginx:1.26.1 AS prod + +USER 0 +COPY --chown=1001:0 --chmod=770 --from=build /app/cloud-pi-native/.vitepress/dist /opt/bitnami/nginx/html/ +COPY --chown=1001:0 --chmod=660 ./nginx.conf /opt/bitnami/nginx/conf/server_blocks/default.conf +USER 1001 +EXPOSE 8080 diff --git a/Dockerfile b/Dockerfile.hexaforge similarity index 64% rename from Dockerfile rename to Dockerfile.hexaforge index 08de657..c01b978 100644 --- a/Dockerfile +++ b/Dockerfile.hexaforge @@ -5,21 +5,21 @@ WORKDIR /app RUN npm install --location=global pnpm COPY --chown=node:root package.json pnpm-lock.yaml ./ RUN pnpm install -COPY --chown=node:root docs ./docs -ENTRYPOINT [ "pnpm", "run", "dev" ] +COPY --chown=node:root hexaforge ./hexaforge +ENTRYPOINT [ "pnpm", "run", "dev:hexaforge" ] # Build stage FROM dev AS build -RUN pnpm run build +RUN pnpm run build:hexaforge # Prod stage FROM docker.io/bitnami/nginx:1.26.1 AS prod USER 0 -COPY --chown=1001:0 --chmod=770 --from=build /app/docs/.vitepress/dist /opt/bitnami/nginx/html/ +COPY --chown=1001:0 --chmod=770 --from=build /app/hexaforge/.vitepress/dist /opt/bitnami/nginx/html/ COPY --chown=1001:0 --chmod=660 ./nginx.conf /opt/bitnami/nginx/conf/server_blocks/default.conf USER 1001 EXPOSE 8080 diff --git a/README.md b/README.md index 9a41088..f4c4d65 100644 --- a/README.md +++ b/README.md @@ -1,160 +1,56 @@ -# Cloud π Native - -:warning: __*La plateforme est en cours de construction et des évolutions fréquentes sont à prévoir.*__ :warning: +# Documentation Cloud π Native / Hexaforge Ce dépôt est construit et déployé à l'adresse : -## L'offre - -### Présentation - -Avec l’adoption de la doctrine « Cloud au centre », le Gouvernement Français fait du Cloud un prérequis pour tout nouveau projet numérique au sein de l’État ou refonte substantielle de l’architecture applicative existante. - -**Objectif** : accélérer la transformation numérique au bénéfice des usagers et dans le strict respect de la cybersécurité et de la protection des données des citoyens et des entreprises. - -L'offre interministérielle Cloud π Native, offre les services d'une plateforme DevSecOps complète afin de suivre le cycle de vie complet de son projet. - -La philosophie de l'offre est de créer une chaine collaborative étendue entre l'équipe de développement et l'hébergement, qui s'appuient sur : - - un socle d'intégration à la main des développeurs, appellée chaine primaire. - - un service côté infrastructure étatique effectuant la recompilation du code et l'automatisation des déploiement, appellée chaine secondaire. - -La chaine secondaire est également en charge de mesurer la qualité du code et la conduite d'audits automatisés à chaque build/déploiement contribuant à l'homologation en continu de l'application. - -L'usage de standards industriels largement distribués tel que kubernetes et Gitops et la sécabilité de l'offre, permettent un transfert facilité depuis et vers d'autres solutions d'hébergement kubernetes telles que les Clouds Publics. - -Le cadre interministériel d'utilisaton de l'offre est disponible à l'emplacement suivant : - -Lorsque que l'équipe projet est prête avec un première base de code fonctionnelle, il est possible de l'intégrer sur l'offre Cloud π Native. - -La séquence d'accès typique est la suivante : - - - Effectuer une demande d'accès au service via le formulaire suivant : par un correspondant étatique ayant la compétence pour accepter les conditions CGU et fournir les données d'imputation budgétaire (UO). - - Après acceptation du dossier, l'enrollement du projet est effectuté dans la console Cloud pi Native, et l'équipe projet est en charge d'instancier les ressources nécessaires (gitlab, vault, registry, etc...) dans la chaine secondaire et de configurer son projet ; - - Recopie des repository de code et de déploiement; - - Mise en place du pipeline "DevSecOps" au sein de la chaine secondaire. L'application reste maître de son pipeline et de sa surveillance; - - Mise en place du/des namespaces dans le cluster cible ainsi des secrets nécessaires au fonctionnement et du provisionning gitops de l'application (argoCD); - - Provisionning des ressources d'infrastructure additionnelles ( certificats, ouverture de fluxs, bucket S3, etc...). Cette étape nécessite l'intervention des équipes d'infrastructure Miom ( ou de l'hébergeur choisis) & du ministère cible. (automatisation progressive en cours) - - Construction des artefacts sur l'offre Cloud π Native; - - Analyse de qualité et de la sécurité; - - Construction des images de conteneurs; - - Provisionning de l'application dans le cluster (l'application est tirée via GitOps). - -Enfin, le déploiement s'effectue sur différentes cibles d'hébergement possibles : - - - Un socle kubernetes/Openshift jusqu'au niveau DR sur les environnements du ministère; - - Un cluster kubernetes directement gérés par l'équipe client par exemple chez un Cloud Service Provider. - -**Vision d'ensemble de l'offre :** - -![vision](docs/public/img/global-vision.png) - -### Les services proposés - -L'offre Cloud π Native, portée par le Ministère de l'Intérieur et des Outre-Mer est une offre PaaS basée sur [Cloud π](https://www.numerique.gouv.fr/services/cloud/cloud-interne/) sur les infrastructures du ministère de l'intérieur offrant des fonctionnalités DevSecOps à savoir : - - - [Gestionnaire de sources](docs/services/gitlab.md) applicatives - - Outil de gestion de la [qualité](docs/services/sonarqube.md) statique du code (SAST) et dynamique (DAST) - - Orchestrateur de [construction](docs/services/gitlab.md) d'artefacts (Intégration continue) - - [Entrepot d'artefacts](docs/services/artefacts.md) et d'images Docker - - Gestionnaire de [secrets](docs/services/vault.md) des chaines IC/DC - - Gestion des [secrets applicatifs](docs/guide/secrets-management.md) - - Outil de [déploiement automatisé](docs/services/gitops.md) des images Docker sur les infrastructures du ministère ou à l'extérieur du ministère en suivant les principes GitOps (Déploiement continue) - - Hébergement des [environnements](docs/guide/environments-management.md) applicatifs de l'intégration à la production - - Gestion des [équipes](docs/guide/team.md) - - Mise à disposition d'outil d'[observabilité et exploitabilité](docs/agreement/exploitation.md) des applications déployées sur l'offre : accès aux logs, métriques techniques et applicatives, procédures standard d'exploitation - -L'architecture générale de l'offre Cloud π Native est la suivante : - -![](docs/public/img/architecture.png) - -### SLA associés à l'offre Chaine DevSecOps secondaire - -L'offre Cloud π Native s'appuie sur l'hébergement Cloud du ministère. Les grands services ayant des contraintes de SLA différentes : - - - Le Cloud pour assurer le fonctionnement et la sécurisation de l'offre DevSecOps secondaire ( et le fonctionnement en production des application ) - - Outils de construction applicative (Intégration continue) permettant de construire un package applicatif à partir des sources - - Outils de déploiement (Déploiement continue) permettant de déployer / mettre à jour une application sur les différents environnements de l'offre - - Les applications qui sont déployées sur l'offre. Chacune de ces applications peut également avoir un niveau de criticité différent (par exemple l'environnement de production a un besoin de SLA plus fort que l'environnement de recette) - -| Service | DIMA* | PDMA** | -| ------------ | -------- | ------------------------------- | -| Construction | 8 heures | 24h (backup nocturne quotidien) | -| Déploiement | 8 heures | 24h (backup nocturne quotidien) | - -*DIMA : Durée d'interruption maximale autorisée (en heures ouvrés) -**PDMA : Perte de données maximale admissible (en heures ouvrés) - -Note : le SLA du cloud PI pour le fonctionnement en production des applications est de 99,9%, pour plus de détail, se référer aux CGU de l'offre d'hébergement Cloud PI. - -## Accompagnement (WIP) - -Un volet [accompagnement](docs/agreement/support.md) intial des projets directement par les équipes de l'offre Cloud π Native permet d'utiliser l'offre dans des conditions optimales. Cet accompagnement fait partie du parcours technique d'embarquement sur l'offre Cloud π Native. - -Elle s'articule dans une offre à 3 niveaux : - - Démarche autonome ( kit d'autoformation, tutoriels, etc... ) - - Démarche d'accompagnement à l'initialisation ( "Service Team" ) -- Formation et certification d'acteurs externes ( offre en cours d'élaboration ) - -Les ressources d'accompagnement étant limitées, l'embarquement est conditionné à des prérequis techniques et ou organisationnels [prérequis](docs/platform/compatibility.md) pour embarquer sur l'offre Cloud π Native de façon sereine et optimale. +## Contribuer -Typiquement l'équipe doit être dans un parcours de montée en compétence à l'agilité et à la conteneurisation/kubernetes. +L'offre Cloud π Native s'améliore grâce aux retours de nos utilisateurs, n'hésitez pas à contribuer, notamment en nous faisant des retours sur la documentation. Le détail pour contribuer est [ici](CONTRIBUTING.md) -## Embarquement technique +__Pour formater le code, veuillez à lancer la commande `pnpm run format` avant votre commit.__ -Un parcours technique d'apprentissage permettant de valider les prérequis et d'intégrer les bonnes pratiques permet à nos clients d'appréhender l'offre Cloud π Native. +### Documentation de l'offre de service Cloud π Native -![parcours_apprentissage](docs/public/img/learning-process.png) +Le dépôt est construit avec [vitepress](https://vitepress.dev) à l'aide de fichiers markdown positionnés dans les dossiers [cloud-pi-native](./cloud-pi-native/), les assets (images, fichiers additionnels, etc...) sont positionnés dans le dossier [public](./cloud-pi-native/public/). - - Etape 1 : [Matrice de compétences](docs/platform/skills-matrix.md) des technologies à connaitre pour utiliser l'offre Cloud π Native - - Etape 2 : Vérification de l'éligibilité de son application avec le modèle Cloud Native Application [prérequis](docs/platform/compatibility.md) technique liés à l'offre. Les équipes Cloud π Native [accompagnent](docs/agreement/support.md) les équipes projets sur cette étape afin d'apporter conseils et qualification des architectures et maturité technique des équipes. - - Etape 3 : Prise de connaissance des [bonnes pratiques](docs/guilde/best-practices.md) et expérimentation avec une série de tutoriels [tutoriels](docs/guide/tutorials.md) afin de faire ses premiers pas avec l'offre - - Etape 4 : [Embarquement](docs/guide/get-started.md) de l'application sur l'offre - - Etape 5 : Félicitation ! Vous êtes maintenant un utilisateur de la plateforme Cloud π Native et votre application peut passer en production via les principes d'[exploitation et observabilité](docs/agreement/exploitation.md) de vos projets. +Structure de la documentation : -A tout moment, vous pouvez consulter la [documentation détaillée](docs/platform/introduction.md) de la plateforme Cloud π Native, son architecture et les services proposés +```sh +./cloud-pi-native + ├── acceleration/ + ├── guide/ + ├── agreement/ + ├── best-practices/ + ├── certification/ + ├── faq/ + ├── public + │ ├── examples/ + │ ├── img/ + │ ├── favicon.ico + │ └── logo-marianne-gouvernement.png + ├── contribute.md + └── index.md +``` -Enfin notre [FAQ](docs/agreement/faq.md) permet de lister les questions fréquentes de nos clients, et des exemples pour réaliser des bouchons (S3, SMTP, ...) +### Documentation de la plateforme Hexaforge -## Notre roadmap (WIP) +Le dépôt est construit avec [vitepress](https://vitepress.dev) à l'aide de fichiers markdown positionnés dans le dossiers [hexaforge](./hexaforge/), les assets (images, fichiers additionnels, etc...) sont positionnés dans le dossier [public](./hexaforge/public/). -L'offre Cloud π Native est en cours de construction incrémentale. Notre [feuille de route détaillée](docs/platform/roadmap.md) est accessible permettant de donner de la visibilité sur les prochaines fonctionnalités. +Structure de la documentation : -Voici les grandes fonctionnalités prévus dans les prochaines semaines : - - Réduction de la quantité de code / manifest à produire; - - Automatisation des services d'infrastructure; - - et surtout, prise en compte des retours des primo-accédants. +```sh +./hexaforge + ├── administration/ + ├── guide/ + ├── installation/ + ├── platform/ + ├── public + │ ├── examples/ + │ └── img/ + ├── services/ + ├── contribute.md + └── index.md +``` ## Contact -Pour toute information ou demande pour rejoindre la betatest, veuillez nous contacter à l'adresse suivante : . - -Si vous souhaitez devenir primo accédant, beta testeurs ou avez des questions, veuillez nous contacter directement via le serveur Mattermost prévu à cet effet (si vous n'avez pas été ajouté au serveur Mattermost, veuillez contacter l'adresse mail précédente). - -## Contribuer - -L'offre Cloud π Native s'améliore grâce aux retours de nos utilisateurs, n'hésitez pas à contribuer, notamment en nous faisant des retours sur la documentation. Le détail pour contribuer est [ici](CONTRIBUTING.md) - -### Contribuer à la documentation - -Le dépôt est construit avec [vitepress](https://vitepress.dev) à l'aide de fichiers markdown positionné dans le dossier [docs](./docs/). -Les assets (images, fichiers additionnels, etc...) sont positionnés dans le dossier [public](./docs/public/). - -__Pour formater le code, veuillez à lancer la commande `pnpm run format` avant votre commit.__ - -Structure du dépôt : - -```sh -./docs -├── contribution/ -├── guide/ -├── installation/ -├── platform/ -├── public -│ ├── examples/ -│ ├── img/ -│ ├── favicon.ico -│ └── logo-marianne-gouvernement.png -├── agreement/ -├── services/ -└── index.md -``` +Pour toute information, veuillez nous contacter à l'adresse suivante : . diff --git a/cloud-pi-native/.vitepress/config.ts b/cloud-pi-native/.vitepress/config.ts new file mode 100644 index 0000000..dfa7a55 --- /dev/null +++ b/cloud-pi-native/.vitepress/config.ts @@ -0,0 +1,40 @@ +import { defineConfig } from 'vitepress' +import sidebar from './sidebar.json' assert { type: 'json'} + +export default defineConfig({ + base: '/', + lang: 'fr-FR', + title: 'Cloud π Native', + description: 'Documentation de la plateforme Cloud Pi Native', + cleanUrls: true, + themeConfig: { + logo: '/logo-marianne-gouvernement.png', + outline: [2, 3], + sidebar, + socialLinks: [ + { icon: 'github', link: 'https://github.com/cloud-pi-native/documentation' } + ], + search: { + provider: 'local', + options: { + translations: { + button: { + buttonText: 'Rechercher...', + buttonAriaLabel: 'Rechercher' + }, + modal: { + backButtonTitle: 'effacer la recherche', + displayDetails: 'afficher les détails', + noResultsText: 'Aucun résultat pour ', + resetButtonTitle: 'annuler la recherche', + footer: { + selectText: 'aller à ce texte', + navigateText: 'naviguer dans les résultats', + closeText: 'fermer' + } + } + }, + } + }, + }, +}) diff --git a/cloud-pi-native/.vitepress/sidebar.json b/cloud-pi-native/.vitepress/sidebar.json new file mode 100644 index 0000000..86e63a5 --- /dev/null +++ b/cloud-pi-native/.vitepress/sidebar.json @@ -0,0 +1,68 @@ +[ + { + "text": "Offre de services", + "collapsed": true, + "items": [ + { + "text": "Introduction", + "link": "/agreement/introduction" + }, + { + "text": "Accompagnement", + "link": "/agreement/support" + }, + { + "text": "Exploitation", + "link": "/agreement/exploitation" + }, + { + "text": "Observabilité", + "link": "/agreement/observability" + } + ] + }, + { + "text": "Certification", + "collapsed": true, + "items": [ + { + "text": "Introduction", + "link": "/certification/introduction" + } + ] + }, + { + "text": "Acceleration", + "collapsed": true, + "items": [ + { + "text": "Bouchons", + "link": "/acceleration/mocks" + } + ] + }, + { + "text": "Bonnes pratiques", + "collapsed": true, + "items": [ + { + "text": "Règles kyverno", + "link": "/best-practices/kyverno" + }, + { + "text": "Labels kubernetes", + "link": "/best-practices/labels-list" + } + ] + }, + { + "text": "F.A.Q", + "collapsed": true, + "items": [ + { + "text": "Introduction", + "link": "/faq/introduction" + } + ] + } +] diff --git a/cloud-pi-native/.vitepress/theme/index.ts b/cloud-pi-native/.vitepress/theme/index.ts new file mode 100644 index 0000000..c93cb0b --- /dev/null +++ b/cloud-pi-native/.vitepress/theme/index.ts @@ -0,0 +1,5 @@ +// https://vitepress.dev/guide/custom-theme +import DefaultTheme from 'vitepress/theme' +import './style.css' + +export default DefaultTheme diff --git a/cloud-pi-native/.vitepress/theme/style.css b/cloud-pi-native/.vitepress/theme/style.css new file mode 100644 index 0000000..de4f5dd --- /dev/null +++ b/cloud-pi-native/.vitepress/theme/style.css @@ -0,0 +1,100 @@ +/** + * Customize default theme styling by overriding CSS variables: + * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css + */ + +/** + * Colors + * -------------------------------------------------------------------------- */ + +:root { + --blue-france-sun-113: #000091; + --red-marianne-main-472: #e1000f; + + --vp-c-brand: var(--blue-france-sun-113); + --vp-c-brand-light: #6a6af4; + --vp-c-brand-lighter: #8585f6; + --vp-c-brand-lightest: #cacafb; + --vp-c-brand-dark: #313178; + --vp-c-brand-darker: #272747; + --vp-c-brand-dimm: rgba(33, 33, 63, 0.08); + +} + +/** + * Component: Button + * -------------------------------------------------------------------------- */ + +:root { + --vp-button-brand-border: var(--vp-c-brand-light); + --vp-button-brand-text: var(--vp-c-white); + --vp-button-brand-bg: var(--vp-c-brand); + --vp-button-brand-hover-border: var(--vp-c-brand-light); + --vp-button-brand-hover-text: var(--vp-c-white); + --vp-button-brand-hover-bg: var(--vp-c-brand-light); + --vp-button-brand-active-border: var(--vp-c-brand-light); + --vp-button-brand-active-text: var(--vp-c-white); + --vp-button-brand-active-bg: var(--vp-button-brand-bg); +} + +/** + * Component: Home + * -------------------------------------------------------------------------- */ + +:root { + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: -webkit-linear-gradient( + 120deg, + var(--vp-c-brand) 30%, + var(--red-marianne-main-472) + ); + + --vp-home-hero-image-background-image: linear-gradient( + -45deg, + var(--vp-c-brand) 50%, + var(--red-marianne-main-472) + ); + --vp-home-hero-image-filter: blur(40px); +} + +@media (min-width: 640px) { + :root { + --vp-home-hero-image-filter: blur(56px); + } +} + +@media (min-width: 960px) { + :root { + --vp-home-hero-image-filter: blur(72px); + } +} + +/** + * Component: Custom Block + * -------------------------------------------------------------------------- */ + +:root { + --vp-custom-block-tip-border: var(--vp-c-brand); + --vp-custom-block-tip-text: var(--vp-c-brand-darker); + --vp-custom-block-tip-bg: var(--vp-c-brand-dimm); +} + +.dark { + --vp-c-brand: #6a6af4; + --vp-custom-block-tip-border: var(--vp-c-brand); + --vp-custom-block-tip-text: var(--vp-c-brand-lightest); + --vp-custom-block-tip-bg: var(--vp-c-brand-dimm); + --vp-home-hero-name-background: -webkit-linear-gradient( + 120deg, + var(--vp-c-brand-light) 30%, + var(--red-marianne-main-472) + ); +} + +/** + * Component: Algolia + * -------------------------------------------------------------------------- */ + +.DocSearch { + --docsearch-primary-color: var(--vp-c-brand) !important; +} diff --git a/cloud-pi-native/acceleration/mocks.md b/cloud-pi-native/acceleration/mocks.md new file mode 100644 index 0000000..e353201 --- /dev/null +++ b/cloud-pi-native/acceleration/mocks.md @@ -0,0 +1,223 @@ +# Bouchons + +Un chart Helm a été créé afin de permettre aux projets clients de l'offre Cloud Pi Native de simuler ou remplacer les éléments fournis par l'infrastructure du MI à savoir : + +- Un serveur SMTP pour les envois de mails +- La création d'un bucket S3 +- Le SSO *Passage2* + +Le chart Helm est disponible sur le [repo github public](https://github.com/cloud-pi-native/helm-projects-mocks). + +## Utilisation + +Ces éléments sont à utiliser uniquement sur les environnements **Hors ministère de l'intérieur**, ainsi il est préférable de ne pas les ajouter dans le repo d'infra de l'application à déployer mais *à côté*. + +Ainsi, pour utiliser ce chart HELM, il faut, depuis la console DSO, ajouter un nouveau Dépôt sur un projet existant, choisir comme nom de repo "bouchon" et comme URL : et cocher la *case Dépôt d'infrastructure* : + +![Ajout du repo bouchon](/img/mocks/add-repo.png) + +Une fois le projet ajouté, il est présent sur gitlab et une nouvelle application est créée sur ArgoCD : + +![Ajout du repo bouchon](/img/mocks/mocks-argo.png) + +Aller dans App Details : +![Ajout du repo bouchon](/img/mocks/mocks-argo-app-details.png) +Modifier le cluster de destination (comme pour l'application) + +Puis aller sur l'onglet PARAMETERS: +![Ajout du repo bouchon](/img/mocks/mocks-argo-parameters.png) + +Cliquez en haut à droite sur le bouton EDIT et adapter le paramétrage en fonction de ses besoins. Voir le détail dans la description des bouchons dans les chapitres suivants. + +Le chart helm sur github contient un fichier *values.yaml* contenant l'ensemble des valeurs paramétrables et un second fichier *custom-values.yaml* contenant uniquement les valeurs importantes comme l'activation du S3 et du SMTP. Une fois le projet importé via la console, il est possible, en tant que projet de modifier le fichier custom-values.yaml directement depuis le gitlab DSO et éviter de modifier les paramètres depuis ArgoCD. Dans ce cas, il faut déclarer le fichier custom-values.yaml dans les paramètres ArgoCD. + +## Description des bouchons + +### Serveur SMTP + +Le chart Helm installe un serveur mailhog sur les ports 8025 (IHM Web) et 1025 (port SMTP). +La configuration s'effectue dans le fichier values.yaml dans la sous l'entrée racine "smtp" + +Voici la configuration par defaut présente dans le fichier values.yaml du chart +```yaml +smtp: + # Active ou non l'installation du serveur SMTP + enabled: true + # Référence vers l'image mailhog sur docker.io + image: + repository: docker.io/mailhog/mailhog + tag: v1.0.1 + pullPolicy: IfNotPresent + + nameOverride: "" + fullnameOverride: "" + + containerPort: + http: + name: http + port: 8025 + smtp: + name: tcp-smtp + port: 1025 + + service: + annotations: {} + # Named target ports are not supported by GCE health checks, so when deploying on GKE + # and exposing it via GCE ingress, the health checks fail and the load balancer returns a 502. + namedTargetPort: true + port: + http: 8025 + smtp: 1025 + + ingress: + enabled: true + # ingressClassName: nginx + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + labels: {} + # hostOverride: mailhog.example.com + + auth: + enabled: true + existingSecret: "" + fileName: auth.txt + fileContents: Ym9iOiQyYSQwNCRRN1VwdmQvWUlwck5DcExsUHpFQ2VlRnZrVlI1RVhKbG1uZjZ4S050ZHlXSnJoeW1hNUhlaQ== # format user:password (où password est bcrypted) le tout en base64 + + # JSON file defining outgoing SMTP servers + outgoingSMTP: + enabled: false + existingSecret: "" + fileName: outgoing-smtp.json + fileContents: {} + # See https://github.com/mailhog/MailHog/blob/master/docs/CONFIG#outgoing-smtp-configuration + # Only name, host and port are required. + # + # server_name1: + # name: "server_name1" + # host: "mail.example.com" + # port: "25" # NOTE: go requires this port number to be a string... otherwise the container won't start + # email: "" + # username: "" + # password: "" + # mechanism: "PLAIN|CRAM-MD5" + # server_name2: + # name: "server_name2" + # host: "mail2.example.com" + # port: "587" # NOTE: go requires this port number to be a string... otherwise the container won't start + + podReplicas: 1 + + podAnnotations: {} + + podLabels: + app: bouchon-smtp + env: ovh + tier: bouchon + criticality: low + component: smtp + + extraEnv: [] + + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/#configure-probes + livenessProbe: + initialDelaySeconds: 10 + timeoutSeconds: 1 + + resources: + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + limits: + cpu: 100m + memory: 64Mi + requests: + cpu: 100m + memory: 64Mi +``` + +### Bucket S3 + +Le chart permet également de créer un bucket de stockage objet S3 via MinIO. + +```yaml +minio: + enabled: true # Activation de minIO + ingress: + enabled: true # Activation de l'ingress pour l'IHM + hostname: minio-st.dso.numerique-interieur.com # Hostname de l'IHM à adapter par projet + defaultBuckets: "my-bucket-app, my-second-bucket" # Nom de bucket par defaut +``` + +Le chart dans cette configuration va créer sur le namespace : + - 2 buckets S3 nommés my-bucket-app et my-second-bucket + - Un secret contenant 2 clés **root-password** et **root-user** pour se connecter à l'IHM permettant d'administrer minIO (création de bucket de 'AK/SK). + +Pour utiliser MinIO sur un pod, il faut créer et injecter la configuration via configMap ou Secret : + +```yaml +# [...] +containers: + # [...] + envFrom: + - configMapRef: + name: cm-name + - secretRef: + name: secret-name +# [...] +``` + +### Passage2 + +Le chart permet d'activer un bouchon Passage2 permettant de simulé le mécanisme d'authentification SSO du ministère de l'intérieur. + +Le mécanisme du bouchon d'authentification repose sur un **Reverse proxy** authentifiant et d'un keycloak en SAML ajoutant au requete entrante des headers contenant les roles/groups de l'utilisateur authentifié. + +**Le reverse proxy authentificant devra intercepter l'ensemble des requetes necessitant une authentifiation** + +Le chart permet d'ajouter les composants nécessaire à la mise en place de ce bouchon. + +```yaml +passage2: + # Active ou non le bouchon + enabled: true + reverseproxy: + # Url de l'ingress du reverse proxy authentifiant + hostname: mellon.example.com + proxy: + # Valeur des headers ajouté par MELLON + headers: |- + #Ajout de header Mellon-NameID avec le nom de l'utilisateur connecté + RequestHeader set Mellon-NameID %{MELLON_NAME_ID}e + Header set Mellon-NameID %{MELLON_NAME_ID}e + + #Ajout de header Mellon-Groups avec les groupes de l'utilisateur connecté + RequestHeader set Mellon-Groups %{MELLON_groups}e + Header set Mellon-Groups %{MELLON_groups}e + + #Ajout de header Mellon-Role avec les roles de l'utilisateur connecté + RequestHeader set Mellon-Role %{MELLON_Role}e + Header set Mellon-Role %{MELLON_Role}e + + rules: |- + # Exemple de redirection vers différents services applicatifs base sur le suffix, il est possible d'utiliser les différentes directive apache + ProxyPassMatch "^/(.*)" "http://whoami-svc:8080/$1" + ProxyPassReverse "^/(.*)" "http://whoami-svc:8080/$1" + # il est possible d'avoir plusieur service de redirection + ProxyPass /my-service2 "http://whoami3-svc:80" + ProxyPassReverse /my-service2 "http://whoami3-svc:80" + + mockpassage2: + # Url d'accès au keycloak pour la gestion des utilisateurs/droits + hostname: passage2.example.com + # Login du user admin + adminLogin: admin + # Password du user admin + adminPassword: OZJFejfrejijIZJijfeij +``` + +Il faudra configuré le RPA pour renvoyer vers vos service applicatifs en modifiant le bloc **rules** afin que celui-ci rajoute les headers. +Une fois les composants déployé, l'authentification se fera par keycloak, un compte utilisateur d'exemple est crée test/test, avec aucun roles ou groupes. + +Dans le cas ou l'utilisateur possède plusieurs roles/groupes ceux-ci seront sépéraré par une **,** diff --git a/cloud-pi-native/agreement/exploitation.md b/cloud-pi-native/agreement/exploitation.md new file mode 100644 index 0000000..fef281e --- /dev/null +++ b/cloud-pi-native/agreement/exploitation.md @@ -0,0 +1,42 @@ +# Exploitation de l'offre + +L'offre Cloud π Native permet *in fine* de déployer des applications. Le volet observabilité et exploitabilité est présent dans l'offre et regroupe les éléments tels que : + - Accès aux logs applicatives + - Accès aux métriques de consommation de ressources des applications + - Ajout de métriques d'observabilité + - Procédures standards pour les opérations usuelles comme la sauvegarde et restauration, PRA, chargement des données. + +## SLA de la plateforme + +L'offre Cloud π Native s'appuie sur l'hébergement Cloud du ministère. Les grands services ayant des contraintes de SLA différentes : + + - Le Cloud pour assurer le fonctionnement et la sécurisation de l'offre DevSecOps secondaire ( et le fonctionnement en production des application ) + - Outils de construction applicative (Intégration continue) permettant de construire un package applicatif à partir des sources + - Outils de déploiement (Déploiement continue) permettant de déployer / mettre à jour une application sur les différents environnements de l'offre + - Les applications qui sont déployées sur l'offre. Chacune de ces applications peut également avoir un niveau de criticité différent (par exemple l'environnement de production a un besoin de SLA plus fort que l'environnement de recette) + +| Service | DIMA* | PDMA** | +| ------------ | -------- | ------------------------------- | +| Construction | 8 heures | 24h (backup nocturne quotidien) | +| Déploiement | 8 heures | 24h (backup nocturne quotidien) | + +*DIMA : Durée d'interruption maximale autorisée (en heures ouvrés) +**PDMA : Perte de données maximale admissible (en heures ouvrés) + +Note : le SLA du cloud PI pour le fonctionnement en production des applications est de 99,9%, pour plus de détail, se référer aux CGU de l'offre d'hébergement Cloud PI. + +## Exploitabilité + +:construction: *Disponible prochainement* :construction: + +### Accès aux logs + +:construction: *Disponible prochainement* :construction: + +### Accès aux métriques + +:construction: *Disponible prochainement* :construction: + +### Sauvegarde et restauration + +:construction: *Disponible prochainement* :construction: diff --git a/cloud-pi-native/agreement/introduction.md b/cloud-pi-native/agreement/introduction.md new file mode 100644 index 0000000..dfcf599 --- /dev/null +++ b/cloud-pi-native/agreement/introduction.md @@ -0,0 +1,83 @@ +# L'offre Cloud Pi Native + +La direction de la transformation numérique du ministère de l'Intérieur et des outre-mer propose une offre de services autour de deux instances de la plateforme *(OVH SecNumCloud / Cloud π)* à destination des *administrations* ou des *entreprises de services numériques* travaillant pour leur compte. +Cette offre de services est une implémentation du produit *Hexaforge* pour le ministère de l'intérieur ainsi qu'un accompagnement dédié aux spécificités des infrastructures ministérielles. + +> __:warning: Attention, les seuls bénéficiaires de cette offre managée sont les administrations ou leurs ESN partenaires. + +Vous pouvez consulter [la documentation détaillée](https://github.com/cloud-pi-native/embarquement-autoformation) du processus d'embarquement sur cette offre. + +**Votre point de contact** : dtnum-brm-contacts@interieur.gouv.fr + +## Introduction + +Avec l’adoption de la doctrine « Cloud au centre », le gouvernement français fait du Cloud un prérequis pour tout nouveau projet numérique au sein de l’État ou refonte substantielle de l’architecture applicative existante. + +**Objectif** : Accélérer la transformation numérique au bénéfice des usagers et dans le strict respect de la cybersécurité et de la protection des données des citoyens et des entreprises. + +L'offre *interministérielle* Cloud π Native, offre les services d'une plateforme *DevSecOps* complète afin de suivre le cycle de vie complet de son projet. +La philosophie de l'offre est de créer une chaîne collaborative étendue entre l'équipe de développement et l'hébergement, qui s'appuient sur : +* Un socle d'intégration à la main des développeurs, appelé chaine primaire. +* Un service côté infrastructure étatique effectuant la recompilation du code et l'automatisation des déploiement, appelé chaîne secondaire. + +La chaîne secondaire a également la charge de mesurer la qualité du code et la conduite d'audits automatisés à chaque build/déploiement contribuant à l'homologation en continu de l'application. + +L'usage de standards industriels largement distribués tel que kubernetes, Gitops et la sécabilité de l'offre, permettent un transfert facilité depuis et vers d'autres solutions d'hébergement kubernetes telles que les Clouds Publics. + +Lorsque que l'équipe projet est prête avec une première base de code fonctionnelle, il est possible de l'intégrer sur l'offre Cloud π Native. + +Vous trouverez le détail de cette offre [ici](https://cloud-pi-native.fr/platform/introduction.html) + +Le cadre interministériel d'utilisaton de l'offre est disponible à l'emplacement suivant : + +Dés que les [prérequis](https://cloud-pi-native.fr/agreement/support.html) sont présents, la souscription à l'offre Cloud π Native est possible en suivant les étapes suivantes : + - Contacter l’adresse suivante pour faire une demande: dtnum-brm-contacts@interieur.gouv.fr + - Après acceptation de la demande, l'équipe [Accompagnement](https://cloud-pi-native.fr/agreement/introduction.html#accompagnement) prendra contact avec vous pour la phase d'accompagnement. + +Enfin, le déploiement s'effectue sur différentes cibles d'hébergement possibles : + +**Vision d'ensemble de l'offre de services:** + +![vision](/img/global-vision.png) + +Comme mentionné dans le schèma, l'offre de services comprend si vous le souhaitez l'infrastructure hébergeant vos applicatifs. +Cette infrastructure peut-être : + - Un socle Kubernetes/Openshift mutualisé dans la zone "Non Protégé" (NP) du ministère de l'Intérieur. + - Un socle Kubernetes/Openshift dédié dans la zone "Non Protégé" (NP) ou la zone "Diffusion Restreinte (DR) du ministère de l'intérieur. + - Un socle Kubernetes directement gérés par l'équipe projet. + +Le choix de la cible est au cas par cas et fait lors des premières phases d'échange. + +## Accompagnement + +Comme mentionné plus haut, à la souscription de l'offre Cloud π Native, une équipe accompagnement sera le vis-à-vis du projet et assurera : +- Un [accompagnement](/agreement/support) rapproché aux projets pour que l'utilisation de l'offre se réalise dans des conditions optimales. +- Le parcours technique d'embarquement sur l'offre Cloud π Native qui s'articule sur trois niveaux : + * Démarche autonome (Kit d'autoformation, tutoriels, etc. ) + * Démarche d'accompagnement à l'initialisation ( "Service Team" ) + * Formation et certification d'acteurs externes + +Les ressources d'accompagnement étant limitées, l'embarquement est conditionné à des prérequis techniques et ou organisationnels [prérequis](/platform/compatibility) pour embarquer sur l'offre Cloud π Native de façon sereine et optimale. + +Typiquement, l'équipe doit être dans un parcours de montée en compétences à l'agilité et à la conteneurisation/Kubernetes. + +## Embarquement technique + +Un parcours technique d'apprentissage permettant de valider les prérequis et d'intégrer les bonnes pratiques permet à nos clients d'appréhender l'offre Cloud π Native. + +![parcours_apprentissage](/img/learning-process.png) + +- Étape 1 : [Matrice de compétences](/platform/skills-matrix) Des technologies à connaître pour utiliser l'offre Cloud π Native +- Étape 2 : vérification de l'éligibilité de son application avec le modèle Cloud Native Application [prérequis](/platform/compatibility) technique liée à l'offre. Les équipes Cloud π Native [accompagnent](/agreement/support) les équipes projets sur cette étape afin d'apporter conseils et qualification des architectures et maturité technique des équipes. +- Étape 3 : prise de connaissance des [bonnes pratiques](/guide/best-practices) et expérimentation avec une série de tutoriels [tutoriels](/guide/tutorials) afin de faire ses premiers pas avec l'offre +- Étape 4 : [Embarquement](/guide/get-started) de l'application sur l'offre +- Étape 5 : félicitations ! Vous êtes maintenant un utilisateur de la plateforme Cloud π Native et votre application peut passer en production via les principes d'[exploitation et observabilité](/agreement/exploitation) de vos projets. + +À tout moment, vous pouvez consulter la [documentation détaillée](/platform/introduction) de la plateforme Cloud π Native, son architecture et les services proposés. + +Enfin notre [FAQ](/agreement/faq) permet de lister les questions fréquentes de nos clients, et des exemples pour réaliser des bouchons (S3, SMTP, ...). + +## Contact + +Pour toute information ou demande, veuillez nous contacter à l'adresse suivante : . Nous vous recontacterons au plus vite dès la réception du mail. +Si vous faites déjà parti des beta testeurs et que vous souhaitez poser des questions ou avoir de l'accompagnement, veuillez nous contacter directement via le serveur Mattermost prévu à cet effet (si vous n'avez pas été ajouté au serveur Mattermost, veuillez contacter l'adresse mail précédente). diff --git a/cloud-pi-native/agreement/observability.md b/cloud-pi-native/agreement/observability.md new file mode 100644 index 0000000..1b621eb --- /dev/null +++ b/cloud-pi-native/agreement/observability.md @@ -0,0 +1,41 @@ +# Observabilité + +> __:warning: L'observabilité n'est pas en place sur les environnements OVH.__ + +Dans le cadre de l'offre Cloud-Pi Native, l'observabilité est disponible via plusieurs composants: +- Prometheus/Grafana pour les métriques +- AlertManager/Grafana pour l'alerting +- ElasticSearch/Kibana pour les logs + +Ces différents services sont accessibles via la console `Cloud Pi Native > Projet > Mes Projets > Sélectionner un projet > Mes Services` + +![observabilité](/img/agreement/acces_services_observabilité.png) + +## Métrique +[Prometheus](https://grafana.com/products/cloud/metrics/) est utilisé pour récupérer, stocker et visualiser (via [Grafana](https://grafana.com/grafana/)) les métriques d'infrastructure ainsi qu'applicative. + +> __:warning: Les métriques sont disponibles pendant un an sur les environnements de production et quelques mois pour les environnements hors production.__ + +Pour apprendre à utiliser ce service, [cliquer ici](/guide/metrics) + +## Alerting +[AlertManager](https://grafana.com/docs/grafana/latest/alerting/fundamentals/alertmanager/) est utilisé pour gérer les différentes alertes de vos projets. + +Par défaut, aucune alerte n'est mise en place. + +Pour apprendre à créer une alerte, [cliquer ici](/guide/alerting.md) + +## Logs +Le couple Elastisearch/Kibana est utilisé pour vous donner accès à vos logs. + +> __:warning: Les logs ne sont conservés que sur une durée de 7 jours.__ + +Pour les besoins de conservation au delà de 7 jours, le projet doit mettre en place un collecteur de logs (rsyslog, fluentbit, fluentd, vector, kafka, ...) dans le périmètre de son application afin de récupérer le flux de logs et les stockés sur un autre support (S3 par exemple) + +Les logs peuvent être transmises via le protocol HTTP, syslog ou vers un kafka. + +Pour bénéficier de ce service, merci de créer un ticket auprès de la ServiceTeam. + +Pour apprendre à utiliser kibana, [cliquer ici](/guide/logs-kibana.md) + +Un exemple de mise en place d'un collecteur de log avec le produit [vector](https://vector.dev/) vers un bucket AWS S3 est disponible [ici](/guide/archive-logs.md) diff --git a/cloud-pi-native/agreement/support.md b/cloud-pi-native/agreement/support.md new file mode 100644 index 0000000..352eb4f --- /dev/null +++ b/cloud-pi-native/agreement/support.md @@ -0,0 +1,77 @@ +# Processus accompagnement Service Team + +## Introduction + +La Service Team est l'équipe qui vous accompagne pour embarquer sur l'offre Cloud π native. Cet accompagnement a pour objectif d'__aider les projets, les faire monter en compétences mais de ne pas faire à leur place__. En effet, une fois que les projets sont déployés sur l'offre Cloud π native, l'exploitation, le MCO/MCS reste de la responsabilité du projet qui doit comprendre l'esprit de la plateforme, les technologies sous jacentes et les paradigmes de déploiement. L'offre Cloud π native favorise le modéle DevSecOps ** ou Build it, You Run it** + +L'accompagnement technique se fera sur 2 plateformes : + +- Plateforme d'accélération OVH; plateforme non liée aux réseaux interministères et a pour objectif de fournir aux projets un accès plus rapide à la console et aux services Cloud π native. Ainsi les projets peuvent anticiper en effectuant leurs premiers tests. + +- Cluster Cloud π native sur les infrastructures du ministère de l'intérieur + +## Prérequis organisationnels + +Avant d'utiliser l'offre Cloud π native, il est nécessaire : +- De suivre le processus d'accompagnement [haut niveau](https://github.com/cloud-pi-native/embarquement-autoformation) + +## Prérequis techniques + +En plus de ces prérequis, les éléments suivants sont à fournir par le projet : +- Vérifier que les [prérequis techniques](/platform/compatibility) ainsi que [les bonnes pratiques](/guide/best-practices) sont bien en place +- Vérifier que la [matrice de compétences](/platform/skills-matrix) est connue +- Exigences du [Cadre de Cohérence Technique](https://github.com/cloud-pi-native/cct-cloud-native) +- Vérifier les contraintes de nom DNS : les applications doivent-elles obligatoirement être en *.gouv.fr ou *.interieur.gouv.fr ? +- Dossier d'architecture ou à minima schéma d'architecture technique : nombre de composants, technologies, maturité sur les technologies DSO, notamment docker / kubernetes / openshift / déploiement ArgoCD (gitops), backend de stockage (postgres, S3, etc.) +- Elements de volumétrie en termes de données et d'utilisateurs +- Si une reprise de données est à prévoir et la volumétrie associée +- Processus de sauvegarde et restauration demandé et/ou prévues par l'application +- Procédure de création de la base de données (portée par l'application / manuel) +- Liste des composants externes au projet et appelés par l'application pour évaluer les ouvertures de flux: + - Internes MI / RIE + - Sur Internet +- Exposition de l'application (Internet/Intranet/RIE/DR/NP) +- Nombre d'environnements prévus +- Nom de domaine et certificats à fournir par environnement +- Estimation des ressources nécessaires CPU/RAM +- Calendrier du projet et échéances importantes et état d'avancement du projet (déjà en production, nouvelle application, etc.) + +## Accompagnement sur OVH + +- Création de compte pour l'accès à la console et aux services +- Accostage entre la chaine primaire et la chaine secondaire (github action) +- Contruction des images Docker +- Prise en main de la console : + - Intégration des projets applicatifs et construction de la chaine de construction sur DSO (gitlab-ci-dso) + - Intégration des repos d'infra et intégation sur ArgoCD + - Accès aux éléments de monitoring + +## Accompagnement sur Cloud π + +Identique à l'accompagnement sur OVH plus : +- Ouverture de flux +- Adaptation des triggers de déploiement sur l'environnement Cloud π native + +## Outils de communication + +Pour contacter la Service Team, plusieurs moyens sont mis en place : +- Un outil de ticketing (moyen privilégié car permet de tracer les demandes) +- Un outil de discussion en ligne: Mattermost + +## Ticketing + +Pour une meilleure traçabilité des échanges, nous avons mis en place un outil de ticketing permettant aux projets de faire des demandes ou de remonter des incidents à la Service Team. + +- Voici le lien pour s'y rendre: . + +## Mattermost + +Pour une meilleure fluidité des échanges, nous avons également mis en place un tchat dont voici l'[URL](https://mattermost.fabrique-numerique.fr/) + +## Le processus d'embarquement + +Le processus d'embarquement classique d'un projet est présenté ci-dessous : + +![processus embarquement](/img/onboarding-process.png) + +> A chaque étape, la vérification des prérequis est un point d'étape *obligatoire* permettant de valider la compatibilité du projet avec l'offre DSO. diff --git a/cloud-pi-native/best-practices/kyverno.md b/cloud-pi-native/best-practices/kyverno.md new file mode 100644 index 0000000..bca636c --- /dev/null +++ b/cloud-pi-native/best-practices/kyverno.md @@ -0,0 +1,34 @@ +# Règles Kyverno appliquées aux clusters + +Kyverno est un moteur de politiques conçu pour Kubernetes. + +Ces politiques peuvent valider, muter, générer et nettoyer les ressources Kubernetes, ainsi que vérifier les signatures d'images et les artefacts pour aider à sécuriser la chaîne d'approvisionnement des logiciels. + +Dans le cadre de l'offre de services du MIOM, les règles suivantes sont appliquées sur les clusters que nous opérons : + +| Kyverno Rules | ValidationFailure Action (Dev, preprod) | ValidationFailure Action (Prod) | Information importantes | Severité | Type | description | +| -------------------------- | --------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------- | -------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| add-velero-label | | | |low | Backup | Ajoute une étiquette sur le namespace pour être sauvegardé par Velero | +| add-netpol-allowsame-ns | | | | low | Multi-Tenancy, NetworkPolicy | Autorise le pod à communiquer dans le même namespace | +| add-netpol-deny | | | | low | Multi-Tenancy, NetworkPolicy | Refuse toute communication entrante vers les pods dans un namespace | +| add-netpol-ingress | | | | low | Multi-Tenancy, NetworkPolicy | Autorise la communication entrante depuis le namespace openshift-ingress vers tous les pods dans un nouveau namespace créé | +| add-netpol-logging | | | | low | Multi-Tenancy, NetworkPolicy | Autorise la communication entrante depuis le namespace openshift-logging vers tous les pods dans un nouveau namespace créé | +| add-ttl | | | | medium | Best Practices | Ajoute un time to live (TTL) aux JOB dans le cluster, ce qui les conduit à être automatiquement nettoyés après une certaine période de temps | +| check-labels | AUDIT | ENFORCE | Labels requis : app, env, tier | low | Best Practices | Cette règle garantit que toutes les ressources ont les étiquettes nécessaires appliquées aux pod | +| cm-no-credentials | AUDIT | ENFORCE | data non autorisée : password, passwd, secret_key | medium | Pod Security Standards (Baseline) | Empêche le stockage des informations d'identification dans les ConfigMaps, ce qui est une mauvaise pratique d'un point de vue sécurité | +| disallow-exec | ENFORCE | ENFORCE | | high | Pod Security Standards (Baseline) | Empêche l'utilisation de la commande "exec" sur le namespace openshift-etcd pour des raisons de sécurité | +| disallow-latest | AUDIT | ENFORCE | | medium | Pod Security Standards (Baseline) | Les Pods n'utilisent pas la balise 'latest' pour leurs images, encourageant l'utilisation de balises versionnées spécifiques | +| disallow-hostpath | AUDIT | ENFORCE | | high | Pod Security Standards (Baseline) | Empêche l'utilisation des volumes hostPath, qui peuvent être un risque de sécurité s'ils ne sont pas correctement contrôlés | +| disallow-selfprovisionning | AUDIT | ENFORCE | | high | Pod Security Standards (Baseline) | Empêche la liaison au rôle de self-provisionners pour un contrôle strict de la création de projet OpenShift | +| etcd | ENFORCE | ENFORCE | | high | Pod Security Standards (Baseline) | Assure que le chiffrement est activé pour etcd dans les clusters OpenShift | +| limit-size-pvc | AUDIT | ENFORCE | pvc < 1Ti | low | Best Practices | Limite la taille des revendications de volume persistant (PVC) pour éviter l'utilisation excessive des ressources de stockage | +| need-containers-ressources | AUDIT | ENFORCE | limits.memory, limits.cpu, request.memory et request.cpu | medium | Best Practices | Assure que les demandes de ressources et les limites sont définies pour tous les Pods, pour assurer une utilisation équitable des ressources | +| restrict-image-registry | AUDIT | ENFORCE | registres autorisés : docker.io/, harbor.io/, registry.redhat.io/, quay.io/, bitnami/, ghcr.io/ | medium | Pod Security Standards (Baseline) | Restreint les registres d'images à partir desquels les conteneurs peuvent tirer des images, comme mesure de sécurité pour assurer l'utilisation d'images de confiance uniquement | +| restrict-nodeport | AUDIT | ENFORCE | | medium | Pod Security Standards (Baseline) | Restreint l'utilisation des services NodePort, qui peuvent exposer des services à l'extérieur du cluster et représenter un risque de sécurité potentiel | <<>> | +| need-liveness-readiness | AUDIT | ENFORCE | | medium | Best Practices | Assure que tous les conteneurs ont l'une des trois sondes (Liveness, Readiness ou Startup), pour s'assurer qu'ils signalent correctement leur statut à Openshift | +| job-history | AUDIT | ENFORCE | | low | Best Practices | Cronjob: ajoute les propriétés `successfulJobsHistoryLimit: 5` et `failedJobsHistoryLimit: 5` | + +Explication de la difference entre ENFORCE et AUDIT : +- Enforce : Kyverno bloquera l'action (par exemple, la création, la mise à jour ou la suppression d'une ressource) si la politique n'est pas respectée. Cela garantit que toutes les ressources du cluster respectent les politiques mises en place. + +- Audit: Une action d'Audit ne bloquera pas une action si la politique n'est pas respectée, mais elle enregistrera l'infraction dans les résultats d'audit de Kyverno. C'est utile pour observer les infractions aux politiques sans bloquer les actions, ce qui peut être particulièrement utile dans les environnements de développement ou de test. diff --git a/cloud-pi-native/best-practices/labels-list.md b/cloud-pi-native/best-practices/labels-list.md new file mode 100644 index 0000000..cae4463 --- /dev/null +++ b/cloud-pi-native/best-practices/labels-list.md @@ -0,0 +1,77 @@ +# Labélisation des ressources kubernetes + +Dans le cadre de l'offre de services du MIOM, il sera demandé d'ajouter les labels suivants sur vos ressources kubernetes : + +## Type d'environnement + +Ajouter un label `env: ` où `element` est un élément de la liste suivante : + +- dev +- formation +- qualif +- test +- preprod +- prod + +## Tiers + +Ajouter un label `tier: ` où `element` est un élément de la liste suivante : + +- frontend +- backend +- db +- cache +- auth + +## Criticité + +Ajouter un label `criticality: ` où `element` est un élément de la liste suivante : + +- high +- medium +- low + +## Composant + +Ajouter un label `component: ` où `element` est un élément de la liste suivante : + +- web : + - nginx + - apache + - caddy + - tomcat + +- defaults : + - python + - node + - openjdk + - golang + - php + - ruby + - perl + - drupal + - java + +- database : + - postgres + - mariadb + - mysql + - mongo + - cassandra + - cockroach + - influx + - etcd + +- caching : + - varnish + - redis + - memcached + +- broker : + - rabbitmq + - kafka + - apachemq + - kubemq + +- others : + - busybox diff --git a/cloud-pi-native/certification/introduction.md b/cloud-pi-native/certification/introduction.md new file mode 100644 index 0000000..bde4ca0 --- /dev/null +++ b/cloud-pi-native/certification/introduction.md @@ -0,0 +1,114 @@ +# Certification Cloud Pi Native (work-in-progress) + +L'effet recherché de Cloud Pi Native est de : produire des applications de qualité qui répondent au besoin, en soutenant l'agilité, la culture et les principes visant l'autonomie et centrés sur l'usage. + +Plusieurs populations sont visées par le produit Cloud Pi Native et la doctrine Cloud au Centre : + * les **équipes intégrées** qui utilisent le produit Cloud Pi Native au quotidien + * comprendre le cadre d'autonomie, les opportunités et contraintes de Cloud Pi Native, apportés par l'utilisation de Cloud Pi Native & le Cadre de Cohérence Technique Intermistériel + * être sensibilisé aux références du Software CraftSmanship + * connaitre l'éco-systeme kubernetes + * les **"DevSecOps/SRE/Champions/enabling team"** (terme à définir) au service de ou des équipes intégrées, qui accompagnent, coachent, supervisent leurs pratiques DevSecOps et Cloud Native + * Mettre les équipes intégrées dans un cycle d'amélioration continue des projets + * Être orienté sur le partage et la montée en compétence collective + * mettre en place la culture de l'excellence et les pratiques DevSecOps au sein des équipes intégrées + * assurer le provisionnement des infrastructures et pipeline, le flux et la stabilité de la solution + * démontrer sa maitrise sur des prérequis techniques d'intégration et d'exploitabilité d'application + * les **concepteurs d'application** cloud native (opportunité k8s, vs organique qui le maintiendra) +Ce programme de certification soutient l'effet recherché et s'adresse aux experts en charge d'accompagner, de coacher et de superviser les pratiques DevSecOps et Cloud Native ("DevSecOps/SRE/Champions/enabling team") au service des équipes intégrées en charge de la réalisation de produits numériques. + +**Les compétences et savoir-faires attendus** +Pour les équipes intégrées + * comprendre le cadre d'autonomie, les opportunités et contraintes de Cloud Pi Native, apportés par l'utilisation de Cloud Pi Native & le Cadre de Cohérence Technique Intermistériel + * être sensibiliser aux références du Software CraftSmanship + * connaitre l'éco-systeme kubernetes + +Pour les "DevSecOps/SRE/Champions/enabling team" +* Mettre les équipes intégrées dans une cycle d'amélioration continue des projets +* Être orienté sur le partage et la montée en compétence collective +* s'assurer de la +* mettre en place la culture de l'excellence et les pratiques DevSecOps au sein des équipes intégrées +* assurer le provisionnement des infrastructures et pipeline, le flux et la stabilité de la solution +* démontrer sa maitrise sur des prérequis techniques d'intégration et d'exploitabilité d'application + +**Les modalités de certification** +Prérequis : +* la certification est soumise à un prérequis d'obtention de la Certified Kubernetes Application Developer de la Linux Foundation, permettant de garantir la bonne maitrise de kubernetes en tant que développeur + +Promotion : +* Des promotions de 20 personnes sont organisées 2 à 3 fois par an par Cloud Pi Native. Veuillez contacter cloudpinative-relations@interieur.gouv.fr pour enregistrer votre candidature. + +Type d'examen : +* l'examen est réalisé en présentiel sur Paris, à ce jour. +* La durée de l'examen varie entre 2 & 4 heures +* Le passage d'examen et la certification sont individuels, sous la supervision d'un représentant Cloud Pi Native +* L'examen est composé de 2 volets : + * technique : des mises en situation et lab seront soumis. + * culture générale & process : un questionnaire sera soumis, permettant de vérifier votre bonne compréhension des processus clés et des normes à prendre en compte lors du cycle de vie du projet et de l'application + Chaque lab réalisé avec succès et réponse exacte octroient des points. + +Condition d'obtention : +* un score minumum de 80% est nécessaire pour l'obtention de la certification Cloud Pi Native - "DevSecOps/SRE/Champions/enabling team" (nom à définir) + +------------- + +Le matériel pédagogique proposé en open-source permet simultanément de former les experts et également ainsi que leurs fournir des outils permettant d'aider à définir le plan d'accompagnement et de formation des équipes *enabling*. + +L'évaluation prend en charge la compétence nécessaire à soutenir l'usage de l'offre Cloud native et l'agilité mais ne couvre pas le cadre méthodologique ou les certifications techniques tel que kubernetes, helm, argoCG, etc... ce sont de. + +La certification "Cloud Pi Native" est remise par le ministère de l'Intérieur ou via les entités qui ont reçus l'acréditation pour le faire. La certification est remise sous la forme d'un mail et d'un badge numérique. +Elle est pour l'instant valable pour un an. + +Si vous êtes intéressé, avez des questions et/ou suggestion, contactez-nous à: + + +**Dans ce repository vous trouverez un article qui présente l'ensemble des compétences requises:** + +- Les fondamentaux à connaitre pour mettre en oeuvre et maintenir dans le temps des applications de qualité qui répondent aux besoins; +- mettre en place l'amélioration continue et le refactoring; +- softskill et approche pour accompagner les les équipes de développement; +- connaissance du CCT Cloud Pi native et des exigences applicables; +- compréhension de l'offre de service Cloud Pi Native et le parcours de contractualisation; +- compréhension et utilisation de la chaine de construction applicative; +- comment contribuer à l'offre pull request et faire un feedback. + +Ce repository référence les capacités et messages clés à transmettre mais ne référence par les contenus détaillés. +Les experts se forment avec les programmes de leur choix, ils doivent juste être connaissant ou compétent sur les thèmes cités. + +A toutes fin utiles : une base de connaissance et d'embarquement en open-source "Cloud Native" est disponible sur : . C'est également une aide pour monter des parcours. + +**Les messages clés, le contexte et la vision:** + +Cloud Pi Native est un programme d'ensemble du ministère de l'Intérieur et des Outres-mer pour produire un numérique de qualité, soutenable dans la durée au coup de possession optimisé et qui répond au besoin. +L'objectif visé est de soutenir la production de produits logiciels de qualité, en réduisant la xharge de travail de l'équipe pour le construire, facilement évolutif et maintenable dans le temps avec un coût de possession optimisé tout en répondant au besoin en ce centrant sur l'usager. + +Ce qui est structurant : l'utilisation exclusive de Kubernetes pour l'orchestration de conteuneurs,le modèle opérationnel "you built it, you run it" et la mise en disposition en open-source de l'ensemble des ressources sauf portion sensible. + +L'hébergement du service peut-être effectué soit via l'offre interministériel Cloud Pi, soit sur un cloud public si le niveau de sensbilité des données le permet ainsi que l'absence de conflit de normes juridiques entre les CGU de l'hébergeur avec les réglementations française et européennes. + +**Le programme d'ensemble Cloud Pi Native inclus :** + +- une architecture applicative de référence facilitant la construction et l'homologation des applications +- un pipeline DevSecOps à 2 étapes permettant à un développeur de construire et déployer en continue une application sur les environnements ministériel ou vers un cloud public depuis son environnement de travail pouvant être situé sur internet +- une console et une infrastructure automatisée permettant une mise à disposition rapide des ressources d'insfrastructures au profil d'un hébergement sur le cloud Pi du ministère. +- un cadre de cohérence technique dédié à cette offre, comprenant un référentiel d'exigences à respecter +- un programme de formation d'ensemble du ministère, au cloud, à l'agilité, au mode produit, dont une valise de fomation et de référencement de ressources majoritairement gratuite permettant la montée en connaissance des acteurs +- un programme de certification, l'objet de ce repository permettant de valider les acquis de compétence dans l'objectif de répartir la connaissance auprès des développeurs et des entreprise de service numérique. + +**Dans le cadre de la certification nous recrutons des volontaires pour:** +- la production et/ou la critique des éléments de contenu pédagogique +- le cadre d'évaluation et le tutorat des coachs +- élaborer un test d'auto-évaluation qui sera accessible à tous. + +Le rythme de production de la certification est réalisée en incrément de planning tout les 2,5 mois environ. +Synchronisé avec la production de l'offre elle-même. + Signalez-vous par les fonctions collaboratives de GitHub. + +Nous sommes à votre écoute pour toute suggestion, critique et apport de contenu. + +Bien à vous, l'équipe Cloud Pi Native ;) + +Définitions : + +*Enabling team* est défini au sein du livre *Team Topologies* cf. : +Selon les organisation, ces équipes peuvent parfois s'appeler équipes DevOps ou par abus de langage *SRE*, si inclusion d'une activité SysAdmin. +Le terme SRE est un terme spécifique à l'organisation Google cf diff --git a/cloud-pi-native/contribute.md b/cloud-pi-native/contribute.md new file mode 100644 index 0000000..331a954 --- /dev/null +++ b/cloud-pi-native/contribute.md @@ -0,0 +1,32 @@ +# Contribution au projet Cloud π Native + +Merci de nous aider à améliorer la plateforme de services Cloud π Native. L'ensemble des composants est publié en licence ouverte et le projet dans son ensemble est ouvert à contribution. + +## Notre engagement + +Dans l'intérêt de favoriser un environnement ouvert et accueillant, nous, en tant que contributeurs et mainteneurs, nous engageons à faire de la participation à notre projet et à notre communauté une expérience sans harcèlement pour tous, quels que soient l'âge, la taille, le handicap, l'origine ethnique, l'identité et l'expression de genre, niveau d'expérience, nationalité, apparence personnelle, race, religion ou identité et orientation sexuelles. + +## Liste des ressources + +Le projet Cloud π Native est constitué d'un ensemble de repos github suivant : + + - Applicatifs : + - Console de la plateforme : + - Installation de la plateforme : + - Documentation: + - Cadre de cohérence technique Cloud native du ministère de l'intérieur + - Présentation fonctionnelle de l'offre Cloud π Native + - Documentation utilisateur de l'offre Cloud π Native + - tutoriels: + - Application de démo Java à construire sur l'offre Cloud π Native + - Application de démo de contenu statique à construire sur l'offre Cloud π Native + - Déploiement par helm chart de l'application de démo Java + - Déploiement par fichiers de manifests de l'application de démo Java + - Déploiement par helm chart de l'application de démo de contenu statique + - Déploiement par fichiers de manifests de l'application de démo de contenu statique + - Déploiement par helm chart dans un context de monorepo (code + helm dans le même repo) + - Tutorial GitOps + +## Contribution + +Pour contribuer au projet, vous pouvez, sur chacune des ressources ci-dessous créer une *issue* github, par exemple pour le projet de [documentation](https://github.com/cloud-pi-native/documentation/issues) diff --git a/cloud-pi-native/faq/introduction.md b/cloud-pi-native/faq/introduction.md new file mode 100644 index 0000000..f5a8feb --- /dev/null +++ b/cloud-pi-native/faq/introduction.md @@ -0,0 +1,219 @@ +# Foire aux questions + +Cette section regroupe les questions fréquentes de nos clients. + +## Construction + +### Comment simuler les services S3, SSO, SMTP, etc sur les environnements OVH ? + +Des bouchons sont proposés afin de simuler un serveur SMTP, création d'un bucket S3, SSO, etc. + +La description de l'utilisation de ces bouchons est détaillée [ici](/agreement/mocks) + +### Comment puis-je lancer la pipeline de synchronisation de mes repos depuis mes repos externes ? + +Pour synchroniser le code tu peux suivre la procédure suivante. +Sur GitLab: + +- Aller sur ton projet +- Aller sur le dépôt mirror +- Dans la barre latérale gauche Build > Pipelines +- Cliquer en haut à droite de l'écran sur Run pipeline +- Ajouter comme valeur pour la variable PROJECT_NAME le nom du dépôt (dans le GitLab) que tu souhaites synchroniser +- Ajouter la variable GIT_BRANCH_DEPLOY avec comme valeur la branche que tu souhaites synchroniser +- Cliquer sur Run pipeline + +Sur argocd, dans App Details: +- il faut que tu changes le cluster de destination pour app1-integ (Selectionnez name pour voir le nom du cluster plutôt que URL). +- Vérifier la valeur de la la clé Path (path des manifests k8s). + +### Comment puis-je déployer une image personnalisée ? + +Toutes les images déployées sur la plateforme Cloud π Native doivent : + - Etre construite par l'offre + - Faire partie des repo publics autorisés par exemple Bitnami (règle non encore mise en place) + +Afin de construire une image personnalisée, il est nécessaire de créer un Dockerfile dans son repo de sources applicative et d'intégrer la construction de cette image dans l'étape de construction de l'application. + +Extrait du gitlab-ci-dso.yml +```yaml +build_docker_custom: + variables: + WORKING_DIR: images + IMAGE_NAME: image_custom_to_build + DOCKERFILE: Dockerfile-custom + stage: build-docker + extends: + - .kaniko:build +``` + +Fichier images/Dockerfile-custom dans le répertoire +```dockerfile +FROM alpine:edge + +WORKDIR /tmp +RUN apk upgrade --update-cache --available +[...] +CMD [ "command_to_execute"] +``` + +### Puis-je pousser directement un binaire non construit par l'offre Cloud π Native ? + +Toutes les images et librairies utilisées sur la plateforme doivent être construites par la chaine DSO ou être disponibles sur les repos publics dont l'auteur est reconnu et autorisé (par exemple bitnami). + +Il n'est pas possible d'uploader un binaire directement sur le gestionnaire d'artefacts (Nexus) en dehors de la chaine de construction DSO. + +Ainsi, il est possible d'utiliser une image non construite sur DSO, par exemple, bitnami/postgresql, en revanche il est interdit d'utiliser my-nickname/postgresql ni de faire un docker push d'une image construite sur son poste. + +### Quelles sont les contraintes génériques d'Openshift par rapport à Kubernetes ? + +- Les images doivent être rootless +- Le root filesystem des images doit être en lecture seule à l'exception et seul les répertoire /tmp et /var/tmp sont en écriture +- Les ports d'écoute des PODs doivent être supérieurs à 1024 + +### J'ai une erreur de récupération des dépendances Java via Maven à cause d'un problème de certificat SSL: + +Cette erreur apparait lors des appels internes au cluster qui ne reconnait pas les certificats présentés: + +Message d'erreur : +``` +proxy: ProxyInfo{host='192.168.xx.xx', userName='null', port=3128, type='http', nonProxyHosts='null'} @ line 82, column 25: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target -> [Help 2] +``` +Solution : +Ajouter dans le fichier .gitlab-ci.dso.yml la variable MAVEN_CLI_OPTS pour ignorer les erreurs de certificats + +```yaml +package-app: + variables: + BUILD_IMAGE_NAME: maven:3.8-openjdk-17 + WORKING_DIR: . + ARTEFACT_DIR: target + MAVEN_OPTS: -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository + MAVEN_CLI_OPTS: " -Dmaven.wagon.http.ssl.insecure=true " + MVN_CONFIG_FILE: $MVN_CONFIG + stage: package-app + extends: + - .java:build +``` + +## Déploiement + +### Comment déployer une base postgreSQL via manifests ? + +Le fichier manifest suivant présente le déploiement d'un service [PostgreSQL](/examples/postgres.yaml) à partir d'une image bitnami. Il peut servir de base pour un déploiement manuel d'une instance PostgreSQL. Pour un déploiement plus complexe, par exemple avec une gestion du clustering, il est préférable d'utiliser un déploiement par chart Helm pour par opérateur. + +### Comment déployer une base postgreSQL via un chart Helm ? + +L'utilisation de chart Helm est une autre solution pour déployer une base de données PostgreSQL pour son application. Helm permet de déclarer des dépendances vers d'autres charts Helm existants. Ainsi, il est possible de packager son application sous la forme d'un chart Helm et de déclarer une dépendances vers un chart de base de données postgreSQL. + +Voici un exemple de déclaration de dépendances vers le chart Helm de PostgreSQL de Bitnami : +```yaml +dependencies: + - name: postgresql + version: 12.2.2 + repository: "https://charts.bitnami.com/bitnami" +``` + +la configuration de chart Helm se fait + +Un exemple complet est présent sur le tutoriel de déploiement [dso-tuto-java-helm](https://github.com/cloud-pi-native/tuto-java-infra-helm.git) + +### Comment déployer une base postgreSQL via un opérateur ? + +## Exploitation + +Questions concernant l'exploitabilité et l'observabilité des applications + +### Comment puis-je déployer un backup postgreSQL à façon ? + +Pour créer un backup "fonctionnel" sur une base postgres en plus des backup proposés par l'offre DSO, il est possible de procéder comme suit : +Création d'un CronJob avec 2 pods partageant le même volume : + - Un container (initContainer) à partir d'une image postgres se connectant au service de base de données et réalisant le dump + - Un container récupérant le dump et l'envoyant sur un stockage S3. + +Création d'un script d'upload de backup vers un stockage S3 (monté comme configMap) +```sh +#!/bin/sh + +now=`date +"%Y_%m_%d_%H%M%S"` +year=`date +"%Y"` +day=`date +"%d"` +month=`date +"%m"` + +for f in /backup/*.pgdump; do + if test -f "$f"; then + echo "upload file $f to s3://$BUCKET_NAME/${f}-${now}" + + aws --no-verify-ssl s3 cp $f s3://$BUCKET_NAME/${f}-${now} --endpoint-url https://${BUCKET_HOST}:${BUCKET_PORT} + + fi +done +``` + +Exemple de CronJob +```yaml +apiVersion: batch/v1 +kind: CronJob +metadata: + name: postgres-backup + namespace: my-namespace +spec: + schedule: "0 6 * * *" # Tous les jours à 6h00 du matin + # [..] + jobTemplate: + spec: + # [..] + template: + spec: + initContainers: + - name: dump + image: postgres:12.1-alpine + volumeMounts: + - name: data + mountPath: /backup + args: [pg_dump, -Fc, -f, /backup/backup.pgdump, -h, postgresql-svc] + env: + - name: PGPASSWORD + valueFrom: + secretKeyRef: + name: db-secret + key: POSTGRES_PASSWORD + containers: + - name: s3 + image: mesosphere/aws-cli + volumeMounts: + - name: data + mountPath: /backup + - name: config-volume + mountPath: /backup-script + envFrom: + - configMapRef: + name: env-backup-S3 + command: [/backup-script/backup-s3.sh] + restartPolicy: Never + volumes: + - name: config-volume + configMap: + name: backup-s3.sh + - name: data + emptyDir: {} +``` + +### Comment tester mon container en lecture seul ? + +Afin de simuler la contraite de lecture seul d'openshift sur le container, il est possible de lancer le container en mode **read_only** via la commande docker suivantes: +```sh +docker run — read-only [image-name] +``` + +ou via docker compose avec le yaml suivant : +```yaml +version: "3.9" +services: + example: + image: [image-name] + read_only: true +``` +### Comment puis-je accéder aux logs de mon application ? + +### Comment puis-je accéder aux métriques de mon application ? diff --git a/cloud-pi-native/index.md b/cloud-pi-native/index.md new file mode 100644 index 0000000..088c423 --- /dev/null +++ b/cloud-pi-native/index.md @@ -0,0 +1,29 @@ +--- +layout: home +hero: + name: Cloud π Native + text: Ministère de l'Intérieur et des Outre-mer + tagline: L'offre de service Cloud π Native permet aux administrations françaises de gérer le cycle de vie de leurs applications tout en bénéficiant d'un hébergement sur le Cloud π. + actions: + - theme: brand + text: Documentation de la plateforme Hexaforge + link: http://localhost:8081 + - theme: alt + text: Voir sur GitHub + link: https://github.com/cloud-pi-native +features: + - title: L'offre de services + details: Convention de services à destinations des administrations ou leurs partenaires numériques + link: /agreement/introduction + - title: Certification + details: Tout savoir sur la certification Cloud π Native + link: /certification/introduction + - title: La plateforme d'accélération + details: Découvrez comment utiliser la plateforme d'accélération exposée sur internet + link: /acceleration/introduction + - title: Les bonnes pratiques + details: Liste des bonnes pratiques à appliquer lors de l'utilisation de l'offre + link: /best-practices/kyverno + - title: F.A.Q + details: Des questions ? Voici des réponses aux questions les plus courantes + link: /faq/introduction diff --git a/cloud-pi-native/public/examples/postgres.yaml b/cloud-pi-native/public/examples/postgres.yaml new file mode 100644 index 0000000..fcf45ad --- /dev/null +++ b/cloud-pi-native/public/examples/postgres.yaml @@ -0,0 +1,71 @@ +--- +apiVersion: v1 +kind: PersistentVolumeClaim # Create PVC +metadata: + namespace: mynamespace + name: postgresql-data-claim # Sets name of PV +spec: + accessModes: + - ReadWriteOnce # Sets read and write access + resources: + requests: + storage: 1Gi # Sets volume size +--- +apiVersion: v1 +kind: Service +metadata: + namespace: mynamespace + name: postgres # Sets service name + labels: + app: postgres # Labels and Selectors +spec: + type: ClusterIP # Sets service type + ports: + - port: 5432 # Sets port to run the postgres application + selector: + app: postgres +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: mynamespace + name: postgres-demo # Sets Deployment name +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: postgres + template: + metadata: + labels: + app: postgres + spec: + containers: + - name: postgres + image: bitnami/postgresql:14.9.0 + imagePullPolicy: IfNotPresent + ports: + - containerPort: 5432 # Exposes container port + env: + - name: POSTGRES_USER + value: demo_user + - name: POSTGRES_PASSWORD + value: "My$ecrETPAss0rd*" + - name: POSTGRES_DB + value: demo + - name: POSTGRESQL_DATABASE + value: demo + volumeMounts: + - mountPath: /bitnami/postgresql + name: postgredb + resources: + limits: + memory: 512Mi + cpu: 500m + restartPolicy: Always + volumes: + - name: postgredb + persistentVolumeClaim: + claimName: postgresql-data-claim diff --git a/cloud-pi-native/public/favicon.ico b/cloud-pi-native/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d5b9b0fcb95eb643d699892ba0abee33f02851ee GIT binary patch literal 1150 zcmb7^-%FEG7{|}Hcdk{CT8g{NyZ!{(O_%OQq#Fgj>ms`ny$I5q3W6f4IkzN|DCo`t zkpkI*U=72IwXhoz!ENuBnPZzaWz%=>`|WwoyCZAZMb9|r?ELsV&-Z!G*@SS=r@dWJ ze_7nrgysvx3sbks z=8Cc{oY`=ZOidMI!hzJ&lFFK4hcOQ+cID zxg7}XN(~`R!y|_S52*IfDTivYX!ELY3Z&66ENpCi#k++vu{v1)EZy5Px`QXgzo)xo zQ}-_?O&!0%tiFb++iBwS;QGxH7hw%Fat>@JA3ViW{cc<@O6`gdyIgoo{8Atwsei>+ zDP8sN5TAwDWyfa?VakJje4m?>K3X-X*l%7RpyOOlz8`-7%*sYJ4Dolb7u$)1twR-? yW{Q6~Uy<55How0Uo;8q<86L^U*5cw{KJ;uI_wVkbr!y~qw;Y@K*8hY5o&NzJz7ebd literal 0 HcmV?d00001 diff --git "a/cloud-pi-native/public/img/agreement/acces_services_observabilit\303\251.png" "b/cloud-pi-native/public/img/agreement/acces_services_observabilit\303\251.png" new file mode 100644 index 0000000000000000000000000000000000000000..cbc7e77d7c7b1e671af4dfd22cd429fbab6ece01 GIT binary patch literal 117620 zcmce;Wl&yQ*DV+lf)m``-Q9z0aCdi?;1=B7-5r8EB)Ge4aEIUyz2Thqt^TTRS9jN~ zx<4p*p4zo!uDPa+F*YHx(xR|Xm{1=+e1H`f6O#Y%0kjMFv4Hppd~*txF$w$vagY}k z_)s~9eE@s_HR1op|KUS*6!eqcXW%oWt(cm_hYw%6-+n;)ZHf&)e0VJo7vfiR(LT=j ztck3J)|d1JMOYSw8pg7^m-hG+m9Mo`=cvB*vc6iw@>rmnOP1l+SE=a8=gd{EN~&sV ziNnj+4L6I^k>hlZTW&5UXUA>(=5Y927F=9hR#sN|KzIQN0{`evIIRQkx4+PF<- zLH_fne-Frz*nhsa^I?pAe;i&w3_ClV`2Asjctmh^1u6nNA_QaeUdnuA0!S$j45o-g zVoYZB*v;(8SmYp95lIYju@y0FjFgEoe9)e}f=N^H&98YR6kjlD#O+MY%-Tv4{+A>F z|6IubvB!N~5@Sx5>TBhvI=#J1$SD@uTpgpBHOjB8b#QTUiNxlhrlEO$ zevZQ9qg5j2L?V^iUu%CXmdpE}k8hu@ww^C$^ZPB;Ta?v^3*-m{6iTJ&TUb!-{Pzrz z&Pj=QczCL`+e3w(AFhvP%Yu4BkjOf`o=eN)o1Bi6`y+8qj*ml;DW(b}ld#yVgD?L4 z`NQF`J5#DO+}BqqoxxdaJPHL3EqK4#8&*+XE)s=Hlj=*YR+GIwT_i*3zC94r7lE}m zn%1aTB2Od|e)n`=OPzkmJu1&hU6XF5qpOe|DN`mcY+e(0$U_m`cSoMd2RELE!| zttov}e|~xr2}egjKwvPP$le>za(8hVN#}6r4Mmal2}7gnaKE(%PCz=7`~GmY4EO?= z*!gg#ME`d(u(!)Pv+3}N2$>Addf*I!rNmPz9j>*z?+cmp|9gjsL4xrx?*IJu6OF

M40poxpg&rr->2!5>J2^T^Nl6hB63WK1S}ny8iAKuj z+3yVHGW^F8{qb=Pi5>p{dy3hguUbc9S!%S263C&Kj3^D zhZ-v@D}MrmLFaa{eY;CW!^*|71ah#38;*WKcDbORXt<@r(YkzY@_MEbw#MtQJ0cdm=$y)CXo&xHAU(Hb`A>`< zSpQ^1{GS75|B500AJ_aMD}wlMOb_`KAM>9{Hb4CDJuV(|2PWKh2k+KTwO=EeJ^XAF zbSB|FunD)b)}g1jA#d7JW#;s@6pQtHX?@w5jVSaNjyZ_!s<(=O37!KwVY;kea>Db4i( zRh7abq#Poa4+wYDa!&`C`-Lpi!%3^?u@@SupoU~U#B|c{8}EUB8)7>WKAIO~V=e_I z2bTb+0E)&ZUn)T&hm3$!hUa1TWSA=M-7=lffLVy|5m9N~|FYg~EJs@^2g>@{m#~is z4It~+$kN8Kd2P(=fSuR88++jF&C=q9pn*el?x5(H2fHKs#a?@*2{G1ges~>{qNM#< znxt?^qWhH7oD7;3{>gRB^NnI<-Y+4YHt_cEQ*NugWmjTR{L8V{$GrhVQ^WEyF9bv= zITcakd@?`ND>&FoNElZ<^w3T?-<+%;U2O>mw;%*Meu9EsUD-4Ry)zR`GlNN^cZnwO zMQiUaaL@9V8wbCb4h)Zfgfe7P_J(1s@Rc?;ScOpQdHnNNRL2h=^HZ08TP`{x!7C;v zh!rFcMHnF|k)vUAEhg{Hm%`Zhe1HG>eH`fC_HsT8vAYtfzLt_}r>^Y_IA6W9j{<^q z9YiQ@Q)KirbnJ?^dt6#XhMf1cSp4GlQ#fzOAKfJIW*u!!Z-nAXf^S!bDc>ApF5$vl z{*tI7i*yka5<8iGc!5C~=Mxc>^dFV!Phd7(iNwmn;6*!qES`C7k3m##bx1#xZ(fjiY5Mkg*BPg~Clw=eMU- z5`&57hYTkrfk7f0>&l2F&?MpdK5*{mcfSzOEnZosnT0 zHD7tclFI|F%7S(W?NzcG%8o!Gp%&7VMS<7*Aovcc_iHXB`F^?IpVXF0l)p+z4K%r!D8}*gs*GUN_7{vecThe&opT%d zOZAi162#}nlfC;NX3m@YL1%9=7EYs?32LSIR#MY*caiPyVaXcVr&$@~x2g`$M1S^- zPr)b)6Zx#;X{ctEUxyf`Rh!34c~3#EC_%x%FqijFi8zS}l#pUmNT{@za4}`H!l7nP znUBJAP8d4tOdhT>Ll7|GMs8EJ@qEGZ(bog^6xSKH&D5$Vb8`?WBSR}bbg%eti<$&` zALVk4jk>HiN-`#N-rZkB$c-bvQYzE#6`SJIsa9Ny>Hx22!u_KJ31wTBWXRcmn^)@2 zAPL1K&g;)CY~lj=m(%OV zoX9&t0m`Y=b+yC~Z|jxc#6mtFgQB>1`~Gtw#4eF;Goz3dE&6b)i|v5TrN9%-`;c^BKnVJ&>1-VuDIS z7GH%7=j}|8?-cpNMv)^T+anXo5D}8uXtQu2`XZnC7A*&pKd6X9J+umWb*hvXqslo6 zY=XXTmw_eLc%ETag_svi^fr8R@3w|o*eFGEfEs$35jnA-HgU+HYeYUVuZdceqF3ie zpHWbu9iOk{kj#r*oaht9`DE5@!&@vJO#Kx`*44fq?6_YmYS+Ss5>Xu-f8*s>DU@mo z_cjxTUTz!ZJ;@MF#iC87gws*x@tR;tP!P2h>Ec#DBb<%e;nQT;V0y11$I!sq{SfY2 z5>H#+o%@yS4GH!50gn79maZ=Ea>*pzn5PjEmHC9>L^vGwVwtGSO`DhW=AbXwPj}~e zGe6)F*Im3H4+5n8d;DLkvns##9dyizMSR-wlA+d{5P}eQyGlSKFd)1wu|n0@9X_m2 ze0ElBFw82S=c{4qH*#nko+?age@0ak$4nhs^GI;*jET^p)o>7a(6AHRW$(F~S^Lq7 zCO+DMRQa7nUPfiwIJz@*nazfuhqGec_HnM_*RQW7ilpwFr(XNNeC_i3Ej2rN@$pj! z(;*1#Ht*ubUo%}?HwR59=;EweHrmf#z$pa9U z_}^lr+trMwT>iZkV_TEWcf(rC2Qanv21c!VHi1G(IxOaI%1!YC;sTtd^utupkTIi< zu{#4)2_HTYsTH`@m|=y}wtkJ52$1kfO--PTC0}f^ejeHx&cVIh9bT?=KI4GirPHXF ze}cv2%ujFUSwc@KJde8b!eS;6;=;!y%W`SH-*t!RHNo?f-He`ZGij!l;RE}=_Od^w z(VKT5NTpH4IFsf+CfN*1FnM{hCmHkg@lk#D%v1@XUN9Hq&GRod_tb0*)iP8Du~UZ_ zjS&_d_QvVd8jgWFjF9SxLH*n;Q7|QDum&Zmc|GZydI4fOP%>IAwW;MBDXSTcwx(t* zTEHWZI&$G(Jw8{MMa*7N-Vdu*J1*`>CWU{K!p8@P!%{A9$|yOATBo>JT>5^v$!>hX zd^A3%zsEN>MS+dhkRoZg{aIi)LxBGwdt$s$U9Z64FARwp@skB)53aC@=V1dG+u)WARiC?t73A6#5Xj+pS$ z%#Dnk9UlsGZVL_#Y*VrCWFiAXdaKl z9C_1SE;l-?!hOgCh0lx%A~ZUol91^ejeS@W^}%eb^SE|9KB;g>xw)WPc4zOUyZnub zV}}mZY*FZw2FJd~pRtqWgXtnXMoV(ge8mSQ9lx$|m#+P;Pl8=%+O3S zKmc9uAS_@;Jn`q;hhLSz$o&lT6gdPM_2y1HLnz+f-gtOftF6xSKu0(_`fVnV3gJN2 zmn}r$kuQ_UWUS5Y+I(*;{u|LF!kU8|zZJq@7Uv);I5C0NBw%*^JZ*BO2 z$L!BGMmaTD=KjqYhmC>v_zS1uF^2V}*|0&ex3<8Z$Ney*_3=cbG2dK3Ow*^-Ki@yu zdV0bC9-5AWv?cO6K%ejAx98#fq7o}E@ZvvTj>&XwZOPf}8= zv8Ew-7|n)*h#o*uezQB82K1x#)z#v0q~Cy+S{5A}J6$*=aR|N?G9r!HjBw}Gjr05Q zLXk`s&@>2F-$gHEELR%D5tW+$qIa@=aQr2wN4^RY^k{5^Mr(~ia zh`T$N^>DBXON4<@TCcaEn6b_)kV%WQm^M2+ey=*~bcCR7Zo%cW zmA&43xvM4@WxBo?u1peY{;-;ByHm4+HDAT&bkU!oo~wBsM5)a}5)$a=*WDMfB(e=3 zw}oTROl!I59K|I>G(!}h-_%-f(max8?Gk3}UkuT7H@(ey=&{cvjY!)n@7fBSx2;ljVjDI;|E* zc{x)E-XEh(q1g1Y?!%&WRb|B9aEI*}-^ zJ!qt&f`k;;c7L%+*Dm~!vFscS)`%~`=K;TS*XndhN?fc8>N%Fhq(YmdQYP1)-roM0 z*FQ}vgKCeUWLlz5`HSyQ)}%o(vG}I#%hP?9HP+kDRMi{gR~{t zae^$uZ^5BHo)(6_kc?%e)&nZSdqP~Bq9RL+6u9_m&GtJ$N8Rc5oXTL(2ZMq9dp({) zp~hsq(vr}xtFERdmCu`Z>i6&8abz-q%tHxODgYS5X1RcWx=^lCrJcqa8k7w*+&}t0 zgaA!6kz9cUiZGpodV^&MBDqq2HU5MD4*;L>4*G&~y532*B(w=!w{K~zqrh+}j7G*I z$q0zK5F|<-_ZLQYe>ZM!ZUDsa`e>f-`*E@&K^zXRN0WNJIl0YB6T^13VkubS$$F*A#z*a0KpD@L8K!3?Xpb&31w<8MN`)Hn+ZSI*Bf)F&`}(R?RM1f8>yW@)ho|kGXwaDC(e6B`6%OiJm#R>Q9o(d4HE6%OylUwd zG6x1QrYsn-)X$u|f8RS?U3Tt~SGNZeePV?MzZ7uo%rZtfvnps_fb@1Y+c;i=H1&!5 zfQDL#<3-l%A^$4wKG5lCQpQgNR!K=XY%#|{&cfV0R~^dgcz9W~C01OlhOjZfPUeyN z71#Tmh8W1VBUE%$Yt%Zt{ZZ~x5Fjmk^G0KMF$5~fW=jJ$DKAD7D4caeRPzo_v7us? zJyGG3VaFf%%mp z0-a&A^Yum06+pSlD^RL@m>3xN4Sf9dHhzKk;eg0zp;yC~%#F35seR_Jj+T!GXzA3y|V^p0X z7zh*cFujz_U;xC*7#0iVhz2{D1z_SwjHo$SubUDVi`LW4zXNQ97Cs6p59Ydz@(=@d41 z>2T%;ir4JFu^i#m;_?XhY4Ax07mE@GsL{jQydc^{k&W$_yKY~_d~{@+ayq1&u}d(K zCFYB5TUtI(Dc6Z-jINLqPB`!FMvz6eiiMf^Hc>;GsdUN-+L2jFB^Q4~EZdANvzXNH zjrM^;5s-_AE}bvWK}?ZjV2ChMB%uhaH5r$d%f&Uo5B&=Hv0}Lqg)be1cr1e}$OSC; zru4p2?nh!Sy}WxJ!gH8_VMcm-bZ-$kh-nCJzEpgmrhodap=9KhF9Dm8sCga&~u`M25Q z-aaPa58yhWHJDAVm!!PaoTl`ql*QDZ&smwJ4**ySAh^-!td{78Sann@1rNt3(5Tct z4VKe|qqAiya5$WxlK}#DvsVC)J<+!_lpsi;xmIn^pSxBsU)Ln9LB5n;RRxHueCP`xzQ_ z=4YR3C!s(r_R$rXm+zEKsE#1Ymah}#pv3w%9g^i4KGv$*jcTY3F=3a{av~M7aV0h5 z`mH>Hm<@ibvr>b8DD|JcMz=N(N~|q(J*&$mZMG62Ql{BQJ6ivM!HN+V^QU$fS4vWI zMuvL^PSAk+Gxr9lkk3VA;GmCb7)NS_Q{$;)fBn4o`^xZkGrbzePP%;`v)W;6uCm&) z_k0NSDNtI0aLQ*=c_?#5$L_Rgc#Rn!%4X6?<^z^b#`}$<#~BB(AA3vljute-f7`?B-6$Z8BGQUvwt4@34+e z?=!~1Gfkbip5)k!L~d>#Yg$WY4z*`Pu%lX+lj9aOX*C3D&*r{Rfb^4TUgr;&$5H@D z?~lN8K3QV1Q#l0A7w|Ho(p-IO>zB^gXEzqvrs(hu7oIwpbGh38`tRD*#$@7CnuQDl>nn!742w7GPxvsJsZuG@EPc z>#s``iX`I6tG%Ax?24?3g&svBF!lO#IC_QHF&~ik4-dQ049ceR#r-S`BoY{nNA3XR z9~zAoC~%>|jt&m==7kJUqRTrvI-+af4;L&x*pXKnnyVU=>mU$_N2XMtE=T16^g{Oz zBNC6+Y(f|KDA*m#8ATe4)Z8pT0nRyi!a{rG@sgUFG}U4&xIEWy6B#vBrj$J-wO7)b zgHM19QoIB<#yu}nEi^2&B($`tuKm3k$VKd3a6#*%%*B+~NK!g(qwL{py3RVw@49a#EOUQ2OW4}u3! z3!X=bW|Rs!r!_|7l`sDJ^Hk&gQMl_Zt`7Y-C#n+HQ!(~8H@R8O&}di3)9$@fM*HBN zP|fHe^V+d(Fn{5`+T1NyTX6+;Rd4l|yoO51b1D=`zk~m)D=R>l_jSBIT|HZAR>&8N zG3bxX(X2!8MP+wB)${{{eYiOZy8>E)0DU1QX0NOL$%Sfz7?fN&A0vcfd?9{z5T*NZ zzSpMKR$!UfSpaN<>KL7YG3eO`YwA0E6gJcMxB@ zoAAmmrD~lig8vFYt>JRJ;A4skv{y&-pwlS@;Kg5}=1W&J(NyU7hT6)syWe^N8=J@x z1o)fs4r+Kc*y;38Xdifk1zZ$^KJwiiKWqQW$J=%9>B4VZ-Y*{R?(PgJ(VPIsVQXjS ztLPW)_Z5X#OEBw)*z%{zgJ?_#Y|ndcA-Y7brP zBpwVKo;D(TqaFx`A-haiW*>f6j$ZoHUoV<(tNwLV!u8@-Pp>38Mq8V&q{dp9bWxq$ z8qf2YqNbpLab`5>caw2P-7dk|M-Odb|L3cLb};D-cDa!;>0+)YAjl|Z3D#@6K7vJH zHdwAMjg3iP>lzXR?YDq-3!fKE#s0wo%E7^qWM!r6q&dA`3qxyFZMu~h;EA zu>cyX5#Z4_8&n4*<-YuEn(!?az{Cl?a6FhAO<@A3QmPL}y`nB;>n2O|yua81_^h7+ zKdm6teeADiOFm(^9t3Q{${=Ces}}6Sd2EvjI3dsL66)#Z8l*634i}M3!bJ3HmB$1( zI3UuT!!rf=`~P}mXJ;?hYDE>;0f^E&q2`DPSl)>6@E)5iz;#vXlso>yst>QMJONE& znQ}$fk6cY3dykgZR_{mB)#yMk7#J82503`R#UD=mwfr8rE6VrG5UKo~-_qI70X}g; z>(1j<`{ago=ZbIPLpkyi3pF(i&+&5O*;+du9bV8-*B(HTaXRkPyZqI4X}LO>24=+z zh}H;#!#iDRz68>;#e8K%&cjr}KpYZ47VF;WG+3tm?c5|)g7xh4Z^GFDoOHRtN>Jd* z6fFdiMB*zqpZ5#)DHazZCT8gGPdX5#%;gMoRl(8QUs)YKRl)Jmih&6az&JTEqQAvjm$DH^PRFbjW|eg#SKeaOq9>8vZqxA4XNN3uZ^;OhaI{97HS?TwWYOy&JIcc} zvdO;ZYA#GkR~CE-x>oHU$vyjXi<5RQ#~kDcN=4G?+}j@63Q4qtWnEoeAEz9 zdwU7VeWg$WKE?}%nP-M6c{=4@lF4NLK{{X9KFf|1(;yMEDpp~3IFzJAGGvvG-K?gd zBJmOtl{v4=-^J4GjVLz_?30%x*56MTBEdD>1_;m%(QI>o2iGcBtp-v=9zZ|;04Put z*q$hDpd=PKS!s5Nh={npy26JBPGT9j?UUM{d-MWfF#aq}2yS!*XlZG|!ooh1uivv8 z4#0~IMdEM~Mi?=fD36RTG}`C{F94n*cp-r%+#44hO{7+nSCsB-jdpIiBy20^6L=sD z_SJatH-g@$`U9PX{TbLRE6e6NdI#Qv`Ac)U_S(n;szE}(fJgdiwMO1YW_N|Sgwi?33K>m$QF=QM2F>q zFw3;NUCW}Nq9!sJh|~pv`|jE~I9y&{rm@*%nv&8pFf9Jm`!s`@PwECA^(7JrjX?Qv zf4Mh5KR+HvHvSg?Mf{6(&o_H*^Z5Dsfxf;%z92MNofJ`40mwttKu^utvkQw(|8>Y;9 zr@r|mh%TpP-KND04|@ZxFxrEVYC0;bEMR|pM1a4kw4n)6-MfT@F0~NHGG1r7}T& z#c-QQlgOL7e&BFWB(9G)R+dqw9{^N3Up^T^_@@ueu?Bz@uIhlO8+@3q z3ikS)!;f$wRdr^(#;!^E5ZQJFlOafDbmrBfN__TIH5Pa-zsvQqliI9u1OjVjreAz| z!|U-y(j@=Uxnr9Mm*ymjVaaa{9G_@fLp2=ZHmW1$wADvt{m0X(>#CJ(aY2dR_WdAh zrH1$YR6+UNoL>;EQV3gY_Jpa@*V+V{$E{PY;1)oXB-l`Ixp)EiNbbbQh~-#12cVEh z<#uK4!Scsm%3k^X8^jGxZH5pQBShc|AC(*MF93rQ`ZW2b$>H1`NnrwT8u%<-AYi=Z z@H7wxNbNQk-*Etqio#+WTUclU1W!O$?>8f4pcn!jWip=Gi<*lk7n#{x%OTf%Ip=)| zdzNyo&}NV`Nea*J(2CLabY3f52kH^y=~+Y-H6flvaMq7~{G!*X+%Ip4vImZ1_F&NPzQ| z+?ZY&obf_9BJ&^|cE(fN$NR3)CpeblWlAyz#yZ#NC7nZNB`Y~OnfX;G?zJtb5NdcO z=MO#Ck$v9--!U;h{x7rVKmaJjNK1y18|lKlufQVq&7Lg%1PKmEsnh}85v5Y8Siw+| z_*%1rC^_f(Hi05GGuG6mH8u6;-xM{)oVI^_Ov72p(LTz|eqAj1IElDp+U9buA1uSh z##YDQ41^>^9Io#|H0lB*`dC7IV`F2c>&0?J%<#|Iu-haJ{N>0I!mh*}0siif0lN)i z=PxNDX||vh7-ilDNe_>Fxrm6waYus@Fw9#1@j=5~CtT=G=wtv+U025pa59@BgzR>a zNHT4L0z`(!X4i_RkdRDK7H0EN(HHBB25KGFuhpd*`yd`mlQv#56TvEHf+to|*ROLygcvJA(8Qa4PDf|tCQ&fs7mIvbLE{e{C0#Yg`+3QyQ^V7j zHx%SB3WcJf5S+=-CR9 zk}17Ugww5CLXW7o(f6>5cCh$-M-T`o1l^Fxq~l}#;b{Qy5hn68`> zuc=xBQ_n8#@GQi^qLPns;d8%!Wh01640qU3rz zOu=@ztZv1|93gb!%VRZ$#UlNC%cVN2BpT7Nk-51YO2sDUS1&&3Zw@_q-5*~60;SlC zJ*+shLc4JU#dMLA<1zKx?_#p~+Y7}uPR6o&r+Um;GMTKok}#sIAYyMO;HpL)cqs}X zB4xnLk-nZnmrV$=cv`p=bC0N7s~#6&slhr7cU=s1cXmR9MpQ#E=Z^@TzbIWm|1DI0 z^P?5{u2yA5m&ZV!OUTifL3{zxe)2nwz>>)kwmV_tnZv31OEwfH!Q_;bX2+jF4aiD| z9w(gRbU_)FnlDRa)b%;izo{o>0-sb6q7p^&NJ2hEB<8c5)`f`NZCU7rwG8d>KYT~v zES%J#i~}DQ#5>prLqCF3%`?%Epd{hTD=0WOf79gX8x`tsw^kQ9?n??fxQ~7? zaDn!f$$Vfv2oSi&mNPI+P?#9R_Da1TJ=)02Ic~>4Do?u78Rc&Idf@_knS!0*%@7yEF>SKFLr1FlnOI;Tvl9fg9hVaM} zyw9l#Gt9LqGZgI-@Mf0qK@}mB0ho*(@ZPME1zAd&G=2%wh_T>%&Q~0Tr*EpXWs6dj zB=7nWyLUU<%Z^4Xl$XX&AZ{tj|9D%C{}b!Gc1!SdQ=U*ojv@!cfr=uABr5)0;X%*| z`(`u}g)V-HVug}`_-wa#$&vVnH;oHL3UzaVKWAS_fly-Gzr*$5y$y#fCYBvfFHJ-; zGa;TOF7d7riUxhtD#u;`*+Wi3IIJZcIqs+!xAY&$a%V)OCT&ve`uRm@w7mb5nyN;B z_ZjKGf@o4bAh6^so@OLfy@J0UU1{U%@QTSzIc8g)2?z^B;MISLtTACT!flM1C|MO& z6ZeAuA0ABHoAa-C7UbOAe94e%&PRr_3Kc&%+c(@n=6W~J`MWS8;O}n8icvdZ%(8UK zD+Y4udUL88$91H*xtj70HP?LP(5aRz@w;Siz((**5U}RqMz!9l%3ELWq0P3KR>bH) z)q7InyN;|>Ixp~p+SR+|1_A_9n{T#cR#>_C$MGfC{X_MI_u+8kHg#D=9g@~4fN zirEz zqLWlMCpgugEt!#zX?N!D@W>uvj*w0=lixBwaT;QYO;MvXe^(X{oW1+BT>5%}%aENa zipLOedW*;k+KI<>v&z;bTkOK;^xH*^p+|{Zhr@eL3C-n6nFas&!a2w~miP;f=5PnIbPtE8Q+_)Y?csaKmwG_xVVur6f*C}4rq#eLu4>gc-sMRgiSiVX}$Fp z!VnMy|J{u!DxShMFo+wBOJe7|DN`saQAB2vOp>Nk=);UvdeUFy+T239IF#d@g{i=5NdeuwpHs&a+-a+6)N_shZK!!?!M7f#1wKVd*hOIV}R z=>=p~A)vXZR2rHtknFBCiOQj8XGgc1tJ3*#mC6DgO$#j3tXZ?e?fM58tOU>;*-m6j z$Kz4pVE@kKN!yAF`bP~LZ7AR|G%%jU$7-osXgt~lY*4g8z1~f&))-A`B9X~BTwW_Z zo#!#D+Q5Ci&6R_lePH;A#L(nuZWfojiN<{P{${kw(>-XlH3N`OUu;v@-kx3)2x7~m zvuEe!#c?^m09aIBM04}!DOT17v9skyBjD&%wO*ctflUJ%=5XKFcL#&Z89De5ESgj;gV)E zoBFb7JjzMfZnZ3)4-oSqM)F%towK-i5xAHaa_MXXo$aAyq<<)Vq%q=t`+4q!K{=L zNtHe_bX918*86PEDmu@g6F7Fj>11X?O^5*FlFX3)y?yQqr34+yob_K2^gZM`bwNk}^L>e4HfgeFIcIB!J&Iy$FU$7UfEiD=C zHb0gGU~08~si_{k-5&H)uMcH4S8TA~X`4tV5^;osgA=7`=_*QFUc_X9%7Hqt+j@w? zU9GiRP8AGvyuUi|t9KfM!6-+@`A0P?01*Ng`&HzJTwb9}O3lnzWq3!2SD}=e#k_Tm z=i@Mz8#6f zRDQr{nzPW&SVkG3+(%Hj`1k5VgwQ$W@^bF)kgVdTDmw1VK5le#S=jm3uoODM0{ z+Hgh!7LSF6MG;3&+(iiia&Bq{L|pa>Q}KVoue!SWlxD=tuOzxGZtj&Bv8*-u`2UP9 z&Pz;$aj^S+?01gXYD=%5pI?pfXeNo|_mY1~4B*|Q8Ul>Lftiv~fXW2mw=fhc9*14; zhldCG&;Lg4XhT89*q8vQML?Q=-4y_Ushnu!vWov!FF>SC7yCZ`UyZ!@*jt_TPaOS! z(aRH)fPsZMIikYidGQY+T{Lz%_?nInCwV1Mo=~dU1B63Xes1#p=jmLQKB%`^=l5Wi zH<3s69hdt}y<#eII^S!d0vQ@s+BGSuB$M$|m1gq^ld^sCBytu)Z%&83HF#0)(bPxz7)%Iip_3dzIzWZB3F(r*)-Hoay>DpVf;?7g zGOi$#=@D}ni}&)9GhL)p+qfP>&`oKuRls3iZZW+Z95zfm30%N6v*330l(9QJH+VuuxDz zq>c`kf$Y?>zs!#2`sG{q@18jBcE90;>zOv2O%s&>C%KtcB-8n89G}|j?yrNcE_*s4 zTe+1;SW4vf{>kn%R4W!UYS7oD-SKqV9hCj&&tH|Qrv@8u`PQ3`u?($090lL~O-JXe z2zcBxOO>r|3%^CNz|AR@8P85nPfo@tmFUx;3>reCtzojAPW45=6>y7-y)QmYf(;Yv zXv1N?l1$bymv|BaHp0h8v*jvMvvNRPEoG)Srb74k6}s04{fwKFD68e&%7Nm^2CEL> zwW+IPwWjYU#~6&s+1p$F*^xL}g)*I_n1HiAP384dE;L_?kEXgK>=Rk(W^2?H2lxp#08nhmQUn%W0!{1cI$w1=kN6}gc#ukIox^OY zyZ+BWj@j~*3R^vBtpaTXzw4WmDP660w}!oOoGk8xm2x#}xsQPCk;`akwnBplZl9Ro zT?~)!>#Mii$jATD@ApIwN%Y@axaDd=x!B~V$ExKBEM76g(Ny!-7qGK6CqBE}gXc#a zUa#ZDY6Gu$1Nc%Us@9qlI8vDgosPDpP?XsyT&s%*r}+@1;lm>;$Gx7Aq_dTK{3T$o z9tgJY;a8x!hJR zpDdqfX{L55WpXdh^!35)08WU(@MAn7hW+n2U()H?bFfgQrm<)gYaj;>-x{C-xY6mj zI-IW}A8K`^P%V;{Hq!XKSW_^V!Br7Y5c1{i)_^RwKbBP4Kp>thEpl?A!UxEmS+u*H zN4QLl3?9hco|08m%p;TkAue5OJ3m{x7Ruzty1GJ!oq1L4bg)^u`>7|mXSp~BP`f%O zOOL2DEhxB^;nwjkE*=>Sf_Bdn17c?j)ua)ai^2A~*4A})1{Kg~>c>k;e4cIwCCr>K zFpgwWy0-q)s0G0whTY)jU(N0AWH|LX zf|4sOvtxa`MXHO#M_7uQ2UE*a`D)tb3&x`TTQSBMDV*1(e*yURq0Zb19n8S!T4%Zt zd;_ikRl;l0R5a@Q^IrmpkS{ov^Ht8Ww^_4gCS0yHYN^a%VstuQDvmDC5AM}GX>6}e z6n2l_o#pm-Z=@;Zb4QzfXtJ0GE9`f)%%&@UeVA-GnJkitJ44DB!ouZy;kH?WC6+Ik za<(&*Z~gv7?#om@gJxUPVXaBVe0fOus+b}>G;D~y9YQJqlAbfTe# z$v+1N^993p>6k!tgGO~cT)d1w%vTVV9Dj1o^|KL`@ai9?5|BW+FwwKZf$K~Ic&&wn zrwIZ`e!_CX$znN!@e&1Xv6YV1N>e#W_eY#0I;yVE&bQL8mxT(faz4Ma^?S9%z8(;; zeFc1+ld7mY`U+IP1@p!NNp%N(N zNrAlO9XkoNJJ!x%nY<|=QExsM09Ak%KuN3V;&7C>8Ol6T?&aAlvlU!{kf+mfrN9is z#bKK**X}lDvll$j-L*|g1P8V4F zkv@1j7t!eKxZLQ5dX1ya(97Z#K2Kt?FqbO;6jNkct(ku>9}m3bTn0ECD6h|Sqznm& za^PZQ8$o^GpMLvAZq7~Xur9%1NKsQOd)?>Wh5UVfJl)KE71KRg03+^;q~S3Na%@N_;Ur`0H-XPx7+&$pW` z<-?7WB%PQxA3R>17Y%O;?)mfk`{k|@Y5<+~9WK|6e7=(7q2jL|AsrMB2tF7Lj9H#U z$^?J~Wfg;%#$+w;IbKAGX}9lfwcGj>yaPTyc4- z=MaP;SNjACg0&*>?25nua62_SN$D@p(23T z;pMSPBmgQU#z!oT^+bIv{U{KIV{fkr-tr?mGq$xU&~0T%XIzY@C{)|5=LTE6MH^U7 z_m{TKOjRdB!tDsG<&ku?9FYji0k3Dwi?dGaT&SniNxVf}|IC?GaBG$;rEiX~wpjOY{&D-B)}19UP#DGeMD4AN3#6@QhsuqWjZ>mX z0UZcRy-=Y+&;v_eUBgJDIPj6t>Ds(^7`;@bvBRP0x$`va`#%!119wmfXO%wf;V ztvOg;R$*lBTMsWn#8q=$iy z8_)8l^7bl9V?&W~_A61S!mpg2O~B!p0u^C&Gz}qYGu-gR*_P8{q#Lr$8e# zNF);P2n5J%9}bC1&2vAbNxET%kH?zOk4s%ct<$ zWpO`=eqz^jQF|n|>-mf4pR0p;`j%`EMUo+tpe;o7z?0l7*sGD*Fzn>;yPFa~kVfZFg&S5It9ZQ~Y zIBm^7W#PR+m1Ybzt4t<)tHkKu58E!?A>@O5nWx#xb{XW-GaPZX?O`(5xkL3Ym@+#q zWy+(J34P%3=^Y(VEDMci2Zyt_nr+2Rv3P?QzQz_$!yzIf>KaEEQQqF$S%#a$a_sJN z!`*@m2p&?Vmmde$+QSIBp`f6uRK^#F4m(4TP;T|FPc#(C1!wbC4~Lj2(fxs%gGRZk z1J4W<%J;DGUNwdLKD4uQ6C*?-p{DQ(oJjl$5gmOlr@I;`M!p|z*EsCOO-w*s7XhzY z&{SkRfdq500JX+)Lw&njeMCV)u$pIwm(t1r8O+A~X$3r+U-2pEy-{8Oq1BS&dFW@$ za2J1e#47E38g)mFe2s>YFc}4fgE8}K=x={d2xBM{Hlbn@@9xC9SX5}429CwN7i)yQ z;^Xs?Q<(>8q>wj$*IPhRO#wMhzTxJU(Y#HIRM9FB`Enl&#k0w8_;Qk^QD)f=@L`T`x6%(xSpd_FrN z%U0M=GoUlv6Jnjl#@FzZ-s^96H{dCeI2O5Xh^ms6+Skh7pw`2Q{djzoUTA3Z+x2zd zW2YAD4&*vKu&Q*D^i6qqaB{FVzW2~PZ(^KT%(wN%?fnRX;|mFK12d(qT_~zPwq5yM3<42=`o<`{}2P-qigi-)V=)U8IbqE%ANn zy(YYKo{#UR6I|Zo;)hnxRvg}0yfPvR=fDRI0Na9nG(vt{(lg(eaBV$!o;^&)p62{^Q_$<`pVbs`yZALS^hD z`)V;Q!r=KuNUNLaWXHIVoAB8)b7qU?=v)|N@cpzwSpT^N54Mm@Dod?|E;TC z{+Pn%esevP;9Q|qCi`@m8pz#0Bxt!(J7s_M_BW{#H7o7 zWszvqOLWqY5G1NYcRr;sjPAW3;HRsBk*Q@h}YfW^9lh)-bmQFi7 zWs)fCzx9+SP#UqYDh~`y=1GS2<6F$H%~vdk2!~n2;(AnCE}m@qiX#MA44$D|6-pHj zC#j$v%$A)2?;5o@9spE4*WOS)pd4G>tiJj9c_fKOfx89*2KKt=5euJ7Z+YQZIzw}= zN=4PCLVYnnKso1LlU$oS&t>%Nr`{fy^LMrSL)^eLNF-VVtfdCvb#GWQUh&`I=yEms zz0_iD-gpoNNeo-wEat~0Y7TT?tdHhIdzxk2Tj~SR97D2*ak=l9b$>0MEU%uE4bAc+ z6X3EY4jcXctw*ooGGn#uC0{|wtg)r@-mSbWR&Rwg-2?yLpl#FD*$Ep5Ws+XCQJTRh z7))`P)!O5y?Z)U`ZMB+>c?%%JK-vTe41g}v72@AqYmbU{B@)p@MnVx_2GW(J(=r-i zvcsPG)uED5{8uS~jJ1|)e$83&v^n^Q<%WdaY?W%W=`9k;Q|kYVv_B80y6yi*Ve?GO zJc~u9kSUZQ^PG7KWiB)!Bq_6&F>@+KhBAjpip)Y2qR?PUNg7C{Qtj8eyMN!kf6sI5 zy`STFu7B?Px~?wP`h3pweZJqX>D(LncBYHh+x0Wn_NVhg+OA5>v|>vnsbRu`?!4b% zBORrU`++o7rIC|=UL5}ul_(qYK~G9oo?O(!s`K)nTG=T)ys*Hoq#FA2yvp@+@^`jM zrZvpqBr;QTE!&wb@@bn^=;!8rOrSk2`h|LIpa{?>SG+g(>`m$sC<^&Ddsfy4Rw-HvFFC)%<`DK06SXU6qn zn!`WDV_wTNmJ3_;y%F|4(AzY|x}{0A&Q|<++ljooeTO**`>vV!+=@EUta9K&%h973 z#Z3gn#kCW*m7Dt&YPG)TIV0?NY|xlFRFe2LOWZ;yYQpT8#p*NVh@fD@L0aakCJDA> zq`m}3Kd&=(m%`UR?ghYDRc>*>GN+$Hib3wfn}^|Zt;(_A@QS40yfHrTSZ%r<1|YGE zd3lU&9Hn}^`~z=_R*dBGP8`Z%gEZhh1sW`B0pBk;}d&Wf{6GI zuU8kG1l7hyHzaD?PrbntdH(!BcPFdL{i0o~Zqc+>R?YORjRuMo9j2W zv1;^Uc>HGV+#d7T^77=sKR^AawE)mdFv{%H>d6oe6BEt)_I=a)XP+$JJg9cuCI=={ z=|AMFj7{2YbKdRy)2c5%zq8FFuDzZ5+s9LC2lMA_&#W$}e9038n#fY=rv4U~3nbOeaAEs+zI>RW3J}M^bfF!iLYhxs zkCbNMA?<%yr5NnJ2SDfQwf}@n+Fa$3Mt8+yDP(`u{kAAN z^VQA6f}=`eQ@!R8Dc01~)a`4RUFd+NR4BJ4;EC~&l+=rtFA+|}wpmB+e{ z*|Rxd2*{1;djYgoPZaExhW9R^v5-Uk;}gXjCX zW$eoQ?&sURJPt|K3hWTqT^hWh3_Lo0_ctVJWlZM}J+0Z}QszHW0zrq#F1t#B#T!nw zu8>({U6<&DF%p&5qy=3IyWzC=+=3*Nqku%$6Q#woCY zuO2_PZvVY9f6s{LIoZ)mPfy=e<4`$@&?f@}16v)>P6|y;O^KVr^W*XU+#`wg+5R=Ur+bbPBXxST}=6vwrdx!@W+-@Gi2ZQKv148+* zu;{6K5YswWJF&(c{<-!Jxi>IV9~>_3f>GSI8AOaUmci9p_tw$p&jt51m`Y$dh$&y0 ze)G6!8Xy~%(UmiqnS@GLNkMqv@Y3p+U;yzkvZ=xvGCWCgTkOQM@u4mmuYf$(rQVbB z=L;}qW#VcEmfKWeQ-pa)Ov$S|f!h4Rg9mMGZISRKAm8c3^A-a$Z=c*#|0Nzwsi-gI zNI)IC)u%r#)3PemlBCv<4aROTM@oDaR=9dkJvr!mq^pF4gj`#W$d5|bfL(NPDHwq5 z0GiO?pLh(2&(ii9&Z_O zJ2qtG+egAH;RK3HZ$5tf^9@rDycdr~M;qN+L+~qLaJ}KbnOlzerL>=~at(v#+|rWl zf}e6Qb=3^qt62Qfdv7=8o*Pv59T>(l!Fw_N@rmS|r@N5CN)07*!qC^16?RslZKLlX zkGv~h3Ps8q9;=FA3kaK=0Ne7?N-0Loc1Tdj3Qjj;`!Pop&cQn z7uqm{a~Uc7iw)+X?EX`GX7S6$SvZ>*=P z{(2Y8b@u!4LN6%0U^XNnA>j+|L*DIX4W2T*B{@$ek?f`6)lEaQ7cT-r?HR;c#l^>$ z-=0{fek8*oZ+%%yPwvCwq6=yj+y`(=J-L71qRRdeAF|tc6FBX3cB&nkpm=T*y-&{R zQPHlmMg$Iv6WP)m0rtzi=J3QJRE>po|4(69`me0@ex0Oa6(BF6SNvi%E)pC^b4~fr zFT?kFPGPSs2!Y(c=b_{j|JHu`_iemFozoi(ADo*59cBIspFH^sq_)3vz>VArkt>D* zMH3EL+%pbx``Xq~I3=www;^OpPQj6oP0{(v-Q68JIXuGq371FTVQrIjfUU=_wYK7H z5?*>*`)g@@Yp=9)maBBYc-6S{76xyaC~zcc|RVKQc}p0P^5EzSN| zVX0uBUWGLWTbOkct`C$WQ->{*3@Zm76exN3l2BO0V`A0eT24w!(2szPaE!EZ>d=c@ z4Uj%RtJ{nIV^^+(4m7=~*(ix5I#MU9+R^>{B^xRBvCX#Rn$;T8h*0_S032w{ zvr~xwIB2JR@e1JXkAsBE-Htr;tQz(~5xWyP_FJ63(`~iZhCq>MPML8qIBOB=+ z)qv3&C?}9scL~vSV7|L03pJ5p5%K-wr7d{K9UEfD#3%iM(a^ytw~jGU6a&J)@P zpUTy^4iU1sJP9zKm*!lsTs0cV1fx2>QSd#IsE*lSe)Zag|gC8 z6}WpGl8xYzA)Ki;+~1hEqT3{KKCMvu`yl z8BR^lmQY*DR0I>FKFeP-$!1xF?ML7psX?G!Jcevn<|TxI*o&dgF#Qy z@fIcDlQQl6WVn1rh-!qdGmQbb~R=UY1P83vATT(E8B&}#~P4H zIq|%uwKa-EFd;|7th_{;Yui2{sR3mBUAlCsoCx_}ysjwQgNF}|crt>atyj|C$PS7) zaiUAmKt6PN!uFKT1{Ez+ny}_K$jxya!i;>7ft58;CxMj(d59AeF0y%pII6Jx6C$|Z z$im`4w~$_FrrY*-?1F}_+fEG))AQ5Dr>;6>+nFYu7|ot_I0U<*W0k|6j?>zss2?)e z*FW33ijTd0^aV>7=1=(Y6f=uoV}+yiA4Thc`Z=;sasLB8hs4Ch!!K{6;MXCY&L52j zPS=i8zpgGDBfsJ+9X_Y5BV;s>l|yM5{SfoFww*bQy4=x;tmp;if3cux{*PlhRX z$dBm1zn_79bJ%@Zi(eBxn_EMdY_C=2vH5=1+|u&gbN9)M1)5)cuq)r-GbVR(Sa|pI zZsPmE34^sP9PB5N9T;HSkZ|!RjQf z!nReyxy(Ge7>(0@U9ES|%%@Lhb6U`)c;82vsdgvsSiL4t`%M>{5(3IiX{ zwtZt^Se9Upe@ zgvs_(LD#LVJU_k=&gxW6i&~kk(qw3=s&akY^iIpXwNtcPWuKfeI~iDEAu9c)^2WY ze&;&$5on+!V#>c=alhwc_tfk?ga+hE?!EvwU@Eh)M-yCL`TO?+GiUcye%oeei` zpm*ZuC~=CJ5y#$gQCl+L^k=zqN#|4~a#lro*$+Q|{=DZiGF-37C$i&-3(2z|(A>GR z+h&EaboV(0VI9Yo52S}N`MP`wK}=iY$`XpXo8w3%hQiBrb#$&xJiDg_Ivn`#z z>&JZH(Mh1<@>JBVVcfKJA#az0{?@9$JNK0uvmQ8bAnP<*T6aaFPnp*Sy5_cHZ!;>W zpvbE7=+KE{EISnyHO%olwW?q^s5JlqwAiIN%7JMj+P5vvDOAZDN~9O_&r^<)!<(?P zbai7Y>|zU$>-y17l4)w=C&_=GFQpobM^>(x$VO#H7W0=*jZ@N0iWXltXL}vBGgt6{ zO$_VC$W=%uL5|4Wo5$IdwQ5c{Fjnj4ydk6mV?CVXdRJ3q5nj4oj`&fXJym>;-O-j` z)!(Mcd8EP2rohfPpat2dn_->ju*-74i;9D0irKzbva4WRoqDHULHjL%nemVH z2DUbm;}lw}*g_E-`oI%Gs>D>QnG_>|wWV?9m3C7fy{3)Nv+)B|w+>FE6Rdv=32B?Y@ z)e8r22~=MNn*$`Ca02g^G@XMw)aM3I!Y%*Z#aVz@Yx^0ZZ0mbADri0_`HhP z206Pjl0O|zNns(O-p5P%`S})1i=(Mm6EeowZwZQfZ`+#99-HagBg84vR#815S&W;pd425<;wC3%T&ICk7ALxEB>`ug6;R?{K&))G!6C=lt{gmi<%^NcAa z6HI9vvI;!iV|1BPJ-1~ht<~CJ%lNt9_kRBF-@S#(eoT*EU_Vs9N`_TcyVnv6l=B)L zter&~+f5tGF{eLoIeO+4w$P8B?h*g125;x(!f*f#T~EN{g;D7W@mlH`kvpP+-B5l)!hSqocFiCob?vhSln# zguyC=gO70{q{zh>>FLA*>M%3vNZ)^LFQRs3w&d^&3iiBBeO^{x@(G>pHfizsemDZf z6CZUX-MH}uBRKMiW3qH*i4v_L>z}>E#Y-VRe&AFJ9OA;!!Nuv0U2(~nT$+!(6bOER ze!frTyRGm}UCSETmX?-Xr+$VuiKsahonC!yMl*@sl(!mK9BqgYL1WA7c?eU(p~fbn z#W&9yrzk(|BPscm$@XHPG`!bWCvV0;o=7wOBC}ApSSxD%Gyb&u?NCOs>pyd?T!~GE z8a0ZFVFB0l@5diGaG>SbTPqr9S&klgRww+xrE2|rfz{@yl&S(XgFdVlw6JvX&X>Gh zXs+D|HII^7`fxy^l~R~N{UX}F6+5Ni#Zv8`O8i%D+ux4;ZLK+8~k2dt1?N z3hp``g|Y54KaA)ca&h*f_wJb#@=~-1)JJ6}bh=p;D0V%6?&iyWlgjIMHwB7Ab&V}W z3!VKSkQcTVXw!pQxn&(X&B$=rCL%#i)X|W>`*_4W@T`>c`ek$%S&$o-JS31#nIhJwY#k zxpedPj@hvo@#Y&hQUg_Rjxo2R(KI*HC-ESuh~KB|AMQ7G43j4?*0%hAo|W8!ZxmcD!c{_Rj6h`#G+!EKV}M5Go6@raI0)Qe%2!%_I~;bAmM zpWk5PviC3wMIt_nzy$pnwfR?^9R4>jLLV~2G17^_ zws*o0A3S)la#0go?PfzmLraT^06jxL^1?)VxBUA4X}ZymdASu$QbkJSx+gUP9nr(G z=ZaBfU=&Bkw}j%tP|#~Ffkq^;S(L$8O3}j9oI$OSea_LxdjHpVrr7-^i4&bki=C2EHa0$Gx^k&hteIhfj@jT|4?~5bk4o&f7VZ4TVus%BDPZ$O#P8B9iG~>lQzOem0Di>as zk(3L~v;p2~&fv;#`*bIZ84e&1o4zEaBl+V9jde=?Q#GEpTBAxXa=_xPw#0t&AR|uT$#?WYztA;=agaz*e}O zidiF)hM%Dl*pBSg6k2^LQT?6QY37-DFkG_Foh_)75xY?7d|kxpjO_;mpYw4LxVvh7 z91IfD>l7=Bt8j||LQ@FV!(QbRbTtEgeSO{C`oFvAD8KQtf(S^XMbO!bJYycSU2i=c zg!wgTP8R&h8WY(1TM!6g*k)I0x20F%g5PUkm;_zjGO=Y{e}wt)6*T!%RMM694N|2h zMi>ai`)CKv=(4LN_xWUJX~+<2JoTFNJ|}40LGx0=)Ss-&bbv{XgNLNuJ!uQj%SBF= z!irdP9H>HOR7rdNu_)@r-35M#cfc%=EGs6C1O4m(qu^OZ24e5ir)nrZ6N(8Yq#0z^ zr|)-Rx7rfS0}nmhtnghXzwc&`ivpWm<4Vy8Y~Q?jvvjnO_j)_VuS)lvOP7S%7SX5A z%zcE=L>!R)7=Zd@*N4g+JPd+8?1$#%k~0=H~lm1)~nNa*m(ZXuo2j)EV;bpfZ+2v z&OUXZSFr1(aApxSXrkEk0+TxIDdJw4-X!{f(J~qMylbp}ArT>7>`FAtEe+mcvC>P{ z1uMEW(1Go`Y(h-%r`8g0`)_$|NSDN8cGSh%vfDu9+b7shd6!Z`yT{j26-(MtdIWUU{90{BmG zSlIZpXS@PX(D32%1zBM7(_H5kl%@%1Ts^C>Q=@C z`ip_ABK`w%g>?P;Cpg$Yy}a}G-8-Pi4^ilWBA_&z%7cEp3}z7V9^GSO4nv$Ag7x`8 z>V!0cJi%)K)5tMr6pJR39f<2v(SJ5@iu^=Y1CABV@MR6OKFE(mAV~7PhcGY3;kQ)3 zagj7UiIx^UoOnBDHf*T>@vRY-mzO~noto*41vI{lJS0prW10Ukm_^f(`-gwL%KyLl z{Qto8e~kUldAIVwa(Vy(1&R z=p*bTyBIcY`UFhkrzDa|yug*95zyZeZYZ069?=pH3zQ6oGIw3-RkG0M$i>%jsB`}T zG}%t)1mT)(5`lZEf$4`ZS&iReN=_Ke%eD0m3=BMSv>%e9 zoiJ&2SMZxr4GTjLceXZrRe5r((!L1U1fXpYj`DUe$3%9E#0kPztt}E94FYBWSKp6S zssP9gJHW?1HacOtD)q`IuY(7a>%g|S%o6NFJ7Y6kr17+F??o{KI+?#G*MI&zjUZo) zU}lT&F;hZJ1AR6)mmDPEJ-DQa*76ZiP)H~W=K>1hGmO+Y->@Ip7ZM~mODW#8B0Cge2zz0% z8z>@GR=xxLu!@Xiket!lJ1=~)7ELgO*Q}?%-*`xZCApr7dv^J0q zfd(0Pa9@~@;pz-8EFFAE&Pg<{SHb~y0%b-I!JA0sdxnKS1T+nb%N2DjOYn!|b$b!3 zH;KdWoIqvp-#@>R#kcG92HzD%rxZ10GQPl=vL2==D(Z=cir2GQCu#tY6h=|t$8tP0 zfWhuHlBonnM(iU9SP$bqi=+?}lY6*p1dD1@!16Ql;&H$A8KWLn|MA6PO2JZhS2FL4 zZvm3W6F&^D9L%yx+b`o%5ztwEc2vF?!m3?uEm_ObI1au3`StzE!?u&(6#!dKoC8mS zJw2bw!3t6;g$|H;-?M#4SrXBXBnN#|B}j_M%PXa;&3^v+b?@D%ANcn8PNbk#ym!o$ zT#g!xV52&_!h(ZWR#s$On--B$i&jE5aQimt8b83y8r#uv9`y7Sg?He@lPbq*08?ac zQW6YwO=+n;q(`yT^eOkJE?Coq?dv$*j#wH%3SF-N9KAqTBA=k8!qgXsp)yOmrjc$w zaN3O4Cl`msgp`Gz;Jd($XIS+#qPIa#NLcPQnju9#A(Po5PkkIACx3mDKZGG`*1sNO zC-BKGi_!yYF&rb%sNqvsV|h_`q^pKgemfKpAXDYwskbHxzAdWdbDin>j~`ua4Q5~k z?^)q}G0TUAai3EP8Y-?vWb?eHt%5|)I@P8VGo6%W4KwHr6+G@9^7691v43|IH4+H3 zjQMGr$hA7;HG|fUoj9TtjOjH_IH0>FbF~wxAo{Mn-qls$x-rM8TWyLde)21MC)~NC*~@sBvhsoiQA0Q= zEr`L>729a+$&;Rj7`fakKV|7o>{=pKztSmeQY2ILW~GGb=>cKti26~|=vxn}yLWDw zQ86B1v6oCCgA2i&yP3Sqz)2(ADeYm5JP-tC4z8U%7iQHT+h-FrG&Qj;`R3@a;<_j1 z!_-BhRo>cj^|}T8FW6M`r1e7aN?mU?f}nxqflWw*a7JWyTVv)0QnzErvELb4#1Dq|!u$RuW+~yh38-nAyBn-Rs<*`Ra4topFn~u(X_@I4y zBLY}+MHgsS-GSr~)-!w+XP1L&>jMjq*j=(j$&xP=2lJA>I^AWa6uLN!nj}t$^YW?J z30)*S&5&gqZiv5rmQbRN0XoNy(U@4H9|Qy#m4_U-GIW0-^8iXuk&;i+KsR$wQHpA( zbVfF=9ZHci1|@JOwTYsEN`QujMl?NGARysoi8*a9_lCyn>RjhWO!%s&|NhY)#o?`+ z2^*58EiGXU#~XDri9|xXOpG$ocZkIjPo;?~1KN}t>f*xp&8UpBgup^gOt+=~wLaTJ zpG7Mm;FDADgCz}>AR=aldv_nEi8n9+K;);7Er@GD*Rl$iXw32BL2#? z_M96T<#_1N$>rfOU0f`hWlR;kfhbHP9(v&kc|0(nQw5o?itYx-pPu$0V$G3g7RrsFe=DyrNW4I zMoc?$jUnKniO~ITpQb&+aw*-(Yzj_3!*4*57nw$FeJS0y5Z+Cza*Vrn;uSOyX@1)6 zV=d6G8ao~YJSk`$KP+!GLsm z4qSFN$|oQ|BzJym=o7s7mhx?Yu?1h`9LSN{6zG*ntUjT~O%^P85{}c6ub48o6AJEq zSlKg6o*NtC&>iH1b1vj42_NcNtugSXiX)rlWS{hhf*l0Jbe374GCCK zW4BGEDcd}9DJ?A(r#jWUW*5LR^StLR!Y_N-;=ly!%J&q#Ut0S1?g@;a++Z!Ohey(T zdHGavBE3ZOgWrjh)s8Drqqjt_EUO(y1HZDb%}Y_%w?bd-B;b;CEz>o%?0-b*Du_Ps z$H^>{@BXS>7pjC-SoP_%=pa^HS5;Q#nDj6Rt*fIJkEO$}(OgkscxaU8&$*RBhY)88 zdeByrO4PB8TRu2YNUFZ;!gsDBbmuwYtK?CLoz;|h49qDQP;w#}PI*))C+%K7ZXqX{ zHIk>H(|uZY-RBb%%P-*CAzxZhv&UX*e|&`>&~e~INrk$*=CmWoJEnLGi%Z~&@OV#) z#QD;Y)~U@a{>e*$V-~0HnWFdNRdAnxq5}`XU{RmOoZB_#tMPm4zE*ML9MjUYKoUrx zor7ArZMJlD@-HVllw>A@$Dn(l&>^4%H`;*@mPf`U_z(#wn!rq@~lIEsJ zGZ^*o)3(6{G4N&}YaU6_MAl3-C8favrP2WbK|y*tx|F7GK%yUZcYC9|L!v!dFqW%4 z*6;LVecf{}6$_oWkqghkX+$dc%Y0s2%e4#K`0{uc8Cw%wBV%h_k!3}n#jjjZ`o><= zQGYRxECRbwWu5i+$Cm?+iU}`ceYH=lmNgZbZ)|L+9+fu}#W@8aB%?DDH3CoKjBr2K zK0~4vGqF%RY>CS|3%shnQi^^PJ(~PP_WZ5RR?_sWQu-3ZtKjG=@}|xgh<>x{``8hF zIh&^Y<;%T$w~O6Q42mn&b^Rs&hj}9-OO${>gjYB^F=hdPQcyT)%zV4=TBI|Qdi7si z|06et?d7@Qog2HU_u5bCW5{nCXO+ynK2eVm`!G`Kk+OMFY^aoWT5QUrEy8yBl5X=p z2e0Kt1aAVN0pMDrvy}Ckk!=r9I7!O_Md;loL>ez_3T{$8G(lkX`~mF0!m0K`!EHH? zxi)IMeLF0DWY~tMAjTY+wg4SItBXIeJ{|q{5?BYcx5KtTrNcZ|ZmvHp{B<|d<>4ni)L)h~)MR7~0O8-9b2neZzVwh4w*0BGd( z+Co-AHXf@Gw1I9dM~ptC@vF@Ih6X29wg%$*y7d%{3N+u>^>&2SdJ8MXOkv}co&nHu zyR}v9=RM~$Ur%qWk34yD0}bFr3<5%h&|kUnJ^8vd+p;r;S*3GFT-!S+R?uQJL*k!(@&LcK@^3C7!;q349<)K>lGA zPE}dM8^DZ=kw*Yy#?LQH$rR|EVp)4$V^qC^+d(y47f0keJ3W>AKl;$-1I?@4Sq$-n ztENVV2Qk6!tZILrzo9++1ef^c=l5T9Meb3iVfV9V$I;XRnZJ^R6s7DE@^x_peU3sv zC6}~MhNEi+uN(N}YPthCb*juVd->{93_tsBhnfvZH{870KOkV=nkyzzX_nw-9`TIH zOemt-(OVfTA4WFtB?nR3u*vhy&4kQGjPGA`{cE)tV3uNFVPT=n57W{zBp#;xTcBKp zh$ywveaP@07Vg3Esx5w}uY%&#%saZ6l8;K#ioc{iBssa!SA+OIGSxKL)uktE?(V*K zFPWUc#IdqgpO1NjhI$;t@9y2Z%S+bZJX2dfE5=@^agQ-uL-Cf_zgvpQ=_KS&Fn7_l zy@R?|np-BzyfoJ&6_N67pCAh0-7;K4d=5$6$iF+4k(bbxX<3wB_(gczwr!Qt`;l=w z6@3lNsdSbyQg1434gTk@Q;uyC_WV13X@cChWB;F!65Ym}ESzYszNmm5%33;|{Q2`| zJeH?OY=DLjr)c`mir4rD(5mGEQo#{sjc6rNQQfL_{{KWGkp& zeA$wD{2;)Ri$K6GH6z^DoyYhsCtqcgN1D~^g?XH zJB!1~YIi!;Rgf<3(8O0&(E4{Anp9qk*=y|dCF#G>I)8S)HtWStQU1fibs;H4{=E88 z5uVsLS*syCMlt!FQx4g|#om--YCz8;>#&G38G*<;QT~Syx8wSZGBkZDbr8sA-Ua(S ziYM)K)2<#mDrqIuxU%gvB`7$MVDJX$;dDja*aj7|h{!(F>k3Vo>%NGRc6o<>C=>Rq zzgYdWgHlzUXpsPwNcoL*8hcklq-}npRY-6T#xoo!#1FHxSs;m|&1`Aw1Eu@%-z3+p zTeY>f8>u~I{l$zcV$SE9BZ2e(*4vPe1c`~q6&*r$vI1%>C04RO9Wg{f14KayF$?3O z0WJ#zLTCYShG&bNu_T1H9qsMy)z#Ixe=}~myj@)M|9S~jHI(ti>bVE^C93JZ1dmn+ z<&NDxGc4G$+z{$wI*VLsvD#Nd$U|TSWSLi0T70*rvQp-*+cH9Fm%-_EvIXOA^FI$#J=q>G z`WlB`iR?ZNfFY>wm?h;G{xWdPr4r3(m;VC%H-)?8_`6X*obn|b$8FSq;j4Rb+eTlK zkg!4Cm1vU0NrAx|LR6R|f&pf@=^8yg~3mf{L2hkP-VK8FeMDXVxi z2jFWk2WP^}eymfppTBsq^ngqeRo9LZfpHqf6{9Q(6K7}MGvf~)SPtEzNYmT6do^}f z=dxJ}#ZwK4vk~d+ROMg>;Yy{Fnp*$0tgNhoz(EYJggcNJh}jkYIY&VEEHi4#F0sO; zIV9-Jz47N^wG!ndfCRdQV|ZLxpZi)vjH+zr-oHmP`4UAAS6)S+wM3T}6O{6E-UQEq zZj*?X??5KDC|UZ4Q4964(zdi8P>XG~7dMoge?{$4oudH0N=aQq|4DY=M6Ar&eLYUN z3qQ$wSP95gz7hgP@;zBuRep^qJO~Q|DAkWYs|AMvD6@viMXf0d62%=wtQ^SWq&tC` zlPfRA4Wk|3jsQ7EL@wwl(LktWlV<6Mc3j;&!u@baF+u~GfFEsx;AWfl?|8v5qZCFbMuATjRUqwgmK2qh0~_WUMcgi=Z^D0tD7 zvzs%!iGg26r}-^b3AFiteqSWmOEcWGpQFh)lM~NVuah;^xC7_QZb-ziz{&R_o;-OH zCsCz7aEuQ?Y>HVhthAtWA(eyTGy26m1l_IZY%%xAuS?sZ$8Oqz+u$RTY zQN|=tfjqRyn4lb@-j_bd+SciJI?~sZuK-UH&$)V-!t2@W9 zqjR=#SISG3!+kLDiJ9j}5y<2Xki*STP=jD3kl+QW#RRB9A4~<&hz`iZ`Tq2rsX0EIIO)rJ!8tpewl=$l|@oCpAROH zbR}`LWzq=-)2+v(reGQ)qIJNRdxz*{9K>7)9d(>+OAHx9-_Om>&ClB-vl@~H2x}e3 zjOXAibLk_49s2qNPqP02y-LZ@_;?t)dPL}7y?PZj_v1+EnI%aQ{vR;cYnc8(edEB` zgV7SNZ_8=7fLCp;KTmzqP(ahVo3z8*}x23*k;eA zmKJqO-nZ8$wz2j{qd~_U1M;vES3kG}fG9CK(YWwQ$<>9oP*#oOjqNonVHY_qmW;-V z^rvB+ZD=@|o>zNx-1VnR5X6OTs^sKAGU5Xyeby6WF|&oDy1K~;2@~OJYXzV~L%19( z;UQ=@DW_|Z3TC0r0I6@yVMPlF2y}B}Ru}wWL``_IpL|itDKs^1s?>OUXGUOFVSHC1 zb)l$eGqE45AHvF+8ol^}({9$Te@siq4;7((90Wv-MU>eeJfdhA7!>U7pS04cIFkaw z;qr$MUMaG%0`D79=sG2@&`=)-SNl`1mnsz;P~IY?TcU7sa}hw5u0*s`Jc64pCa~iJ zlW&?*JnBLQK5U6Q(*i7csVRlF&q*WP{E#K66L1Cb>3V6D$K`o=MVY_kE1M-i*XjEf zD`?V_RU?GT-ze&(z!0NYvKdZ%h~jAPNj1jC#xlsD!!29Q!zGfPtvevzN)Qf8<$J@P zG{+gqxI$0GFk*R$>|2;>Vw|VHaB5?nU7U$2_(G2i6h}{VKQKN>Kzck_$1fug?(& zLDc*$@h12uw%8&t6|{5^eL-m~eYk+O%Ql$~N{1h3JlJ%0KWy0X@+%i*!~ z$a53YsK=<_!ft7`Fxm7X%|AJ`WY#V2c7e{RomRe4M%~YI40UguiUV8Cz$#OS=ui z;A8_8k^io;KH~7967!k)dGYesArWwABLO$^FHAy$>O2A5q*E|PMZh5mo2CK1w@X|L z_Z|&D7C`{r#8f^iVWJwx9&WT6fNA<>5)vFF&iT-EOKs?=y&4=elqkuXV_G#HQ5QGDITcUIpOcla1N>N8OciOYlqSy9@NKmW1n zFy_bYsO-3|u@sP)qwl~7X9Z0TGb5v(0Hr$OZWMHz5-OM(6ZBko+LJ?K2tscyJUxri z`IZ!6;ieq!?4Nfpz?d_7A>CtHN6yKioZ$~$Y2tj9&6RFEp|Upjj9dJVb}u+@zm)-l z)=WVpSRGlH3lU#b1Pln>&yqthqR=;m9y?~>`qI03We_#p{&+Ilrh9W|MYQ!@L$}=K z?sUif!?b;*rZ*3DgQjctsMsoW?wfDoMs*XIix}XO$w~XslcwhMD=i_3yr|+YL06#r zRq|NOOA}uzVNz(#{ceA+y(LVZ%)vWN`CEmoLO>&!_D*ezYL@MWEI>q{`q!~gW<%GW zWEncD3MX4yQ75dXnm{ekIAqE&G(;COe}?m4MlmxhjDoW@>_Vg(+)vpSh_z+JgSlDP zT&AI^DdAjO@H}1jH2o%#sNX*wt8A#}V_|MY(I;$$#w4X1+zF4IOFb?&B{C0VZ|a@m z$${#oQnLL)j?`I9{^!n}8>rG{q!VQEsd`^7idJ~N*Qsj~gQz|i6%gJg!-U$~UfabkgFBM;tD>7$0lOz z_%EY#HcVeQ6BmO%yuobj%1-1f6esnUMX`_$CP9P6!9xY;J7$>1tKGktYIPljb*`DH zaV?S^ts2@z(82A70yu8nZ#v-3o8_JVZP%Bf}K6!YU3MaZ&oz=pf2u8yyQPD zh0=LEG_>~*QRtkx85L*sDdR0y#gv_R&)FuMQnNe^4-fAi_1??la~p7-X*@)fxX1Pn zC<^>fQbPP-p0q91Lc_QC&lKz#ra+XKii-^NnK3(W-oA4#mxcKsX+b;Rbv3!Q-n}HRai#N~h8E7atLm?!E266UVs(a6daZ zN(vXZmNYOGhJq{Ooa>sLY1p6>X<*QK`|zSv^Ph|gN0X*B8a2tO5bg_touh`eZyu6f%To$n)!;3m zO(EaFI$ZHjO8*kTZ8=kRCMmw6OJ{pLt)qd&?a|S`%Feltn}@KG@YlUG{wKI^2v`d4 zHe=UkTL@l~TH05Au6XN*d!Y&Z>s-IGL&)%;p)~*_B=x3ra=Gl;6HxGo*Q=tas3<4L z9!TPB@puu*hF*jRYIW`p_w%;4guQp-%Kt}qWmcB3uA^WfmSB60f-9`WxJIcTHQMyV z7VMgJu8zMSe*cm6jd?iHep3CLRgX)#{(~Lt>($%dJjxQk2M=snnq`vePOe?op*tsY zO?)=CL|xUt_kC27xm~C%x9WaKzk`yKZD$K@+dZ#1Gvw~B;x~31_KmT1c(P!^%d|5u zUW4hfH%hIZFjiGpPHMW9nZeq>AH~(Sanlx!XNLDpRRhNsu@ce8?uh==wq#P|lD_#j zf`vW16Br?9g=&<#v4r1Dzqi+O&V-UOBlXUmJGsdZ!^q^4aU9*^6%69uk}46V78du> z>zgx6>#2ki^X;yrTle=@yw_fIT-5%$RemY8bc?UN#O9keU-r+qudlt!S+XJ&R@J}t z_Xw2ld=_Wl2#5e^S?`|sW>annvE*@`W+^A$xAXIekEE9o&mjj;fK-~3^)7rNPOyKc z`wVViCgn!3K_yyszx`*9_lLTyZaafZ2mZ4?W_}SegwX$DEfUV$R(c%63+;aFUkr{6 zL!ee~ocOZ8a_#`yVHJow-ZC|m)Hh^177`MoFBd1$+w6CE0xS%M z&0%h;kFYv)GeAp6rD@`b<b>r`I}(Hz5FY>)ZH zMW9J0e%E&)_cP4i-oB95*x0y=!R*G0&o(kOCERsB^%%X_X$M<9j?I{{@oIVk9$eNI zG@)9t~1hcmvm<=`9`k~!Hewg=7M@;aiur^*UN{|r8y8A zHT3FFK!Sr7ED~d7U$Zdf(?bZsd3+g?uUWusfIy9kJC{rK4GO(xp z(-U_Ss(H4^{wc5aMJB1N^_4^k)rP5S-+GtkMBl>JnQ`R{Wb#36^(Su0tXm$=Pe*Lx zV{sx;1ouA5<1DlvFI5lzU_#xYa+S=R_w@K+E+y+=zE56dAS*tV;v%SGl{YjvaHWdq zjP6+K3`Mb0QaF|lOafVu)QwxDk{m6>~jbP%M#9g7~nuSx2rI(P&OQ#x^G&cS+Iu1g3rK5`=^dyD0B&G+*o`vT;5f0nfx#?e=Hki-iG7p=Ob4E-w|M46V83q;;IgoKv6uz?7keh20yQJ_ z5NsZ)CgmRry#jW|PDf#blBbSRAexx@+9L$02GBV%KT~D$Jv^&!{|}iP|6pGA?c2Hc zw7O^b8<#mooIHuBm*XIJFhillh6DxSlzRdpz!llw8yjWD2@(?U*eN=wsHn(Tn~nkm zjI;Lf!8O92$H0)>@ajnd+K`6#e{>_B-$5o8z4+vc%P*3J%4G)Nr% zaLAAM0^jZf8p-u_r?dmxB-Kr{cu>K4d+hQR78XY1c^=3zb}`anc4DOg$3Hq+mh8U)G;d()A2e4@mM2s@^DfBt z=5N4)4$Q7K^j$XMsA_BF!@IBt1I2QX-aZG2?j#%qK#eghpc(MEYRPYlz&+QRf}QQPTvJ*ubQ%`XfcHCVChUO23Yu7 z{ey7$;c>tMs|qt1de#rXO~FQ2n73}288ZvUJoHpiKJdsLow<++5}h;%4q~T3M*}MN z@(enz@f6<~!+2N2M_l#`A4={i>5t*h@gi_YdK%%M-HT1)@6k!TBM4DIb@hAvF7i^u zkZ;`l*;K(o@M7zUFOrclQVAm|*`ODWOg7RQXRHC@C1c^+ZUd*nsD1JL`K}LGPp(aA zhL(b7Wm)U^%H-y)uNVt@cr+%JF28--0x&&d4AYp8?sdm%o*E-(=i9xs2TfppOJG%u zSa&Np-`u>N#Zq-Rgu3^zJyZ&^F7=|8>Uhm1Lf7bCXcGA~4lIlEn7l1vdKlz{h3n)? zIVZ%`{lVnq{(uP+d3EKhv!0MyXT3?*+RXh4_7i6{Nh;T6BS;%G;1*13*!|dJIUrGc6$kv$SyQ{ zq;#7*s0#%mRfUiTx3nCGw}_5~k79FrEONX#OPFTa)jpw%TNgsuPGpZ%62GnB|H0my zhf~?UZNq7xP??D`&+}A6NbK$m%9v~<}pQAIM*_ay~6PkSqk)7_f^ zGsCQMzfP$6-tx6P6))MJ&#{Kj&8KbNI0mfc!H%mV4BFtCgU+S>Hv9q{QSy=d(Yq+< zR0$s~t`B^gM}>XEvv^Jo^Oi#Bl%pM{)wo7n-TD&@D}L70)R4sFmBj7+AED$++E-R| z!I}G;^)cH-AJy@$V%9AEbNR5vZ^3@n-=eDO0=c2}i$o$R2M%nEq+zi+4+g6NX9eo7?C!A&6NK@lXVq|f;)vA&XW$0roN>aE#1vNKgdKPp8 z%e8`IzcRds!&Z^=WJJ;OO0zDA)Qo?ywO??n!DB$3DPk&hIVnq?J@aKzn>U1+DEAT1JO|^b(s?%f3U@{zF)Lst+~;sQpN9ObL9S$( z1I>~edff`I4KAyC`7F?8SKO5=dx3#+b8`#pg5GL7Nl=){IK4iD>m|8ZfndTz7i6A& z6z{`#ZO~}#eVWeHnIgy_s6{3l|F!c+u9g5=#7mV>D8+N*bAtL)99D{FrI-Qkcor{SJu!c=I+qYPyqvYie*l0 z(LYtRPKc&aRHA}eN=k}>fk8sgMhi9J>oqlO@4;IQS7W~kGFVYgp5EeuXIRYNg^ZRa z(If+IX!Afhu_a)c>fpXm^cX|c^LPB3)b#BVKk%LxVo{m{U%__OD0r0>0W(f$n<5Kx zGLiTk{tHwB;$GoZDLb8;F+pWJmHCa^5t65hZwv6@1S{R1tsWZ*84V+|$U2dTb^==I z#Z}g#s-z#!#w?>-c+1IS!Z!aCb>xLtJg1!OB~L2eOKHP$6MZutzEY{n(_+h~XGQ$v zJAg#6H5^~>z|kBxyh~Nnf0;C0d%Wbb?T^z$5{&#BXvS%_cH*aS(So^5(c>FgijXA< zG7KGZ^GMB}*tK)T#9jxppG6A>zFg}_k)8xUHp;1+x>l|MSw7?_#pBtPH*S3Y_AU9_ zK0BZ!cx)Q3kl@?2db2z)f4IUjx1)%;kS1%xt57D;jfEUP_i}qik&v%G`%KCF%4&Y} zR(9IOk6P+$QrL^KT`NzIMt%d{OanE565=KLGi4}g;{zR?J_s`CZxgl1jjg5~lb5W~ z01}G3z9vmMcd-nD)3*xLyk6l3ezqB@0_8{#HgMjT6zaug`ur;&;?l-Lxln2P#oH@@|b# ztufj0OELO<9=HSZo9vi}dr-C(S4o@%zFy71zHcNjaCa+dYrBI++Un9+xgkN|c*w05QM>~3ebnC0a4{mMjS4~vRHlB}if+Pnln};T za%Wa0seXWV0PP(|j~;bDP;+m85aceT;nmp%&(VlTP{S}ca#IaAuwPgid(Aa5yj1@J zAb#s298PhkeIY%+4TzIoU$1o=1KPQAwR-Z#o#&F&E|{x{o8DG-sS6s4sFOb^rIGLl`Ij?ORKh zcu&SQOfxpsH7KQVVsl^3+(c5(j}_Pw&<`PjdG~s{N>(moND5M8OpbpUT{B6yLfhgr zba%*yp~hjhm(M}$VUw_F8iXL6W%+7mRvlkRw4}FRXB>-lbkLW*p{NEjKK$H3cqXcf0IUvX%LX@-;tD$~!l81B<^i|9u-Q7Rt=iR5y zEA3r(nD0ZmQx)YK&oaM_N?vBbbd}TYJ7L>{23Q#uK(Gf_hgUXzgZ6-?Y9FdJPHlaC z+*j7OxwYUG(G#Hctq3*ODtHAnB~*x9zN|Ew z+^##htgR9P6eitx#mkvzn;qDgvz zSU99?qbqdd!ZN&#gZs>x4cvE0D*nCvpPt7UV<$V^idt!r8n(3H*wml8GB(An1{qI` zzOHOMkGscauTx5^UtvPcK7XF9k8mG)bf~T`_?Od0F>Z^Zp`js^#J5eCJh_+Ae!;T_ zmAL+fuq6O9RG*`Y*tFh(hpnV5c1eQ1W5{aY=7AMiG5a|RjwAd;4@SNt6|E)5&9PJk zB3#x24Bk{Kd9#XJdPn}H$NW2xY-^UyVC_xaM>e7BDOb|Oplu~`a`%eZTf?uIbrQ;e zoHR<5YezEn{F3PMeuMb7Kcis%feeMh`MJ5fsn3*@c~|B+F?rGcjFQw#48QXUSa)7` zeF^7D?`j&St^VwiY?ABhQSmP*vHpp+5TYe`en!HdJpo36whN&v$92ZlkBoiLfjmPX zpxGn0Bky0hd08*xG`;w0i^=5q6_?gPRbjBf*r?xVrC8qRJ#(tQChhzx%Isp8l7#Y2 zV_iU8{zgJyA}GIdq4j8J=-Lg6aH}B9`fP+)IRDMYI_b|4#5IjrI)GPwHxGCm7&dZr z#9)a@RNz2KvaSVNmC9y9%_75XSxHYBL{^$0ldUv_ZS9XAe?;aFro;s)6o{#Av9n?z zy=(*tH(zEk^B~)WJ0ZhT_QxM|Oov?aJ=RkZ#!py$r?N#C6bu73q3sQawFz?%p zWszC-?cMbICrD|UJZc9h+cZs}Qk;43Wnb!Iy5Ukxf90@SUro&JhM2PLj?X)$AAB(M zXuRusz$vG{``V>DC%lS{9yTo9HqRMyxMGnkWSI7oG5*u1-M(GDN?|9*IAquY4~acY z|DV!!BGcyOOcz*1GxRAg*ECZvmS}soLN8Yr(s9X2p_DXHhmK80#jy!GG2-G;O##h^~%8`XQ+*XwLk-ewu!fKeh=K|ilQE#Iys zw|oAwxu5smY~7a{93}SE^@l&+Nq?Tgc?#2d6n3g#{PiRKZL`$@5yNEV7gw(p?>rZ% zMBGlatU_PkK6@kJM3KY3lpV5L4_>~Nr3l%a z*}hkO#2m@beDRZ*>v+RIRAZmZkFMg-6Dhx64TBm_3#XHxC0(&pv0cz-iBC>m)x7!P z?1xP?U8xc8pSOq2vnhMDY#x8A8~KD?F0a7j!7q4~=V|`zqcjWneb}6pRm!crzy9F6 zNIQXa^PK%^rdi$2)mIM$Yb^daSZP<%^17B!%5h+i*Y*B^lMkMpw=A@2E~RLeI=tQ& zP%nrb^$B_h(t!zH~qr%+^h;rXqga@&Tl94?NQfgPB!iD#Za zP0YTeKQnnZ{2fMxR8=~iksEBey3?}mq|9UHrLDC(e~H!xy|jm|xoVF~9IiPmV7h{^ z{c*z#lFSRUZ<9W>>t(g}K1q6*{u)zS@>D9QSFeuj+bN03IPQCItdb0v9x1_$iN}wV zBpv$S4^Ok(Z@;0Hr}lN8qHljAp#1B%a_z43a0-pRfpKdVx!yemdW*%j6_~pA%*Uw` z?IeTw30dZ?R$J=a!&i$5t^Q^@26=tT3OraNZU18m@zW4)mGNB`%gmX z_vy)n__&?DufyYe!*#jDXTx5qO={CM#&k_BXdIi$J^1v~r~dB)=RXI$^ngk3h8GnT zZazMVq;=`3uLbnW?4?T2pKl(%zxL>ixO5%`5XN4{RZqUz+>d#id2OW(RpWq_BS`_4ltJ2S#Q{NDDn?Uh{u zH`we&R8%Ssypc6O?^}EF#4N^)jEwErc@DEiTD!WY0tc2uX~WFivD@U7PhnNnFosdk zbC@aZJ6rB=b71k;E58?7!WMNpJ6L+|x}qF*q4^%g=xgT{mA3S~3%ym@T4CQ<7wk81 zja!~`fS~s4p@~V&qjsMxj(=%tfBy9WZ0nmDr(1Il?AgD+Ro`8oPTaY3M;4p<5!s>1 zUv?Yk;%C;&!TSBMg7N#A_l`NnPxJIWHAj<0Y1Iy%rA(;=hNG1{Hg;UDc@OvdvDt&K zZ_{0|Tnek$8SFEtwS)ne=z|maAPJt;Fj4%+Y-#$0M{~Snj%PsLuZixgukRdn=(B|$ zxO5+6%RD+O`DNUCt5j*1jLXg5SD$~(N?GNOg^XLBxE6ZdFMIcN;{F=nOis1on6>Ly zERX29dgt?yYjjC22Yq$-i}j&Vv)O^+;-cuDebUqO4J`#!Ug~!(!Y7k3+C(z$Kd(eb zcN!wkHhN~}1)3XKY>rbhVW2{t<3u6-c;8k0d~mR7pt~EV(;LH9-m_4t!ghRW_QUv7 zx#cTX96=KXOj@8&?m`I+^dlN|(x0<|FG3AoP^w^x7J*$t>gZ9l6P{B)B499bb&r2b#xN7AuZ_S@#D3z+}#&V|vSFX)^9Y`xkt6%(u z1yNvC+$kH(l+;0iZRhLS3!)~Tse<|}({tZsbas=k3dAr!NaA^?9!f>Kt@GZ;w`KDv zlJfG9if6#B&NMO0FAS{lY_!blk4CTwaZ+!7}7q_dTF?Kh9i!8^6zauhBF4E*Y?7~C+L)JCVy zpVC-Z$(i@VwAw3k>DSArJ%@i{6{T!ChKj`O@>N@69VZ7CJd?Peh*{P*zG=(+4lZJF z-xpM~P226iz8fU1s|$F&LQgMpqng=T#u>+ot1-7W`yFO_`8s?B?+Uux&~$%mB`@tJ ziIw5()C!rp6c+X(o?Yp5?F;3=UDehX{b?ChpI5z67%h@==r6Z&yK??@*uX%;;#(P} z=450;L>_=1Gi2P^=IRu1>(I`ovs1(gr6Y8`6Hh_~;{`y{I=xm_n~WY2D71lRWoo83 zTrz5LH-q2T-0aXR#5N;V#PD$VB?6hJsY|O-Yhg8zr+Q!nLL%yJuGaOD5fNqO<<^)k zKS4+@Lm-RcRd6Rk)HOAOQsUWj=LmPC*#{4BTVL3FqeC8!^k8*Q2_Hra+w{l1pHxkS zE@*$(r|r(yeNyFNT7YCRvdTkFg3tS&ompGfV^W7^pXZ~TktgSSwrtrTYFXb|)Ul{} ztRK@_)ZDghFgvSSl^CsWV))>qx7_wEZ!#n%t~dw|o>O{&rt$}4?MpX~RQycd^bOfH z3G!>_t2_PPf9C7D^3;d!v{38%BcHEE8cdh%&y+o1U{#>}H19|7r;Sgp8qqk?haLJgTkB+cB7pMl^3 zQFq3xNSzy@TWHW`)Y%=TwMa|%ox^_ZX75T6x{mACIq>poJ$drU=!~SpuO)kXDf_-m znR5z3t>;uU6WEN8OxSs-g^ORkRa@(kz%QjB#IZ}Tk0@}Uw+j`gerU@(jr>2K-Lg;e ziUi@!2qFmyVd^1GP2n@%{?GDh+Tas`Lf+FGr z^GU9=Sv-FWXyjk;FzHx3HAqF%ESq5RF#P(?oIQ&f1Wo8~CTdmlv(=TUgK^BHd{p9k zBv5(kfI#RpF_-~1j#=-Z&qu=o7wRDct6CI*KS=Typc5*6hqn!tc;&aTM`vs`tWOKi zk zU|+zvP28F4Nzv;qmx^g5eA5n3=D@<5V~s+}Vw=K&rtLw~J;Wd#xT7{rU`;Z89gk6% zfu%#$a(9^zxY01mAcfh7xiC~_wp`wR*hYuFIx}-l*D#V}yX0}@SSJ74sSYBYU3zB} zUg>tPYxQ;0lBO7M1m~QmINmUU;LF>`A23d%#=G_LuPHE}{mh=7RW?J9-L0bR zFQZHdIRZ=$^Kv;I{W-28&E zQ)x`%{o>*x*LEy^l%pJQXduJYh%tvdKa(xd)X(+7!>pozDNcs}sJl_rXBI{Y`J9u} z+j#e$gqb{J3~a|Bfb^_+6URk;Bl0X1+$Y$ta(IE#^CxdRqu@cC=2;kIh3T z$4B%DWbjwV8QiNn9=v$rSd)JB?%m~s(_DMs1mfV5-+0ezjf9A(z;_;HZ>ABNj)>w` z#_9JSl~Q@D!{QYZ{W|zond!5+O@&iM6^?)ES3?u@vPXO2f7h12PcZhbk(*{CQv(s+THOV z*s&CPB<=V5LHNWfQf(7m<&!znm#tV=7cZXh4ihe7C5Mg?meg&FIr|``1JReHc-w6} za-BPitJ?H7)IV6dQMekBiB)t>Pbvm_BhL=GdKREI^AqYeRP6yph$#(XU)7=t%TuSr)AjmX#jVeT=j@5HFnZ39oVtrRC&=RG{-lCR+g$juRXQ|o- z79sO+Q?X9wUvAw}NX%3?tg}2Z3m0%Pk*wJUZ8lr_GNElXu5YPV&#@eTHd5X4ps-(% zM(YDAbON7Q>`Cn)fk`#*Yz7KGCKG`&YlSrQ(jaP|k zu8FcG<0*{8mPDu_stuwvL5_xohGV~~MBSBB?5ylE1$Qx|PPtCt%xEqQG2)CQ8r;EK zKJX&-=n2vDsALE&lI-HvlKb|m!!pZXJ8WS-S}~#$x(JHq$WY3he)B=_P*)u|7%=Ox zF;z^Q|3^)AHLEq}be1#wmPK?Ir)6s2=R7^ZGy;ta8mWy$t+gQC%_5aCFzZ+(1Pr%) z#bFF0Sy)QJ?7mS#^&RrI>;9tXPRL{z>^#tV4?I7_o6!|?(+pK_p~Jd(bmwM9b1Rr> z(6(V8HGikMp4YpP0b(n_B8u41EnhKqppK6I9Rn5YUmuc%PS2^ahTW;Fn|ds;*V9jG zot*XgbCOlxeZWRhZm}6v`MqbhtQWTzrZjiE##?h!`j8FD>O=ru4I8Xjgo?Ds3%k4B&7dUz~f z_s&`zl^G%*waGxt?P=T4YlPn93n(#vX!vP6wPel}>yZ!zU7f&bIOnfuBL|$xtaRq6 zWxW=$WKgEt(jt(}z;5U#w86nFj$T>^dX_yRCu83zr^T|c6xz?71574bM=}2lk(aV5 zP1L;P=&*_Z{KCRQhxmu#dqcYz&rRJxAHai?H}L~!tbRD4USs272v*I zu-)lJKz6m@@zhC9Ni^~0#Mika6Ee~;K!k-cO}EfJ@kQ2qOtNO%=87+4(s^p5O^egb zns~Q5S=vu+u}S>P6?7bTmY-Z?ymhGOf`gQ2AMne{hzN<^&lM)l=R;(M!B*3nU`agKW~Itl_KPiN$`nX7z~TqBE3 zHvH;frybd0GDhogU*;fs_6Him_&)7ZBD1vHa3Mz94onE42IUw zyXnP+h~2L^yQAK2_rfeLV3WsZlng%(3DsqT*^VVhWBfF9Cke7kpo%}2+j#M^IhlGiu^!UEMnCeD^7_gvV*0tL^pRrUf=5|Y~` zEMft22!b`Z1sq^5C^-PDqaY%SWE!%=9PNR#6YLC!wkaE&m8F%55P)n5k%UFeZ}`kNb7`Dr{BvtQ&)zMVv^7LBdAextua5NsK1ehOE<9~ae0shiPL>Ws07966<14s z1CnoKsOFiH-4_Iztm&N=VfN%Mz>HMk>ON=?Zsx9t*&VVKw7B7Q>9?V{*FfA?OtaT9 zoGMs9kUwEvdt2}xoeYcGahqN)qMx5nJthV6QvJ&+0B8qjY`VSUTx&}nK1h;p`9+q= zhuCEOau()1bVMLQi>7`At7;v4wgd*=DI{ulugt9w zzg~ZLANH>dYR3`!KN{hE+{_e;WS^Xb#L zL-nlSbq>JZ=6HQ?&nC1(qjna{>OaEd!5k(S#6j<_7qyO%z4H{>qZWpIX%0xNY5Gjb ztIpU+?GaAD63@ zLd)G#1f_($usNH#-VnHu$< zg0?{?EGJ_41D53R(qVH9PvaJ1_kXNFdeso7U2iva9^>I$AyrXe-N~FpzMP=Tu$q>% z%AkcyW>|{veg@47+SunI@f_86N;i;$_r=kdTI8xvHTQ{i%70RCU zT%+aPyqfDJXOQGdTCD?7G%+3Sv1>{?Snd&Vj>j!g_5F(qzUv-2G6pTZ>);Y!$F0MfGjZ2L z(~Y>N$!aCi=6ZE#hIU=uq1GYb&%Hr+%5aKeZ7L)*pjdiuX-#8yZ|@uqBV^V9fKzn+>=O)rQ_q0>LHVQE%ZU9aWfs;wyk+SPfnqSA-#nfY!SxT!* zmn#}e??nSmrJWO5|AJG#TcQ5_6GCx|5>@+OT<)z?U|VRXD0Fhwux$l6EgAS?v89=- zd;2$i2FBvd?=`}g!a_}@0$!!qLo;KKaJ9LS}%Rsu(j|aS54tT;!`W40`NT&&dYFUjZeg~LxC>Z>56U0}9zft*pfdoDMR&{g>n#8FT?hxj{1VLw(A;xv z*nm51V!Ik>y z_x&JLAb%Mh9fZ9duSSTK!^{kk`DCFk9y@`!0B;;eXw(6`;6NR3U=P9+rHnlgYkHFE21lM*3!=Wdx#&Oxc~c zp=K~*L#vFmSk#x98BEYbgGpUxraj^<`DWW1vJVp6F9fCR?BvucD%iQnOo;HeW#K=# z%DLltJ6VX%<{o~%^)}&r?BV6rgBuA(0hW=i4(zSGm@3=>t_?_CGi-6kbzgpTRZvMJ z^;jQb$#!V#?%u5}E^g#t2d&KF{H!T%I}Wk92I4dsL~er=`!@KiR&6w+uzYh!M=1z} zgIzcG7oZm~GI9mgyd(Ka=@Zt951&8Fy)`DSS@zF8{&zfuOf&ruJNkU?ocMViFss1d z(=!9zP8pHxP*TQ{svtszG>!R$-6~pI%n1$y7Yo(lt{VZHO1zsiAY9~QV&b2V4T6-4 zlo=bm>7PFW#tWIWGgdIb2)5HR*b9NstQ1q(23&yD9ixsl9335JV83?=e*ZJGvkE@I zKG>19mkEay;nO1$CTKnPdr2Jw$3p~>#b2RyBnm0+Su*E5^amItNa)Uylp#Ukl(31S zqq2x_{e24gkTIhL;1^&A7L+PnQ10AW0B%KR(3mGX0UFL8!QVndhTsK22UxgX%!wi? z<2@7lnlgHJ$voMKE{;jAEt! z`Jq^f<#A(>iW{9TnXseQ1g>DD!oQoB`T&svZuYwWyqHUKg7O#is^GXR0>^{$XGKS1dy{uYL9x(5U-!hQKS8{Fn@SX7C$10+biViuh(h=*jwwCx$tkSJlS z3(_q_OI+s+a$m|7Wf_;#gbL`%|d-No75pk(J=37YP_@A@lrG>eH*wNT<{_fqoSmY23e@EVdZW4DJ zwwVtvKI0Tdc;|-2A%-r%HavEvlNqe!unsa&leuDc28?wK;@R+_&`{pr_sPT+w+SjV z=|!UP4J9?GRlwV|E)XnV1L%C%h(K)x)be$D+NXmO9b!_5wx&uUHm~R`@K8t_(Qftz zr#v?19%Ru7qH)4jGbs_!~MleGg)I2Dr4qc)xN91F%CTIH(qB8??8xn62wzXp?3@eubNsl~p{(S=| zD}|nP8U+Rh7A9jG=;-z<2f?!&#E}cS77c#(n?%tzm6(|5DWd591gcgF+G_^)Hk`w_-JIVmmy{vjWX>JeRfUa=y9iVJQ>`pe zoZW;?cJ-_ukwgr(nfx6t` zXPEirG8vZ_bolVM>1o|Y2^Ybb&^&8qHnyn30PJhfPKLhogJDbi2J2rxeCPu}`(;i1 z3s_D*Ms|%|mMB~aaVOSb{1CSW%7Y(ztAw)lLaT@v^a@IUXxi7VU8~@O1QIeogu*9S z3GmoV+R*p%<>Op6+yC~M&nep!CS!q7xM{}js3?c$Ru|LbXjg^}qaTh{BMHPXHITk| zNuhhJ3#&%MM;g`Ov3?VcQ@BAyU&fW_a5iQ92+ntI+(X=a>|&7sr{&N&xAG>iOKm~4 zz=A+Y2sf2+le(Rm$e)GJH8R=X>ir!g!uJN#v&zLec36xcFClrHLiM9{nYo!6srFPr z>l)mAv|UvrqN1ry&%&xOKWDw7rSpsDrewiYLDs>C4<394!zM_oa`RK+^#NAo!qy{C z&_#O754$?VO6vFH5RqRa_7@dWoS0O6Jh5TmX)M0Z*Iq`dK)>I~rrhk$k~tt1&}oE# zitz$_;EG;e7R50(O)1&)H?nPC8qqCBZT19;+1RUlb}AuIggBsk%=7&39W;KS>ELhh z5gTj7@aF*h-+wiajzFpri5pF9Pr+K2H6=QQtce$!nSIyZ`8gu;Si6l`e2bCCv&F6d z0N!9h?^`OrF=%XT4S`0*pR7c^F$L~N>@sI9uCp|I5N8?jsm@$OybpJ)4$3(+nwM&h z)>!S@)gWo#2chC#vY^i%R_lJZXK7D}Pvd2}?Zm6mLUU@JwWu>|3i4KznkoKC-rM*c z@hN;Ne-H3E+nWr-E3v2j*M1ctOJ)}2>ae}|*LzdFr~OlHDxB1M>0Wi~r#ze?Mjy*S{$S>3{guv-JqR z`huOOYHN>S8+iW43|3_w6OZPc>P74b?65`P-*4F+V0MKfBXSLuZNuYZEY0GyGVeFy zGj}CZO+Sxu;d!SynN)2Ro5`WT(LWi>{{vY|(;n_nWVHZw7<|%?@q$~5(bX??naB+O zff>9+JXiAsc7k|A!MCdjfTXR*3j1mD`IYsT)z#H~bBw*(G9GH!A!)}Mf@)|nfzndj5fuszRXxv|_ zgdNTqcutB+aqFGEjaC=*qf#_5K^Va~{_vkeFU$~E(aHl!hqaDYOoolJB(gcEE1n^h zNAMGGb@+(La|rzbc)bC?YD85tT{odG^^!XOU6 z$8p|dcMpw)xHx1Jh|zqPCD&)`D<-~!O%eY?yWDd==ngnp!>77`S>VcwZh$77ISEhx z++KAVoW`3W{ZOrF!~{Hv9lbM(^r_KEB?-JZh7{N>ucxO6_zktw7RYl_hX5%|XQI$v zKy)jix&~BknX7sLwFmvH3{E9L?1bUn2?XX0e4>^mgE~t(hEdhwuw>kzs2tGGwMu;Z z^+|9_gr-1^{~<|KZSRwf3VeS8?rV;XS1>SV5RI`=uUyRcYKmp1rh8%NovK^oN@wdT zz~x74eSCFvbiiTb%#sjWNe6Vun~tX$M+JG-Mq~-;QNZo*Fd`8ZHy{Pn?!8}9Md*WE z_RF(aqhsokv)w*_e>=`09M?I+D2DGj&k~OX+Gdj&7oE)?f!ZIfO!KC# z4f3?Zc-s}Mn$cOG%%`24Xz^`sEB2$(mM!SKI*#o`tZ=#AvdLScvD^#pLtCM5sUsb6!Gl6_zXRanRYkT{zi)Ei6?1qAqS7Z9&C}IKj~%0xt^b?SJx%;2r%} z$gR^BxvC0A(MY2PbJrKs-?~s;eGo*RwE;E00bo|&qNoIUWPJTFlkvsg6~$$e8@Qr= zeO`Dk%9lgr(s+^!Fz4wPumu@Ge01(PaK-?EjwOtIuK2aG;%zL9%iwmQaDn7vV+m?M zkDx07H=b5H_2tVpx(+^~rf5nJoGY)S)Q*e6Z^H>1rB)F!@iJh0aM3s>+3g<@vL=f3 zN?KZ%?c1@oLf{$$8er|})v13Gd9VWosb8D>WFIyO_6yp8tO)K7e1ZP441^UaI6WE> zB*+n5Be0o}IhNfAWRuPJN?RStOoA7Wp`EQ$8&e%U;{eEsrJp793h0qj+6k)qj|f?F zKYjqbcq9F9ReJ}42P_RVI1@mIn;ocV#dDI~adST+71B$HgU*i3>LusB#=O(4d+>(% z3Kcdm``PL_;+?I@8CE)jwj3LFh(hQF0#^iRI@OO42p0iqth#KaEerKPAnP z&SDfO(M&NlJ*|fFjrS4{QfWPPdh8W!<^xElz?Isg>Z#^zSphi<@Ungh;Rgs4v4h)d z56f_mc|zrr1bRZ>Kpi0zTL*Zrl;HJj@SXw0lb37@vmrq`iHijt1zQu@%gghK+z)vn zW}ZBF{rV0FWrCZ23x8}q&ooq=GZy~Dy5KYQsvqRO2?Ua2ynKA(jw|9}`x>UVXcbbS zR6sw$#h}lE);IfKzdktHD)3vH6tVg*8~D$Wubfz;`ijQ~N;F_W;Z&6R`tKaO;r|Ej zQRZZ1<*Gaa13ynrLPK|3+L;QH=J!YZ;0S>Vet(?5uWX~Jpa7Ymre)%ve~ah(&0*l% zoy-4U`zqojY>=f{$h7~uLcQH#_0r7El|w@V)R`k-J^lW5ooihF*F57?zmed_rbcj; z#K-i8?*Kx?2bm-1zu>Ex$jHb&;L$UZp%H-6N*w7j?Y$;D0K3Ja%6zQ(@*0!*rYH&O%mS8w%2DAO*Y^gB&3*8#7(TO zt}grKjMWB->>mALoKs-NGTCJ`Pt4bVA4H;Egn^a*f;N9pR|j~t_Y_sFqS-s~2t@^Z zAd#V7J+;whri+9W`g(~`ns8ihz9!5_KzUsmF35DY45vk{pEr31ra?*bhLq~Xa@1Nfhlo9@=9E2nSe3LfH57yOtwI+nWFS(&AlC&W7!H&mIV+&5FKNBMzB-omaVI?S>`l|DdL1|J|aR2GB9CEReqdn1Muo!KD{2#}!dkXgkmv)t-| zAvXCiWmDWB3|dhacZThQ@JVt0gL)${qj&(4Rq!KeF-zDu4P+X45R;iO^ydXVf#SwJ z2IPrlhB)&swmk~nj~}mf-VL&EYTI1JT{CdyQLC;~sf}Ow14(-eGsf$16yYC(0Z)<1 zgW!e?(ghB>EJly$!(iSq6_3ZDrSPOa98$KAyRR$EVF!^R9~ByS2o&5q+x| zKE@(HjB^ZE>J2EA`aW&~K^Iu_6r+P3*#Ip@#u?-z!(*5@lkyvK0EaNA1N?NMwFpVI z^=mw5kR*WV(j|mHq~|GO4zT@|?tr)Fc*AL+^%H%AE z13d{}Js)#3_2^K5!BtVw66LuemBX z(0fDfT$ttjCJN2$oCd2Z)zMcs*6Gxm){rp!}6aX&Q#MuRY}7sZE#VhT<}cd3irUm zGI6L1IApxD4@J+@Q&|K&V@i$ zzllib1v|Uy=ev0+dkcwz9FE?w1(R|(){xHL_IWNk8U!uLNN}6c%a<<&HrRfei9|X_ z-~~VnDz7;~alw=fItgLN;ju9|N(#Od+BTjjZ0o>=@J;?8xX<7yaLSIti$Q<7PRL#? zcH9VP?Mjl$bze_HB@R5QfvMB5iCVip(+3e3epqLfeH8cgDTC{QfF0E;SklN(3S0|& zc=xU=(mBFs58V}@ED=wM;mM$EApm&D%PeV4S!weOB<*k<5F6$L9Rc@^orKZP=7o<# zs&TKfcK!js%IW!?Mtk?ZyDW+DITp2A-~}ew5uK2!mTi|?;W+@M6sCcO17Cd@xbqVr z5h~>9E?Kl|Pz`5_ovH-W?w&ez3Q-&;sIM@i9=C=2)3=RV{JFlg{C7xcF7ON{Ng#~@ z;H$?Fj+ZIFv67L;f#Y%Kkt(*`&dY;e0Lm}Y?4Ic(vi#6%JR4=%N~&71=GJx2kl03% z!!;+?P{d;i+Qw#*;2?kjc4qgwJ+qNUH53Y2;h<)8aK^GKuVQ6otsx}NJ?yD^NCd64 zPX9q>BQCiglY~31twA0f6OuUjn*;ji#aix=3-$g!eBy*BkqX)Wln(LLs{jA1|KvSj z8w@@6qxWTxiqbqPxPFvby~ztB^w{hY=%tt!|J>Q;p?ZL zKNE~Dk#?@L*r%{){+Ia_myLcr*p_*Ne939_<3}mehGWye>|gioQwi*o`Ox&I3LZPs zb1(A29tpc&x5NtZ_Rl$J-lVfx`xo!WE4dxfKbuo1?O2~t)=&5$vqlv?fZ5 zhHhW0h|TW0EcR&qgex_^&y5_m3B0na{US-dhUd6PM8oZZqNn%Mg8RoF#?x*I?C-w# zQ{H*a=Fm3zE4=HdX+z#zJ{{F6ghoTj(K=rz9Ah7)U20kf2X}wt*SrJx*Vo&t5i+II z6DQ7bz*FycN{O`6dTQi{)U}N)Bct=`!|KNzPFPB?bgazP^OZGN=ZmcV4fIgpjdla5 z0V%XPY~n29mm;r0|H+4xMDB;*0K3qfCUq`W{5qGXsYlmC2Zz{Tnm-&WMRYQbyo%v% zd)nsevZiaCPu~Q_^W2~)CBdTdxjs5T!PFGKF{W%EovT?5k) z)m7kA-7`A_AONSm5nwiDzaBFPCd!^!W-E@39-Wt9+;d)hz~eWUYm*UuM_c%-@_DB7 zK85x5Cw-%#1vvDv?+}!h-h_u46b*Y)!p?!_K=}hUX?tL1svC5l?Y>`-r{3+TKY4bT zfY#tdq##qIqwlrr*Ewq6fcTMcaRqw8If@F*jie-V{0}B03W$mK*M(Mt&x0~W#;z#! z;>9=knT`;YxnMPcI&-YnGsrb+CQ(WsL*i1<4@)===4#X`zu@Eosw6)^e6GX*3EW1` zr!2rUP0KUHt=<2OWMcm4uI2q6Wg-HuHK7!duuuf{=@Cq7#YWYJ)+4ox@8uu|>B;4mPfxGRn&c0SOV0>*Nt!|W

+k_Ozn3Y;S*=$FGB7f)4#{j32DQ3=dd?r@pzBl$iKz zgVpL#Dt(}<}(3V7-Wh%u495|28L z{?$pgwIS{U zZYZE~9EWH1TrCVut+8mC)K}0Kl@J9|fbVM0hd~g6qB1z7eFbcD$P1@!FZB+ni+DvZ zCE-;mM`4R2-0RN5tS{-4FcM?`rH!5}`==n%xm*2+!$Ol0Z%2ug`<5g&!%OjYRvY`` zyQ+{3g7{P1yjlNhv>7oxjVNqdV)hj>?sYs{7|-y+?Wp(FtJ9D4S0I0GEG;z2ECB~x z1hR9Wr)LZFs(5dP_8ZlY;qu@B1@g@;4X*KE2#6Hm@Mz7P6gmo9`uh4>TR{y36uGmc z*(gXzD=Afjuje<#q)^#K%Gj*mtf|^U+}xlJhs(|VZfw-OPqhFY_tX+Y-5@IvF+W=a z#_`s{)BORfLocJ~%WP_+W=YKw@r*X&{8O-cFLx(oapKAO(^QuD7cV;46>d#vd)C9$%0Jfn}+89U4%1_c#Wdh)Rrxm(tz_p4vY;}KBVqhNS1_eIHC37Y;3xGX6gvS z*g6TRMLK#8X+jaDCSZpw6vMeE(SAG09aw_#mk6tEAfqt~%5%M7e8gxB@zlBgJazr_ zgYUYIyqxAPR~J@)ZgdH8lz%HXCYdNIduCGYEd#;9AiDu;WSpy7g%PR5{Fn<`JIkCD z6fiZXg_zsxa!oQXz}FYUMaq#A$9*MC5Yex56Jd2Yu2q{3^|V}D4O1y>RKk4}8M95H zQFs&wA!7JlQcs4DEt(_?Ytf;A2ZpIOhB1l3GoaT|R>KLEwZN9jTLJzK2fEQ_@_vkA zZeLS?dqA`t)iDd7LG3!k&nOdhpL?|?EYbF}3tKd3uiQ?0@Yer=oY!>NUhVQzeaDCv5av7v6vx#{8QZX+A@bK>cuzv*aSt{R0XT^_d_3b6c)4?;eJhN9@$!nVr5;-|?b2T@)ZTJ0ZCOD9L z6~0=xtKsIL`Y9Dzp-qkXBIobtUm9osRIU{~7TXiC>MMaqX9SLk?Ep?Ty3u{TLMwl_ zrS&4_ZqS1?{)@)4lLsdBauoN?oy<=9y(%C%T%iR(KiPj$ZT zX)&O2%c_N+R&T@l20r(+{a;H{-rV0#-Nv^5@2kf|X;Qie>f@!GH39?qoGA_Wf%$`< zo;s=7)Ji+Ab?bCNqIhZ0;@rA)&uH+(4RoJ|le97uafOhJo zFdiWOPKAZ}!xh`FTo&J|QFjXs*VgO&21@sGjkMDLqhYXN)LqAM?#8^hop^(E^wH^& zL+h^;P$}V+5}#^{8J^zWm6jPslodKfu6-=M;oCvVcu{|B!@X96{l`PnuY9uV|L0nr zZij5*-RCl!I%}nHv~>M*J5jfkoY!?eN5~PGANp?CA9J1dT+i-iyCX1g@b~CI~VQNNwl29BpE3&3%SiHV({FP#T>&vCa#~1|lDKy3Qa`N4vHu`8nS*@Ar~!^KFR zGsY!u`2Feg6Rj;DzVl@Jcte-$`=VGZ-umwrIFWvZ(Xab5xvWY4#n)rE)vl#yYAbEt zoONlCT{4&N%;?}K<+tQJ{7Pcaev@^)x%E3=k+T-oIk1x zxh~bSD)o}pSX*|Q$XW;)M|#e`!EKp)ep0{2a6d&<(Rh@Sz+oBpxOPX&-v3={H^Rp} zt^ZC4yP~7Iv;WhQC{eEaDaP10-khJb3jYxiG=D|bxf!hKU3-Mb-PbpQ&SrC=C)M6m zF0aAnj!}w(PvO~0m5;>2@{ydaB`wC?$VP&}{95NrV3tgP50?*ia}8^BlIrtTZ-t)w z`*Kg8DNrfxEojkgfEyOc5 z^;6cAq>%FGc971#88D)7J-9<=)7JMWRPdHKOl+-KBm8rx0Jj16e{F&3KgD$X7Ztny zKlEO#HBfY&eRRe#iT8wcPuxgVe*RET`FeOcdcC-Mg&JqXx!=^ZO75QFYwepZM3W&? zON%MgVcT7GP2*i$Y2 z+8}x;o%=h}-u9H; zk~2Me^onJ};UnL(*kzi7yO3en7foG=yl)K;iok*6dJ~wG@J$DW)oF-VejuI5fC z#*nRIn>{Zs8tx`-ej9ZnvegG>S^pPb?*Yzr-~Rt!4JnB-N+DTgWF``&>=ntT$SPZA zGK*|7(~v^4vne}!q_X#jC_=W7@qd20?)&>ae!u_m|KG=bUB`7Cl|G;MIA7=aJkRs- zg!{~xzyTvhVoR`6H2zrAAaa2 zNV;gtv1Pn%@9(=Mz{e-*UfkIHY+UA1e$k!yXGQlKW~Xj{@g?n$?Y31=cz&r3BUaa* z^2RGJj0H&Tk7!H@h)>y1N^0HxtKpr^4mQoSsI{%lLi`0}^yV0?_VA?=#H15-b~e1Mzf*D@C6a?B2$U7ng%6`7DK{q^BN=Evwk_8TrS0gdn- z5G=Iu90R|nSK@Nf2Rta!!Z(V?wR1D9d+uzHRDUrczkr=7dHu3J!*6xR2q4!hREr)P zd!O=-*u9Y#0hlZL%#Xgh5OOx}tCQdX6g3o z)0Y5nbNziosl6R7=MZOz4WT)_J|tFE&%NH$i>_vbe&Okr`(`Z_mUUyKwTYcvu^kIpxHVl)+UfXYx$lr`h5#V`HRRWia$`u=^#mzZwF ze2K1%y82Kdm(}dS`#Wk$Nym8hH@#hYqcHokqc?`5^V+H8NJ9#}W5atV+p{ih7zwwk z-qSOA%uzB&C3&%2TXO$E$#1!45}O_BokDDSCX;OiKFN{bYJ4NPT+^-!I@?##)?mL})cOc)tBc9ee%MV<)Ikyu?n5_}HJ zFCqw-8*AOKgco%jKA67ND=RaqyI$;$O?L*5%ope8`3oN(;VxAjJZND!KPuw>=Vg)G z+Gcmw7A%W@4*ppRW87vaFcs@YHsqgqh+YWv&HL8!)%qsU-o!d2kHKXUSaiU?wNsGW^lI0r7F+elP>s2yMX^PBNVNQ(BE zbklg6DlV>f`STCcr(#Yii+gOR-4Jp8+0ocn_~}%i`j==m>iJ~K2U0=Sp)|HT=D&|G zPvN?sH9yCkB|#Qoy0+9vu4`i%r}OS2i>qIb>$}pcD-ZXXM4WtFf5xa*yKtK9IADkN zw)2+^`UQpf{YT{JG8Bt!uw37b%#>TY4m{mI;`;CrK-x280N+-}F7UzT5KX^#=xJ}F3qq4B!p z`#v=yKRc%ca<6|X7cl&L>KRmn7KzfNOnXxy9NvtMv& z0uFT_U&}~%BwjB_``Mi}$fIX@@^g~u;CZN|Z)c|Y4aWF9HcavzW_0Gh)pH*|{s^z4 z)LG@1Y7@LSFY!ffk0A~L2Ifo3e$l~nA0?$kK2EN0;|lsz34*$+?TG;tljL+-ma{{} zM)lG1kDCt8X1d;8i%e|$J-Y+p{`Z6mjScK9!kCkA&P?>o)0FQrCMOD>R!x*`%e-;X zVX8OpPE(Xzc6|M|R!=KM?M^p3E*-k6BWId`1yy=>&1rRxVpQ~52rUDFs2z|ommy02ko5hnSZbQE;5aL%+gMW&2#$$zX|`+jBZDlAak1R z3L6# z?RIqYnHkof-P#oN-s6*D=tp)zrZ`Akv=T=llaSl$y^XU%LdEvUpQd}AXecd*tt(s{ z)ddV+!03gGs)kQ?_4|h;2HH>HVn%V(+ja8iQ?Z5Z@xDn;&XD6i-4g%L9yS^Qe{W-6 z!%M{Tn@gu^1K*Ummn?Ur7Rv66=1LDfY^i56Fek}Kl6O`}*<5ZQf)xr({Y@11NrdZT=RPPNsl(koCi zGymYQP~<87L-bp_hl%rU-O#+K^eS3}Zo&~Q)*v~4T7}~Mdhe2#-^{-xUHqY~c zGrF7)iN(t-d&7dsoPK4L-MVttGA^6R|L`F{19oz1mE-r*;$b|B83oJFbRyxWzVURG z_I3zOehUKjskAVBwV<80FQ&cxC*47LB{7Iwr0%>! zec2-;Un_4$L=n)Di<(|h>u&z zW0O|vY5ExWQm@?YmSL19HcQ@@+>J_7Dm#DYtM<6j_LlR~a$E`b4U&DbyS&4A%vyK) zGn`7UV!N60;0qDap&VMFi#5psv&%*HHgV<#;o`z44$~{WbQ>QXogb+VWmnA{E%K)` zew-k&8^;tkNrRx3r8twuLr%%!q=)-2|N2JBpZ2Tun=w$9pfBDF)OjzCZD94q{)_Gz zQkS_5&rV}d%8!KF$#6gTnTE!-hO?B{D}JROd*{5dPEC9FmO{__H;<{2Pdxwz(~Cx; z^5fK#1*!pI`?2~Xzii*CY&mdfG@o8ckr;1!CKc~?@7{IkH}bjTo#}J4f>EbJMUP%v zzI~R(ud=eNRzlFHHAO{MCxv8+UeHB$gpNKmn)BVaKflAg-#yOZAe%ZsN_sfF!o$5m z%3@xsJxzTmtnpZhqr&%U%2Q2w0`n;<)!G7qombrC+}9S)+$g4Qx_E^9q2-P!eb)IM zgpvwN(6sKsd$&lx-50bH7fh1yeWCEmLuzyV51^<))C$QP@!YnCyDWQEdWt(Cbe|Oz zB#8Qoiliu0n9rNC$xWD9j>fQ)tMa)@`Q?3zv-bv z>2$JExGBqH0h+1T`bnt!I^NAfSk`AQRc{Zb@lvE-`s9s_MV%jG(3SiAUoH37qaihd1(#3~y@>R(1#&2V>Z>uJyIm z^&2r9^-T9ePNre3H8)#UB~i9dDVAiQtp8Yuot>JQi0;^~7{LqjktcgM|5&}eU@z+S z{=vB<)(nLwL#ZBIRzn-IFJ2}V(tFNVX)eE13uSN(;OwAgkKi7aU|x&2OU26qd)GZsp(Y^{OX?wzEycHz$kKWt{|kvs)zSSZ{C#{fpBID zLUqbCJTS1=CrzEJJM*oeXSt}vf(>4Z6tltgx$%#)oErJgo5k&eB~~wDr>J<2Z*j+c ztJi1CGd<{c*-NKJx^D*ARcE>g^XmMNa;*9Fq+roDMdUzP<^!Yg13pqJbzE;V?kLc9 z4-A&ovc?_^+kZqu&E5Z-&gJVh>grKqu@xN&QbWhiihnk8+ZuRhSR1RE+0ah>;R_FM zn}j)0hT)axbk2+4`|t1QdinAO>gOC2g)5Y`la=yFkFdH<@j=MinW?arOPZXjn*2 zZ!9VNXZ99u(rTUfwu?kT=9OXBiFGM`` z9g{zMy;i*&T_+0@YCB8n@=3fnC!R^}h))+axb|Wccvh2O*RYc_y{a&V>jR8kgZAKT z-||vRe3(JY!niuw@eCnI53#XQH8QuRp2QR}I^pn6z?otA${KWC5WzVoG1r|xRJW{Hr!SvT=CYA0YV$&1 zi#syQj>Md^U!-Q1ZkP%?3q^veY8mB1PQLRul*RfbEAdkMkJ$cv%`rZ1UTXt>%Sp4A z6Mm-qo~+gqFG6=JHmI(q=KRH!S5TFX-;U%R$RY2J%myv$~`yO^xNa_CJoxt|2CBT zO{=LWgF~M9Q!;j3FYQs>*nQEoMcY!SQ;=q|oz|*f1CxFMNzLWA)t+Sjvp6 z56R*Eht*DN@s90rSka*P(7)$^_~&aN&i@APRv}8(b6kEu-&wf`q8&Rb zdlET3#n1=0_}-kZ@>DqQ#e314iFxYSpAOmDykR1>Lx0cc%y3zM@udf0Qq)-%#!(aX zp~Fh+@-Ic_`wBXv^koengh%5zN?CdJy0}^1u<)$KEl1l_o|sW30coAn#9SAx-6nDq zn6&xb^e$YzRHs$3b@A@+u=t|1Xs$)eo~z6%31NIf7pUc=ae~D35Nn1i1ASUlRa<9O5u+YlhqIER%N%!`w*q^$P z?TRmg(UaCKBm-?*dAd4QGCM~Ced208dF&n^;c+{pru^#s!@>URc}ak>@?1T4C+_8Y zid5fMk4~xpwe=<^u$?$6=BmvsEIqiS45oXoA)6(cq&oi4;`gsporRG*6D&4X`JJg% z4&3Do$!>mPQ)WK&lqKN7g9lp(8&{r>_2pFS75<#0<|g;P>^4Opn$Rw6u$ZB~$+PhYxd?p1pZLz3=&>H_wH# zydqT_YKx7ce8VwsDVcc4a{R`P7^rUhz4sV>V|gS0?DwqA=GV)*e7QRW(q8KEe5D=l zNbQE?S}C+6Ev@^ThRa4zx>>vTXfB(|>lw>G%Xu%wDt1aY)1*>yMC}q$9~}`BpKrbs-uCo*gxcU~Xs?0b^_y0T-2Ay|QUs_5C8b@mk)MOR*wW zbB)nFuh`W&sx5niG3=Cc*Jkijj71|XqNF5Q0Cw6Aj~vg*C`~EoTZ^>)17c|6KwffYo_%axh`o+ZlB5!5 zh53yg{ELan``GOp#44lbY69wJJyufH~dr{o-+??D?w?h|8Vnts01JUqRCbT?Jxq>dFt1G6} z(4=6;xL%o30NK~cwKDm~VanI_JzqZQR_;xEBil{Yn({dBwti4Dq$Wi{ADL?F`Q8e; ze3Z`5{rz-x3bH&3{3ed3t{%6y17*7 z(xe2pOA(g$;W}{7Webk>Kajz@tcd#5L7wjE)%GV#Rw~oUpIAxP)OUCDFnBstv}ntd z74|y2hW)V0L5aLK54qge!(Kn$*x2d1d>&+%Bl^SoC|*B5vzHj?EpnQfZlI}s%;HNf z<_TSZC+ihP!-vcM5UdDVwF)hz&*UXCMiv|)C>Bywct8WNL=Mfc)uA6NL;nUtikpQ`7*-S~xCd#g0{ z{Y7`QscKp**$vY5E(E=`YIr0Q9I!avf738m07>=cpAryeHB$|RUGfhw6)L|5VQU<+*J0k)p+A)T*_d<-|C&v--y!mem zLC+*FlYWY(5M+K`<3}#^6wxI@F42d^D@a5F;?E+I9A95X&8}w``hQhyPfv9;Mqeli z2v=c})I=j8Nr~&voPmg~XGKbY!xhHBe{g51l;?aIB>9w1S+8E+CQxtxyZL&^tk|xa zoC(wG@Ba_Z*53Upw7$^FIyZogU*=J1L#*o!)G|PPV$pn_ z);roi;ooWB8O0aQYmJnc(R)QNI>8v@KPt3`>yQ-B-(mMYj3iQcLOZiGGUC<|fH}Y? zmDk)E`rDYGH3TH!e|`v({-59j@aQ|`XUnq32;@0T#s*MkS@u>jr?40DnFg@Apv8uj zLmjXYJ~c=DJ2FS1B0y-K+rnR3X!N`gWXIzI6PEGfF~}^UxXY}dw_dzhVSMVbH7b$m zfi-6&0qBIBNS>U$@qVrl8BqSy=iCJagAdj)nxm?;e|hot*Y~zhnx1TbsWFxtDxE5E z5Z;=9{py8uVh*}v{#Q}X=;vdQ_MgtJ%`eR{ck|Rzt@eJc@)6?Fy2E)+OR+m$!%FBp z*3yW^Q5yv%KRI2buIPiB^^2E0>Vl`F0xezsYRDwQAP)XUbMfSqiwi1EPEBjv zt5Ckt%ir&9ZRj?i^4wa!{kb$6^Or-VYrZ>LP)~e*>HckMYWDm00>j!ebWj=^B|WYF zM~1(!a}}mIxQWO4C0~y$Y^(_#`he@{u~5_BFT!#kQQ$_&ir)BrkI|ZsT)M}L?~DwF zGVH*^ah?}9$NX<2Y+=*&Qe(uV-vLfOvun@n#`)uGtE=Bh_!*g3+(8EterFt~lEpv8 z{J89h9wVyH{UmJ)vFFWT8G5^!tvlb0+ugnF_pE2W>Bz!lZmP_$vOVEp4zcX{5+-90dT4M06Ma?veGRuXPr7ma5KbWAYra~is}p4X$j7W z*ycOJBlt?RXnJmh6)B0sw5d-Wj6Pz|&C5F+Y}xvHxuiCTlaX4|5%u$`g|)TA52cvi zyqP^@rwiRnHh*@ix2~?t{6=3ber|5$2@2|jt9iG&(lvD-9lv4T{Pfx>C4uMsZ%!Wz zNRY}goU|UczTlX~H42(slWFC-KXnI`spO+%F=gI`Fdz4VJN8hMGydyPCjxDJ%rosa zE?x7k%vdhZtqvHGaH^i%b&{SSU%^adW7GR8HlhC6vknnl$nq(rI&Q^IqBi4(FglZj z6fDRDlYn$UYw(AxPpH>-5u~tCwXBz&A1>(w z%C^3gbJz#&)c#&A*#-@trLo9A%cJ*j&){P5^%CX z`)*r7EiFnr+J8%DyeS&&vf!e4hsiL;v!d=lxkx6#Z9-R^YgS z52$JKq~kxDi{>|qW}&7D*?2rO51{B9EPB9p8UZr}1J3Rk3B+Ky>|TsBv+172L*$F) z(b~>zCs~y&d2c_WCqefV)lXgBt(cgYCjkK?=)j1-RHnLurLdW>^VrTU z0*slk?Fyntmi~5yKVLue~h?$`>SCDjoOw7ZOxR}^IDQ`@ZVoLa>7=zsq38s#lL7l+98HU2s^((fT zpPkvYb0@}?&w?C1mV&{4^_ZeG`2K{_@a_CkWk`BVU;^t9c3v-s{)Hp@$zdkDhN9f{ zHyKYcrkXL69sdtu#_@&(XokCHCfE_x!MxY+O~oRxEKVx7IF4bCK26y)AQ=BGf5X206OW0Ft*y(CIZT{v&9co@ zLp(M!LP8`meZ{HT@j#ehC2sNe?<^3>n~JEaj(4wPG95lX82Tlr70kd^EiT0jRwrMw zp4zs?x&#J*VTO1E90gF%;5X>W;s?kGJ-@Lm_E>$%8Ma1i_xGyT0^5P9QU*G@;4KU& z3keE3+1ZI32FO89!38zKzAaXSe?$EPa3)bH)&+Scs1TokRVQgFy=TwI@b+r~&`(}b z1t6ngsz04>#Sa0((|ADA`J?x zV#tk-A$o)|Y@*lK^=|grrx*qz;;A>vHu;d5Y<*cy>!{^ideFgky=Vtu}?k^EYk-!x@2#<^|(9LI*+L$** zF@Bpx97kU{^=9Q2A`(l1GrG~IzPQ}}5w>6EP%Xyqq>kDpW6zSYlCl#ns{yL4QtGnk zZew{8J$|&XO@PBnwE8dN(o++AKUi?>0_OuODGj7qH%bJ-=>hTb#P$mmec|D)y?G-W z0@w#PGpd~fMkN)0QOf-e7pf{liI=3V3H!C`cPFR z-YmljBIPe2e-2xIxW5A<+i)@tdl7d3&W2?1Ot;68**%}id!p)xm7|Mlcd6?q4>`Nh ziuKym9$UH`adc^AyZ-pq(gGL90yI*;f3bzTcyRa?GU z=0K6^QQA}N>P@Ado>M6OG%{AVIVVsZmbw&-!<7mCK>iou9p*G~b9vaaVB9$2sb-R* z^pPj)CQZh?XU}5A$hO>#ztDB%wAa}+A0uDu(`Q%TqdtAUM~`V#7nw&?|Fv_m>x1#B>kS!bUvAyvS(^COGCG zRxlsVPAS#{^dABu{?C(!U7-^9KZ4iJsZe7z_6Zb6Y`4eV1|9Y)o37wk*L7fNu&FZ9 zo0mM{gcT+bi0Ci6oik|)(~TimWrSrf&kpOWJr3hUo{)uT3uwa=uo}in^%KRhY`!&H zu{|&_Q1^(QQ_ljU>#M_P1{Eb_olmSs*dD?TJP-krAHg`nN>S*uxapri@qJnl`;Q)N z^p2m)9JvVGUK>=DV?LE1K3Bqq{UnXU%uhOlvNeBnG{K`MYLS9{FS3)t58#UggHDL^w|CkbbHNb^-u zRuI_5JRV+u!*e}4nz7sB(oS#z;YOBocj;A?K!gMJH4*JV>n2f3VHSS5@Y@`bilSl0 zTLbwa#7z_`)3UEFj-8spR1ues!=KLdEL01Sc8l~SeBlZicUs&PB zepux4)dmhIA;3GFmut zXy9xCd^vj(+aGyA({@t<3I;5T#(Weq%i@xfEUdHvsC0MM_xg#pA0!>qWbo^Xxd-++SWI0$%WyNRG06PU{!ue_l#g-fpc3@0n8vAB_3dW z;3%R4MsaA!18=14+1d`%a3CI7Qh>k23Q@I1QE_o0_N)L7dis!5@Lw{lxNE$)4=h4z zRKd$^15*O4TL5X2JWDoJ^BK!SuZF-Q1Fjvr`pH*fG~iqzJoBp3o>}e`QJK3Rm6FEj z^UHOlx1QXl^8yRoe~7&Wqs!bTL5hrptbrkv!S3JSVb=NVPlh|M)?^!> zo%G$(+PF?eQk~2H*)%APJMeozHqag;x$UxT>axt=zVN-NQ}|BXmCDL#z#Edd%KpE2 zAQ{PH?G1PMLV{lbTz$MlzL=wSVkDP}d_${9I{I(HOo3D_F`aa(gWqxJxWv1OznrE7 zG0b0|KW%Gkk@qpvIqqQn8cXN_z$=*Ar14NYOQ!!qiF%%VUt;Q_6HBC--o?6IL~0>V zn(LXhZ_8AlFPQV66g~5G{Xhk^Xy#+WU$eEZw1#Zc-fO6QzssWF*lhpZ2R0HUroquM zmzcZ{2x*VAIJ+Kg_BedbK#Xv$M! z&Tc(>>o3KdN(3p>W}Qv#bB6Tp#=z)}tTTU!KM4;*%~)Eu-D$;+l54l>p%-WJcgvq` z1Yd&Xo{;IvlP8UGUA-#*xggxgT^WxIt{JLs&3>`mC>WOd-(OhDl31CzQ878JpVWE6 zXb--su@B+n3FHEBSyV!vfB0}oMy4K&*M@a52wI!% z9y536ty`vN?PX>8T;881a8y*(U@-Rl*|W*1sgEwCXZZQ6hQS{VfQJ|j4RV^kni|Qj z?H!8Dlf&Z(P+6)r+5y4k+8o;JyM6@{Fh=XHfCN9~GxE)-5e>hD-61u#*L&n3K$;QCnZQ zaX`3JTsA^k0h9zh_b^byiS-$1vnP}ZU+{8)%C)+_Y@vN>UF1K5`HTSAWFW)FQWtCy zKuX{|hO_P>R>gpe(g0h09^Se~TgebPFm3e>tS!C*1bFQ3fwaAWW#lnqA1o-t27-vF zRa?L-H1rETKTJVGdVvLpbL1u=$p+*PYnRAQLa>|%NCyFrWmh#@6L`P7mJV-fhsHzv zsn1XOB%Vp*#iYx+2H{nUfT!0|!5(;Q-fOb?Q`U@DA8Ign?EM zZtY)2->)CLxRIq-pXc#QB&92JW%ayu#MA9pDa)F!4N7nehDX;vO~CfRSVNBgHp4LH z*T@KC8kNZZ0Ks$&TIz`Z7f~{*+>(iE3QsGRm!CKiB|3rM?f&~$ESM-bipy}eCV(nE zfUJOkHdGryVIn((1WAh8Oc&Qu@@TAx!^DXu(|U`0uC75GNQHM+lFBZ&s1}Zjt$mYe zp2MbE?(wGH-Xi4Jxa^URQeObMRDzjFm*#eTMz4@ehkn^ z8%R2A0f}>e*K*TeS-V@8PT>9*4JYx}giznE|co3ELp5xH?F@`Z4@K=Z`g zDhs3MReUQY@iIYd=|vz$xcjK#gQOY`#F-#NqoB3vFGN|bi}#*0nH`rr30vA=jS2Ge zry&jyI6xko948IfylujPZ8s2M*4b@2PE1OZjX#e3j8L4T&xS=$8n6^jB1ua_YCq9} z;Ekf1mX=mTSa@?%jd=aZe|G0iezkvyHCf;cvmGYem^5qrwgB))pxhmNUs7f5kNEq8 zn%L_^L>t03C~n+AYCA8I<`wJ^H}&j#c;)KVFl_wdUg0g_)>qtNUmeus5f8UmhKp{i z6RphJnlEhDKxNlnqaQkSi-0r-+|3{T}>mycZsJGFp%grTx5Jn923 zT&Qs@{gqe=r9O?oC4Y@yA;J9cHzPIVRh(ZWJk_Dmf5JC>#Zrc945CZXRjC`C16avqS3al7_ZRbgor)j!g;$(&GZkqQudpZE9 zglQeYZz-^z$Q1P$|j2deR$oP@ttt8k$MrC%#!C@fBh?wFt`ZFg? z!NRt_d6U<$#vdrw5P&sja60P)I*ApSP7m%K&B8zx;cn{uYs!Epq#H-L*p2qi;b8_d zj$2;M_6SJ`e-V`8BjW_K2b?n*JTNhp>9!BK0 zDjM1I2s+F=Y)_4!u)vsYgnQ-vC$%;4P-B_$=% zMEU=yg7)_DG3SvLXJWTE+S=NwFWc^49K9X{-9pr5sp0cyrBb?=i1mk7#z>eR{JWgi zx_`|8oA`JS!P#PX2in)M@NT$uC4*UkHS^1+j8mLC`D_$Q`9ZgR(s2YpasymU@^&w9 zgl26(S;j;5!6kTp&X!61h#9Td(MUMHfDGo%f*stVr%Nc!0k(=$5mjMVNsvS!HSftD z!HG{W#C%98oc%L3A`KaXcY}-<34sDkHU97_*oAJ$V-Skx+Hex0-`n_l_QKi+=K?8`&hB>3Gs;S@rMfh!s;!GeWNc9ggMrx9x^O^>VV6Iwe-d#XZRNu7yk%- zv5(vP@3Jl|B~Ye3Jjvo`*`l~e>-zMD(*Yscv06vN4!of#7~AlO0x?Vgu>!J1bKAe& z65IJ*$Sj~=aihnJlNi(wM2h#oDkH?y*jHCwN`yWO2cwHPCyKw99rzGMdK1MD5|r;aA{XJ%#+kjg7HU<@o# zWnVCBiMxFDY72a8z_^xrt@8t(5IBE8K1QTDLI83@DgewETk?T&dU|?rH+YZ79~TEy zNOhF0IQvemzG{3;@KpLh*gn;<;xqmB!e4+eFS9P=B{;O+?h-x+Mvx*i`^cr8scS@z zCGe z^A}(~`;)4Xj!;?oQ}Cidtq!~3k;9&~CZ!!NVQv@n=oK-O9CH!pUoQQYi6S(d&A!>u z!MJA`l6b5J@+7MJMWsuHB82~1L2Z6}DjlJ;pqq2DE&VGSqpLv4^m;O_Yf1o42)*ln z8E9L!+lI%E($Q_;{Q-gxS{ur@c_hs?;_=gylL0H}55W2nhB!?>YW_LxTT!u%&|6ws zI+xH?dkMt?xz-*3I=xG89tR{4GvyAG6k9@~ zqM~7Pfn?6LNSbdqMi6c9!imm-XAk_v9G2BAUS9u?`V6?&?HgX_*`>)tm%PrWp~MY1 z7t-P6yK|OSZeI1jMmQko`wI*SML78ThOa0mhBH0bz`KBw4!Nr%PM-pSX=QlV`LNm` zI{=6|JegH4LQ=_}^3ltKNORF#?N}~Jzmhh{{Gi5*i;g5Q&5T9 zgNdE%w=QAGmANT?4}Vp;u3=TLG&s+vVMgh$0B{nka#tx_bjIPMI| zJR{`{8(&>;^<6vh05xTjWhW7%urZ3<;hyU0+;m?AJj(ezXIuKefLz%IvoU-Ld^SQ_ zfdJchk{XC{a9;qnk>a2R{}r8>YL;HPTD(ex@^&{$P0hYr5lnul2v!itYxjkv)kGws zYs&r5D<>!CCtp4;Wgki;D9WfRDGI)YNs-~vRWwdCcRi8w51c2RrPlgL@YM11%SW+= zPgC99(8y@rs5{=U>&oxxmbrus11YyI*5A?u;5|&Fw4%`8h8H`V$|IUCEXs;B$(PP! z^sF=%FXl%V8WfmTIPP)ysA$XtFZaP8tkR1pP%j*vYh9G)XQvhU9$XIM_ttpFYpQaq zg`!q>pJ0gOkPlrhv_gZs;&2Z*A=89x4Q~bHhm+|@q6wZ-uo8|W$criq`{J{2^y5~8 zcr{$szSJUrY0G!O29GN4O~jS>u!<3NP|c^Or(J&k;yNO3@Ne%#84mz{hLldw-7)y# zNOpYus33ZS69=DGsdJ7FS%9$77R(8dV!%x@&dtgPX>tL$>##{CSflV36niKOwEaxT zkX=MQDI@InaPNvVzuyLBP4)uC)qNCQhmahj+|nlZ;gZ9U!L;qdX`8L z@eb4%l*vS%XmSQ{J?Z;(&Nu?%xK6%lE1nl))rZ+-i+{;Liv;$XDw`!I4#_^i*b|e` zL4>_o#Pz*Iry2W@O%5WNgdP-d`g3>pkqhu^V)`B@Y-vA#i%+PNj=}~*T}xW`ai~rY z6j8G0<09bqBbh#ydd{vJIW*MvfsPJ==(|em=a*M>bEGwxA~W({&qu7~Qm9MER#lL2 z+BH0CMZw6(=ysFHD2W*U**q4CI*ro}fiJ&h>BnwAFBd%Q7N%IwKz zW(lMu)xm}Nd2r9$6n@iy(a_ybrJ3wq5uot);A3#a5Rgwuk3gR)!?yu78Rg*(rM=ZX zJ@1hhAU;SH`@c|~+4)v>fB0RTILeU{y5Uxak?#QF!bjloMuqkkc@|Pkf^*y33Iznc z!ZcV*z(U9c%p}Q^Ym@D#Y#aPE2ty3Gjra>1i{WtHOF->|m5ORwY_rbH*x1<0>H>K0 zr6$IOkRpR)2O}7dm{_%(9^F5bBG2b??s)FPkuYxG!KtV3-=DQ_*vqmy+_3#JAfOSI zH4Yt2g}{3y+_0rih_p`@15Ae6I~AF0zfN-{++{`=p6S1!T=S>?M(73kK`l8nx`N;Y zdqGtG_;h8c{@`|@oo^a$M_!bbHH&N*1zl^JdOCg^r)SbV#0Kz|u+piI*BD(agIJ20 z(Xpc$({MwrOmo1kz~B8^YWZ$78c|O;HI-gmU&6p09?&jz8WE?AzV$!&4Tx=^7m_Lr zB`Y&@T3kg7!mx1U_tqT?N6f+AGzOm< z;i~HR1&SQCK#T1L`Q}S2tF=j`-;bDt^o3ktI!R`5WpTk)vHAKBf;ESJC$u*+B*Tz! zbGSj+zM`ah=`_LlD2m`*J1>L7zLipc1DCzp9{=J@+BtfVlgi5zhZ%s{y(M>fzJG^> zupBs5b*o0mnN5X}+CbuH@y}5~@eU$AUo~L>U;`0Y&5sB11ZI##zN$Ewq-B{UaR+!H zlp;|6qssRc^P~HHPva<|dEq$GvSW(p@Fk~fm{sQ(Vz1MEO0Cfb3yQSCpMr)2XTU#F zJ7`~_-1g@*`05UB;9 z^dGnv`{MB1?0u9KYN-@vG!f@}uk&wGFLE%EV*G;my2^AkLGZ9w`LbEP76EiPw?m&Um$ed<~Kv;LoztIAGV}x z@&pG;I-(4Q=7rl+ma=om3}|h{4=+2&xqhTanfe~{?zVMsfc$W<6FCnl6|c*sqd^aA zF*E+=Da%b#70|I;8M20ucpyOxl1sB7xXaI7&tWmVs8wIfVgObnDk+GFM+oBRWk00G zuTP(cgO*Y&C(W)bL?eIxEeYO9Ig;sq9RhA9WvN%KOZ1Scb^$-XaTYD)xe_Hcr?2;G>k|gQnQ~sc0xMzOh61 z3qc;K@VL=c{lRw`7no2xITEovK-aLUP_L`tL5;{5O?a`R$>ywosJ_N1F{(YcSeK9T z#)J+O>IR`BCaeb-8{p&_&Tk?Qe=tt1?6}jLWET#p!AAvF<9(Rhaf={c7Lp*(U7VY{dO=PmXu|m@eM{uMm=qBWW&X~3ZhVLV$LL$OS;2NJ?ydbrF2?XmZ|B6MQWpv?_xr6 z$>m-d>Hc5mY?h9w@-_A582JIB3WXA(a~a8#fZ)VfqbDrhER$Dl*Y3l|_cI?k-+_+Dm~kNA|NA>t zU}XTlecJm>Zrw_9(QxTFF^|cWgMv}HnO`R-?~POujb-L;A(b5RDN{RLSc;*8Fvl4f zJ>()oG7pLms3FNsn1j5B_?Bu?WLsNu`OGJq=|eXNH(6U(mq5NhtA-4cO`$?Uc|-le zQJUdj5UOBw-+&=R(@LG!F10?OVghlf`r=gZJa)Ppq4^ggQMiBqpCeDgrj`!#=n?80 z0_c)t{Kt>jMPtd%x%cb~M0RLrTTL!eUlo|z zUj44B$^&^69J~I0SHxAQW`X^R{1Y=JJc8qAE7&+G8ca*sIL#7}W$cYWGHuvlhl37M z%K;kROGJM8KB_p&!3QKO;cii!j|B1}!G!vk7T zPm8@IOfCh#;C){C4`3^n6T=8h3=9ko=*qMpmY0b>XBZUqj4z@WY-Gl?V3g1{i{lYfN6xbxr6FP+Kac`g+ zA^J?WzQ(ZeUlF!@rtQr~$kf{l$#(;(yfq|9`&PX#r!x}bdib3-Sz~JiMOB5LFf^^! z8$4yso4%8Xq(Pp|(rIvDz*veXT5_gzXEy!^bIQjlIJc=OjI>*|Fy|6pnYNkhjPH+Q z$|x^re53thCk?Chbo_{vc4fys5&MQ7KWE5@?l@a{4-@QEQ8D28Ii2j&TJG+;gb#i| z+ybEj_pH($^5f}KoJy^g+22q`5llv9tNxv9ARKFGZt#tw;zNp}3#2J>Z(ixk+i2K~ zI=;=wzyaoG@E|?i0(X~Jlmb8Ny9N$SRL_QkntBmw|9be`KoL-9j)+-5Cza1>kedC7 z00~BIjai2e2hmS4w|jnTj=^UHQ7n}ADf|&n=^)vyc{9Uz^BDRycsR0;AqrE@jIvWn z;3-As$Uv%dfDn?%-Hr8gX(F?qom=^HHWmXCOpLhMunkAB-*uMm~@s8j+JBuG3Dz9ah>vKY_zCH^;VSMYD@KyYnTE z^KwDs3#4LVVx>#){1$UxXNeIv@YYM$;KF>Ir4!sAp`0C?w>{m;`nB%>X47Et$tbka zlP7VPCuOmbKY{$hUtOv-(%>%XtZ`GmV?}cr3Kh@jclk<9y~a=wdtz8 z&nJ;>I(|*%79+bOwlv(U3%s)9Ly>$RekrJ$*GOr))&9J=opu-jo4j4t5wk0+~ z_=d;>iHrT$M;2E}hPT{J=32?o80`2S_E%b%m%-uD`B~~AruB*m# z6F8Z#qKapgkY}W8erawd-B)P2If&2Rl8i5e29l$#?fl#vQeGK>lab|0Wr!aZ&l>6xN=0!}6H0@e7uGbG$fbkt!fzIm~wTpP;2=J3E`Vykc*7vRxqX`)VmBYEwO)u*2)C!viWEErR zuRy?>uqqJ|6W6Ef(tx7{7m<0{ljxpZO_1CN^DJiO*LSj7e~ypC7v?!K$6x*Lc$%J# zWo>dF8|q;mOUU@#e_*O3!tt+W5_p?J=~w_2+cdo;8qx7iry46Bh+dtcNOEqyqnec+ z_KArh^0D)-Mr01m;S7WZ8!C&Gtx4H#$X5WQTOorsC!R8wt+x2-kJFgjnrrIsoub-i zc_Gk7u){D>LpJ<+zHYrC4jDHyCkcKu&kJuwMXuy!Jc2;!56^~?#x!k}As`UyH2A>~ zj5CnCK{Ku@+e6OZh_o3mkbFN;%bc6+-)`hR6%E1{NO0yJNeq{Dt-9p^!Z@kxc3sNl zEnl@cRR6h|Hw_J8`NgfR@?ZrvCXMoJc=wtwYa|ek9fMg53NDBw8t?Cnp!_&~?#@lf z+eqT~xkff3ni1|QB35qZGswHj%>R`~|NU;EtSM#T4Fer3J20k?4U&@Fg}Y%pd@o!S zgr&@go+tHw$`z6v)GvJ}ZyFfzRSk8sxZqdJP(JKGd>XT?;yp2ndI)zA+j0}0!5V%c zA>;3lKF@-$gER!_ZFP~%PV~ePDm?82R9IOapb(9qCMq?=;1@=*Pfu}#N!&uo0s{YL zyWkF0N-8RJj_eC+{TWfC96f8Uh8}t6BWvKk2)2dBQfH)NMH;R-hh6$V{xV3fB$y1+ zR@qBRO6VXV;+b4XgLyN-7k#>iPg@hZrU~v`cu7++iK4hmsuS~p(~YR4x4-WRMn?@& zVrJjkGd|+&XSj0;m~P1MtMc?YZB}=}$XD#fy-vbmA}cSek)=17p?yZ1u?@mMfgPK$ zdgAh%aM>YP1{vR+>yHutS%4G@_eeXG0qYj4ucy>yB!vPWkmQl#RJ_vZ#|r~%D7etK#*?y6i&a?z9$g>ljMKPP zy!OpkH2f2G{X6yIU-dYytpVcL6L!_Qwzg|s)adOv=`c3YvRi(I=C?5HxeWya{??dW z(T*1<(k8FQaIsZ4!PQ1sL_}t0GzZ-dbW2drM=xuIBZx!E(q0p3JTH=TZ%s=y?9#EW z)Y_ojHhpZ8jHBW*mV(1x`{&Qx#Tt<~e$mcuBvEnrmrzcj@*d7J`(#~lX2lgsEC4DF zb>-g5^s@{L=5yy(@nkn_c03CHgq3oPMOI%(P;UUz*-nQbooPBFNkWp7J$~R%wO&ow zJ;NP^K(zY|raA8)*@{XD_=iY)AN8*g*1tn%6AbYTH|kj=A$gdapE`_bFPse88VTeJ zZ&3AM1W1d^3?Myt-HbzX!C1%Jdxsxx(;*KU3q!4|QPxQuAyN7or=72>JN+BHH5fNr zL|v7e83t3Nu~#_7fq{tu-M%pCfFx^g8KC{B;fieTID(4LC zy=EDQkdQb!IKWLJWja3jH$DX(Q5fqS$su6l(H9S-9r6ERxGapC2I3FYDD50WDPm$` z(e8$Z37iUu9~k>`Lp}u();lE4NCDwDdKc<|qw*HQa#!Y!KX^>2*sn$5kwqogGtS)HJkUfh*La^s0w#SBLcTOMHa0cMJAA03;?y8@hYB`2IjN1X zgTF#sOA9nSvY11yGM5T44waj*lPBl)m*Z~6gn0`1k0VRuOP}c zhuh-ExX#wNPMrCf|5I{uh3vL$z*|O8)e83Kk5WUS;S}UH7ui=$joqOuBRIaKF}~!Y z!D3f|H1R|cp-i(}-zDmfG;SibaQ`9QHng?jSq%v&BmBFgGdBfB@oxvwQEcY?vnqd3 z)yKcR0j&Ux&TK;*T-9KMp9Exb-vEKFQ>YQkF;_%o9QpF)n>Va_=}>}k=VbpeGlm=s zr9=-!JffM=RlCVH*4<7h{aSbI@MZK02{};w25SIkuFl4!G_t*XsT&k@c1TQYP&yIDh*G2Tv4z9)&ud z%_I9)Jq3D7_WzV-B4CsR*cFC@pjk-v)D(%Ja=kh=mAMpxg>&#oj1F_b?b2D$`6BgL zT3$wwLX2PF<2y(tSyk^(8NHxs#(qLh!ER7}YY~rR>ya&8^Q}k@LrQWi)$d;)EkCfv z2h9E277QqUvjBz=2D7j=KYkqW6y^cih3BzqCV~-sk|V|Q>NM^JEdoJ?)D*^uaRx$J zQapF3yI_Yif*WSu{~rBvU4FTkPrh*rjtQbSUv`8)SO)0?trt0< zGNC1f0IL_eS*H}_WjTa}gaCk93*CE2P|^|>it-w1!cMyLw6E%Z0~^uUa{&M)j`N-O zmocK=+>SshiY;~DfBq~7eCE3w;TOl}_g97mK_L-xQ-A`LLa$xxsnFSiWO(s#3L~LH z`%6j}847|88T}@J#gPduIs7BF3yatWWC=^qFQOaADI?dP5WTK#2cF6}>4X%Z3egO& z0SZX#cZKB^T`0gZj7?4bZCu6NpD;+U1tzEN7~wpsk-b)_AOwl+Uhb07-)8L7yue#X zs|&(fa3N3H9)KMw&27`W3c+w}zE*bO$aq%K+Vl7cXNT!=Tqt#a)yTV%PR9B6CnHABaoOl9WD1lB;|eDs6O)R|V{I5+Gi9xgYP!dG2q3HfC1e zy;aB zBFCvIkgLsJibK2(xCe$e<8fZ_k$DE z*cHR;8;MIuKt>GZ-c%FA4s5vOGM~b}xUjtJ0S*-QO5^L;yXSS0hT$oUH+HD+0Val8 zE3|fUDU1*K5Hbo_JE({>Jw$^EjpDB`bi#vXA#6A3%Lj`xkw17=2_YOCGcv6P21%Sb z8wti5QbY4RI_b2dqa)hA=H5iG=soe!A86TU**iFxD3dy`5tSPl%BIbAgtl^rzz^>rzi?;z=1iJz}%SS5$W}wPq3G~5a=rxCFaSF1p zPmHdHWYhUev9RiTnLc`yIyB_}Iww{Rhl1AcRQhNYtTNJkn)pC+a2`wEIcr5 zkx8TkH~GE2uPq{zE1-i`>9p($iwtmaZ~&x60Z3hk=>*@G-C)aWdHB5h)oH4q>(K;H zNsD){H;2~nHL4jmjZlBM6jmc8W}ML&4q2dgqne-C*?#KWCH)=tjN25ahHfgGm*wIa ztp*sEXOEk6h1!RwSDw3s3mIBBJ%heFdyVgz^8{vsotOPb^YV~=unqhcpSQqh38Mk7 z9PqY~O#t2O-KGA?)zyNeJCoDXj^L>wmEB$$)^#Nr=%Pbs%7#IM2!^7L!F0@X!=TWo zk_;tEM1%yqZgJkI=b@4a9W+(Y8Ai`r>WR2@$nw9Xb#$6xohM2$$_!o7fanN(JPfiZ zf{~|CQt3Xq*h;kVJsx5l$jA90P=hnF@fuLjt~_n7;q*}T5P&u({IE%5=$GzpbZ|iI z(euVg7=CgS`r6QgqHRX-9M_65m?u)TD}Zg##Aq6ScI+Fzl(=U@ic z?Y=-S1Wlk!IpDsgL(u>Xo%B7@N>)(_DwXeDh04DU)K#F8pGn>U;S1Eq%#AW~Ae$?G zFrTUjtuqJ@Ay6d|^{ifDQSY?5Wl+5bkPBdAlXAhTSr(#@TsQ~tx(;>*ZL*xx{T9M1@IiVPFipkSkYq%vu#$T6)petdv`){$)cazUY+YG}MwYPw0peA$YN}{Yi5dMtv87p@RU^)y=IAd;|0b zVZ_MB@Gcaft*}i^P35#D1aHwoD-R+{c$~78gg=aMZjA|DtXyHCl+fpK|I&N=)0#enhJA%u9cEVq z%}Qho6iEhT}qsQeYSn`*>?t*XHr=C=C30 ze06pV!A_@kp4OV9?iZvf*a?D=`3KZKDcTfM3L-w zsfgxOY7=QsPlGcwh<2N9Ce|)J>HcM0K?{**@f^?;rIs%kkkCng73u%a+k-E>)avUb z(tGRRfOHCB!@+}V2rmWnKsfEOJM4@hIFx+r>rwnzA)|xV>9^UqZE3XhTi-K9g<0P> z?dc{{;Os#*tB(F^{3}-V^ut3G{1c$sAS(j|dxzB#;bGjBcz7N#9r|dLu0j~?cd(`V zm!Ii0^0{lpo`0u42!=;`>r4wF=3i|8k&!1)e zjBV)QTi#ldZyiWHJv{*>+F$2Yhw+z#MjG_Ye+_XHA;0=8h-97w!Y0r>*#Al8MRK!a z0WyVJcNa7k^6RlOZyiuDcLwST2zVGqjgwttgz76CHD)NxV9vk~iT$FJ{*i|S#;}uM z4|L~e>n9;b1FS1wtV&1vefZV(EBVOBJ-N!s^^^j@AyD{0009p3;ROW+#u7YVxx&ez z$|MREFQ`Kd*SI~z#|KjF8>oWW+1Vn$TJ)BLv;-m!P_@NCaSdrh_8NK#gBM27i@;WZ z-OlrxIh>cl9->xc)-D8wFv+%9+|R+;8H}zgbQb%F1NV%f)0*P36Nl*&=HMuR52yhH z&>cqI0qbT~ihA~ngp_=05fHQ<&{wj75+T@bsOfL)j(Vlsb6kLf3~z(z3J>&iD_{eF zAwycL{jr0!; z0MiPziqat(!T$>5#Xw0%b@Hpn>G3YCC2UGb9HU*gGdV_ zE+*6s-2f<3VerN-Am@l%2c;_c_ANQwI51~=484xa00JL34t<6a$V4D=lW~wshA0uJ z&5z;rBS?#Q?i@0_dU2eyXV2o`eE9c;sGSJuj5NUrav3*{&CI-CP>lk>1DIU6ecpG1*|QN1wF+PJC<#WnCVz;&{M zfE{KAhN>deF~EC3>@!`kg$q@X+g{U5dT#0Oq2dcpI#lEhxAOk|7|%dn1a7hsBm%e+ zj=G}_;05pO?DY8QrURD&0#9YYPl3bAqz0H6%{Oq<)sW~xf3Epe=6O0xn0KJD%q(%e z9Omx2yxDsGC)E~qa?C?|;iweP17`vxL zt6M5Za~UD94&7;z=a;o16%NbS$dV_XKRRCjNi}feRi4k*2S5qY2($EKMm=_up3T;s z94I8v{K|k}fPw&A+rlrKff!YlrEzK=MNnsx})naS-Zl^ZMF5JI9P~ zB(aayB_}6Ch7XYD@*^EYX{_}k!JO(R_otK=w89TR>ZxXF(TJAAVv9H~L}L7X8w-$x z1xmr9$6M;=mw*iga(<+h#+GL=cl@$fJWIA+y9-RuH zFLN-yq<0>9I|!B*JFvl?NRPS?sd$!uCJPNsr*qi%CJD4Ky_D;@;+amz&|;z8$q>=# z_ITdrde}+R6;OT9*uL}hDGYs}*C(70`f%mF8OJFc3N`QrC0}^mVG2ZEJ5;$c*(e0# zHlQaya4Sx$l1E3oQVBL$=ToA?XMLS!rDSAQiWwbvWcj@E{0}mC_U8Fsn5j#%M3dhp zV!NnI=0;~E2^LLse=35?b59&p0Et%BiDuV7I9#n$ zN#M-~+ZBGhyBeh{=(=SFJNM1?+n5Dq<<**913;Hd|J1t22|W^|p-z{WnECAr2??<8 z?9k57J5P3X)PZ8*60Nxc97ZsJS;7jla?VF;4iE=PpCEiciVr{)h5~-pB*X9pt5?v5 zXf{=1B@ex!1*a3X>T@t75Jdex7a#XHT`CaRjGVCFAcJ0@(!U-CA{HdizJVhLa*3{+ zHIipW$p38n`EwS+L+~aLSd{W=gH(@kGk|8B`ruWYow>qHmLE?M+++9Ktb56uUV})zFLvBdrvDHyfcfzu)eIUp6dw6(wtob~Ydyv$VxWqUO>^#&hNB2LnX%~NB zre#cuf}z(yap?j_c%a)E5&Ck*^w#ia*tKxz6_Wcv;A3;wHP}qo{M$4dcA@?ZoA7<+ z#-l8mEG4?6WJsl9A0P#IKs85jU|I413i@zXdP}--G$2_bqgy5;Sl~)oeZa_teew=< zv(f{2PCXiFY+QXHM^%6OP#Mt$l@<>V4>p1mV4*)}tV2M53 zz%Br0^Rv|;FKH~uW`bqd+uJkiLSVv>8*)9!C6kTko+q!-Rc?_mNd`9+Gk$MIC9{L6 zeS2#Q9Dy+)lw#PlY0;Z^BUMScjG=Qf3%m%(bzp|Ew$*1jXg!4Ce-Lej`v41&R#mYG zVfHzEvMunUtI+3wJ=lAEIc&>Q3i7zDNi=lP;M`h#drTRu*~)q;xQ7N-vHI(8vzIUG zO~5T;E>J(M-Z%GSi3`s&v_a!Bc?7}s_#pqQ1?qwjYR25wy$B$?McA*P3;F(|x9@g*CH24EPHd@H#IZxG{0}jJa<6vd7+NV}mIfQw& zO5G=QlrAG8ht zT!A5Cg@6X(Lj$OL|4SPL#L%(Hv`nYKg21c{(h=a0DwK=WRd;4M0#STiD8Pvnr^Hi{$2wQl78+uOh011Q#$~;3~Hx1!JxN-=u{K37> ztDWzBh#*Q#0eGxKer5zGRGpW(zC$-Ail7I!4-8zSQHc@pcW^cS{KX!>@uD82Mq9bC za+CA(5dL}%OVGuqRkP1KHLih0f{hUa6`qdwy__%hivtkPGEk=QDa}C>ItZ+T4`yM%Nn{-KI*9psXD||xy&d*$&A;KgJT!H_0f4r@>4v&56&aFTx%#k5E6z$ zngoT@vS~-jU!Q8h?wH&bYsn+VOSV>~`>f z-D|2Q5~O<*2ZSMiqF4#(kOTsyNiB_y{Fx{A76