From 57a9b7407f967472ef06247ad1e038126240b308 Mon Sep 17 00:00:00 2001 From: Ultrabug Date: Fri, 10 Nov 2023 11:31:36 +0100 Subject: [PATCH 01/16] docs(mkdocs): starting blocks to use mkdocs to generate the gangway documentation --- docs/{README.md => deployment.md} | 0 docs/index.md | 3 ++ mkdocs.yml | 69 +++++++++++++++++++++++++++++++ pyproject.toml | 36 ++++++++++++++++ 4 files changed, 108 insertions(+) rename docs/{README.md => deployment.md} (100%) create mode 100644 docs/index.md create mode 100644 mkdocs.yml create mode 100644 pyproject.toml diff --git a/docs/README.md b/docs/deployment.md similarity index 100% rename from docs/README.md rename to docs/deployment.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..1940d1fae --- /dev/null +++ b/docs/index.md @@ -0,0 +1,3 @@ +# Gangway documentation + +bla \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..4d015bc5e --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,69 @@ +site_name: Gangway Kubernetes configuration generator documentation +site_url: https://numberly.github.io/gangway +repo_url: https://github.com/numberly/gangway + +docs_dir: docs/ +# exclude_docs: overrides/ + +copyright: Copyright © 2023 Numberly + +theme: + name: material + font: false + # custom_dir: docs/overrides + # logo: + # assets/logo_by_maxicons.png + palette: + primary: blue + features: + - navigation.expand + - navigation.indexes + - navigation.sections + - navigation.tabs + - toc.follow + - toc.integrate + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/numberly/gangway + name: gangway on Github + +markdown_extensions: + - admonition + - attr_list + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.superfences + - pymdownx.tasklist: + custom_checkbox: true + - pymdownx.tabbed: + alternate_style: true + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + +# nav: +# - Home: index.md +# - Getting Started: +# - getting-started/installation.md +# - getting-started/quick-start.md +# - getting-started/philosophy.md +# - Configuration: +# - setup/index.md +# - setup/choosing-the-structure.md +# - setup/setting-up-languages.md +# - setup/translating-content.md +# - setup/controlling-your-builds.md +# - setup/localizing-navigation.md +# - setup/using-i18n-context.md +# - setup/using-alternates.md +# - setup/upgrading-to-1.md +# - Plugins Compatibility: +# - setup/setting-up-material.md +# - setup/setting-up-search.md +# - setup/plugins-compatibility.md +# - Changelog: changelog.md + +plugins: + - search diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..977da28f8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,36 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "gangway" +version = "1.0" +description = "Gangway Kubernetes configuration generator documentation" +readme = "README.md" +license = "MIT" +requires-python = ">=3.11" +authors = [ + { name = "Numberly", email = "guillaume.legrain@numberly.com" }, +] +classifiers = [ + "License :: OSI Approved :: MIT License", + "Operating System :: POSIX :: Linux", +] +dependencies = [ + "mkdocs>=1.5.3", +] + +[project.urls] +Documentation = "https://github.com/numberly/gangway#readme" +Download = "https://github.com/numberly/gangway/tags" +Homepage = "https://github.com/numberly/gangway" +Source = "https://github.com/numberly/gangway" +Tracker = "https://github.com/numberly/gangway/issues" + +[project.optional-dependencies] +material = ["mkdocs-material>=9.2.5"] + +[tool.hatch.envs.docs] +dependencies = [ + "mkdocs-material>=9.2.5" +] From 2693abea57dc46310dcfcd843b7eaaf7ec3ef5bd Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Sun, 12 Nov 2023 12:49:20 +0100 Subject: [PATCH 02/16] Add Gangway documentation in Mkdocs formatting + translation in french --- docs/custom-templates.md | 14 -- docs/getting-started/api-flags.fr.md | 14 ++ docs/getting-started/api-flags.md | 14 ++ docs/getting-started/build.fr.md | 16 ++ docs/getting-started/build.md | 16 ++ .../configuration.fr.md} | 0 docs/{ => getting-started}/configuration.md | 0 docs/getting-started/deployment.fr.md | 64 ++++++++ docs/{ => getting-started}/deployment.md | 12 +- docs/getting-started/helm-deployment.fr.md | 146 ++++++++++++++++++ docs/getting-started/helm-deployment.md | 146 ++++++++++++++++++ docs/how-it-work/auth0.fr.md | 48 ++++++ docs/{ => how-it-work}/auth0.md | 0 docs/how-it-work/custom-templates.fr.md | 14 ++ docs/how-it-work/custom-templates.md | 14 ++ docs/how-it-work/dex.fr.md | 53 +++++++ docs/{ => how-it-work}/dex.md | 0 docs/how-it-work/google.fr.md | 61 ++++++++ docs/{ => how-it-work}/google.md | 0 docs/how-it-work/how-it-work.fr.md | 25 +++ docs/how-it-work/how-it-work.md | 25 +++ .../images/gangway-sequence-diagram.png | Bin .../images/goauth-add-credentials-menu.png | Bin .../images/goauth-client-settings.png | Bin .../{ => how-it-work}/images/goauth-empty.png | Bin docs/index.fr.md | 17 ++ docs/index.md | 18 ++- mkdocs.yml | 50 +++--- pyproject.toml | 3 +- 29 files changed, 726 insertions(+), 44 deletions(-) delete mode 100644 docs/custom-templates.md create mode 100644 docs/getting-started/api-flags.fr.md create mode 100644 docs/getting-started/api-flags.md create mode 100644 docs/getting-started/build.fr.md create mode 100644 docs/getting-started/build.md rename docs/{configuration_fr.md => getting-started/configuration.fr.md} (100%) rename docs/{ => getting-started}/configuration.md (100%) create mode 100644 docs/getting-started/deployment.fr.md rename docs/{ => getting-started}/deployment.md (78%) create mode 100644 docs/getting-started/helm-deployment.fr.md create mode 100644 docs/getting-started/helm-deployment.md create mode 100644 docs/how-it-work/auth0.fr.md rename docs/{ => how-it-work}/auth0.md (100%) create mode 100644 docs/how-it-work/custom-templates.fr.md create mode 100644 docs/how-it-work/custom-templates.md create mode 100644 docs/how-it-work/dex.fr.md rename docs/{ => how-it-work}/dex.md (100%) create mode 100644 docs/how-it-work/google.fr.md rename docs/{ => how-it-work}/google.md (100%) create mode 100644 docs/how-it-work/how-it-work.fr.md create mode 100644 docs/how-it-work/how-it-work.md rename docs/{ => how-it-work}/images/gangway-sequence-diagram.png (100%) rename docs/{ => how-it-work}/images/goauth-add-credentials-menu.png (100%) rename docs/{ => how-it-work}/images/goauth-client-settings.png (100%) rename docs/{ => how-it-work}/images/goauth-empty.png (100%) create mode 100644 docs/index.fr.md diff --git a/docs/custom-templates.md b/docs/custom-templates.md deleted file mode 100644 index 63032d6bb..000000000 --- a/docs/custom-templates.md +++ /dev/null @@ -1,14 +0,0 @@ -# Custom Templates - -To customize the HTML pages rendered by Gangway, you may provide a set of custom templates to use instead of the built-in ones. - -:exclamation: **Important: The data passed to the templates might change between versions, and we do not guarantee that we will maintain backwards compatibility. If using custom templates, extra care must be taken when upgrading Gangway.** - -To enable this feature, set the `customHTMLTemplatesDir` option in Gangway's configuration file to a directory that contains the following custom templates: - -* home.tmpl: Home page template. -* commandline.tmpl: Post-login template that typically lists the commands needed to configure `kubectl`. - -The templates are processed using Go's `html/template` [package][0]. - -[0]: https://golang.org/pkg/html/template/ diff --git a/docs/getting-started/api-flags.fr.md b/docs/getting-started/api-flags.fr.md new file mode 100644 index 000000000..ec0d27e22 --- /dev/null +++ b/docs/getting-started/api-flags.fr.md @@ -0,0 +1,14 @@ +## Paramètres du serveur API + +Gangway nécessite que le serveur API Kubernetes soit configuré pour OIDC : + +[https://kubernetes.io/docs/admin/authentication/#configuring-the-api-server](https://kubernetes.io/docs/admin/authentication/#configuring-the-api-server) + +```bash +kube-apiserver +... +--oidc-issuer-url="https://example.auth0.com/" +--oidc-client-id=3YM4ue8MoXgBkvCIHh00000000000 +--oidc-username-claim=email +--oidc-groups-claim=groups +``` \ No newline at end of file diff --git a/docs/getting-started/api-flags.md b/docs/getting-started/api-flags.md new file mode 100644 index 000000000..e27891b55 --- /dev/null +++ b/docs/getting-started/api-flags.md @@ -0,0 +1,14 @@ +## API-Server flags + +gangway requires that the Kubernetes API server is configured for OIDC: + +https://kubernetes.io/docs/admin/authentication/#configuring-the-api-server + +```bash +kube-apiserver +... +--oidc-issuer-url="https://example.auth0.com/" +--oidc-client-id=3YM4ue8MoXgBkvCIHh00000000000 +--oidc-username-claim=email +--oidc-groups-claim=groups +``` \ No newline at end of file diff --git a/docs/getting-started/build.fr.md b/docs/getting-started/build.fr.md new file mode 100644 index 000000000..4c4fb6594 --- /dev/null +++ b/docs/getting-started/build.fr.md @@ -0,0 +1,16 @@ +## Construction + +Exigences pour la construction + +- Go (construit avec la version >= 1.21) + +Un Makefile est fourni pour les tâches de construction. Les options sont les suivantes : + +Pour commencer, c'est aussi simple que : + +```bash +go get -u github.com/soulkyu/gangway +cd $GOPATH/src/github.com/soulkyu/gangway +make setup +make +``` \ No newline at end of file diff --git a/docs/getting-started/build.md b/docs/getting-started/build.md new file mode 100644 index 000000000..d29943e71 --- /dev/null +++ b/docs/getting-started/build.md @@ -0,0 +1,16 @@ +## Build + +Requirements for building + +- Go (built with version >= 1.21) + +A Makefile is provided for building tasks. The options are as follows + +Getting started is as simple as: + +```bash +go get -u github.com/soulkyu/gangway +cd $GOPATH/src/github.com/soulkyu/gangway +make setup +make +``` diff --git a/docs/configuration_fr.md b/docs/getting-started/configuration.fr.md similarity index 100% rename from docs/configuration_fr.md rename to docs/getting-started/configuration.fr.md diff --git a/docs/configuration.md b/docs/getting-started/configuration.md similarity index 100% rename from docs/configuration.md rename to docs/getting-started/configuration.md diff --git a/docs/getting-started/deployment.fr.md b/docs/getting-started/deployment.fr.md new file mode 100644 index 000000000..cc8094e0b --- /dev/null +++ b/docs/getting-started/deployment.fr.md @@ -0,0 +1,64 @@ +# Déploiement de Gangway + +Le déploiement de Gangway consiste à écrire un fichier de configuration, puis à déployer le service. +Le service est sans état, il est donc relativement facile à gérer sur Kubernetes. +La manière dont vous fournirez l'accès au service dépendra de votre configuration spécifique. + +Gangway est maintenant conscient d'une configuration multi-cluster, nous avons développé un chart Helm qui facilitera le déploiement. + +Voici un exemple de configuration : + +```yaml +host: 0.0.0.0 +port: 8080 +serveTLS: false +clusters: + Production: + - EnvPrefix: kube01 + apiServerURL: https://kube01-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube01 + emailClaim: email + redirectURL: https://gangway.local/callback + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email + Development: + - EnvPrefix: kube02 + apiServerURL: https://kube02-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube02 + emailClaim: email + redirectURL: https://gangway.local/callback + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email + - EnvPrefix: kube03 + apiServerURL: https://kube03-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube03 + emailClaim: email + redirectURL: https://gangway.local/callback + clusterCAPath: /etc/gangly/pki/kube03/ca.crt + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email +``` diff --git a/docs/deployment.md b/docs/getting-started/deployment.md similarity index 78% rename from docs/deployment.md rename to docs/getting-started/deployment.md index 7ecb43d43..cc8094e0b 100644 --- a/docs/deployment.md +++ b/docs/getting-started/deployment.md @@ -1,12 +1,12 @@ -# Deploying Gangway +# Déploiement de Gangway -Deploying Gangway consists of writing a config file and then deploying the service. -The service is stateless so it is relatively easy to manage on Kubernetes. -How you provide access to the service is going to be dependent on your specific configuration. +Le déploiement de Gangway consiste à écrire un fichier de configuration, puis à déployer le service. +Le service est sans état, il est donc relativement facile à gérer sur Kubernetes. +La manière dont vous fournirez l'accès au service dépendra de votre configuration spécifique. -Gangway is now aware of a multi-cluster configuration, we have developped a helm chart that will made deployment easily. +Gangway est maintenant conscient d'une configuration multi-cluster, nous avons développé un chart Helm qui facilitera le déploiement. -Here is a configration example : +Voici un exemple de configuration : ```yaml host: 0.0.0.0 diff --git a/docs/getting-started/helm-deployment.fr.md b/docs/getting-started/helm-deployment.fr.md new file mode 100644 index 000000000..22ce74a24 --- /dev/null +++ b/docs/getting-started/helm-deployment.fr.md @@ -0,0 +1,146 @@ +# Configuration du Chart Helm pour Gangway + +Ce document décrit les paramètres configurables du chart Helm pour Gangway et leurs valeurs par défaut. + +## Paramètres Globaux + +- `global.imageRegistry` : Registre global d'images Docker (par défaut : `""`) +- `global.imagePullSecrets` : Noms des secrets de registre Docker global sous forme de tableau (par défaut : `[]`) +- `global.storageClass` : Classe de stockage globale pour le(s) volume(s) persistant(s) (par défaut : `""`) + +## Paramètres Communs + +- `kubeVersion` : Forcer la version cible de Kubernetes (par défaut : `""`) +- `nameOverride` : Chaîne pour remplacer partiellement le modèle `common.names.fullname` (par défaut : `""`) +- `fullnameOverride` : Chaîne pour remplacer entièrement le modèle `common.names.fullname` (par défaut : `""`) +- `commonLabels` : Étiquettes à ajouter à tous les objets déployés (par défaut : `{}`) +- `commonAnnotations` : Annotations à ajouter à tous les objets déployés (par défaut : `{}`) +- `clusterDomain` : Domaine de cluster Kubernetes par défaut (par défaut : `cluster.local`) +- `extraDeploy` : Tableau d'objets supplémentaires à déployer avec la release (par défaut : `[]`) + +## Paramètres de l'Image Gangway + +- `image.registry` : Registre d'image Gangway (par défaut : `docker.io`) +- `image.repository` : Dépôt d'image Gangway (par défaut : `numberlyinfra/gangway`) +- `image.tag` : Tag de l'image Gangway (par défaut : `master`) +- `image.digest` : Digest de l'image Gangway (par défaut : `""`) +- `image.pullPolicy` : Politique de téléchargement de l'image (par défaut : `Always`) +- `image.pullSecrets` : Spécifier les noms des secrets de registre Docker sous forme de tableau (par défaut : `[]`) +- `image.debug` : Activer le mode debug de l'image Gangway (par défaut : `false`) + +## Paramètres de Déploiement de Gangway + +- `replicaCount` : Nombre de répliques de Gangway à déployer (par défaut : `3`) +- `updateStrategy.type` : StrategyType peut être défini sur `RollingUpdate` ou `OnDelete` (par défaut : `RollingUpdate`) +- `podSecurityContext.enabled` : Activer le contexte de sécurité des pods Gangway (par défaut : `true`) +- `podSecurityContext.fsGroup` : ID de groupe pour les volumes du pod (par défaut : `1001`) +- `containerSecurityContext.enabled` : Activer le contexte de sécurité des conteneurs Gangway (par défaut : `true`) +- `containerSecurityContext.runAsUser` : ID utilisateur pour exécuter les conteneurs Gangway (par défaut : `1001`) +- `containerSecurityContext.runAsNonRoot` : Définir le contexte de sécurité du conteneur Gangway runAsNonRoot (par défaut : `true`) +- `resources.limits` : Les limites de ressources pour le conteneur Gangway (par défaut : `{}`) +- `resources.requests` : Les ressources demandées pour le conteneur Gangway (par défaut : `{ memory: "512Mi", cpu: "300m" }`) + +## Probes + +- `startupProbe.enabled` : Activer startupProbe (par défaut : `false`) +- `livenessProbe.enabled` : Activer livenessProbe (par défaut : `true`) +- `readinessProbe.enabled` : Activer readinessProbe (par défaut : `true`) + +## Configuration du Service + +- `service.type` : Type de service Kubernetes (par défaut : `ClusterIP`) +- `service.ports.http` : Port HTTP du service (par défaut : `8080`) +- `service.sessionAffinity` : Affinité de session pour le service Kubernetes (par défaut : `ClientIP`) + +## Configuration de l'Ingress + +- `ingress.enabled` : Définir sur true pour activer la génération de l'enregistrement d'ingress (par défaut : `false`) +- `ingress.hostname` : Hôte par défaut pour la ressource ingress (par défaut : `gangway.local`) +- `ingress.path` : Le chemin vers Gangway (par défaut : `/`) +- `ingress.annotations` : Annotations supplémentaires pour la ressource Ingress (par défaut : `{}`) + +## Configuration Supplémentaire + +- `extraEnvVars` : Variables d'environnement supplémentaires à définir sur le conteneur Gangway (par défaut : `[]`) +- `extraVolumes` : Spécifier éventuellement une liste supplémentaire de volumes pour les pods Gangway (par défaut : `[]`) +- `extraVolumeMounts` : Spécifier éventuellement une liste supplémentaire de volumeMounts pour le(s) conteneur(s) Gangway (par défaut : `[]`) + +## Affinité et Tolérances + +- `podAffinityPreset` : Préréglage d'affinité de pod (par défaut : `""`) +- `podAntiAffinityPreset` : Préréglage d'anti-affinité de pod (par défaut : `soft`) +- `nodeAffinityPreset.type` : Type de préréglage d'affinité de nœud (par défaut : `""`) +- `affinity` : Affinité pour l'assignation de pod (par défaut : `{}`) +- `nodeSelector` : Étiquettes de nœud pour l'assignation de pod (par défaut : `{}`) +- `tolerations` : Tolérances pour l'assignation de pod (par défaut : `[]`) + +## Personnalisation + +- `command` : Remplacer la commande par défaut du conteneur (par défaut : `[]`) +- `args` : Remplacer les arguments par défaut du conteneur (par défaut : `[]`) +- `lifecycleHooks` : pour le(s) conteneur(s) Gangway afin d'automatiser la configuration avant ou après le démarrage (par défaut : `{}`) +- `extraEnvVarsCM` : Nom du ConfigMap existant contenant des variables d'environnement supplémentaires (par défaut : `""`) +- `extraEnvVarsSecret` : Nom du Secret existant contenant des variables d'environnement supplémentaires (par défaut : `""`) + +## Session et Configuration + +- `sessionkey` : Clé de session (par défaut : `mySessionKey`) +- `sessionsalt` : Sel de session (par défaut : `mySessionSalt`) +- `configuration` : Configuration en ligne pour Gangway (par défaut : `""`) + +## Exemple de configuration : +```yaml +host: 0.0.0.0 +port: 8080 +serveTLS: false +clusters: + Production: + - EnvPrefix: kube01 + apiServerURL: https://kube01-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube01 + emailClaim: email + redirectURL: https://gangway.local/callback + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email + Development: + - EnvPrefix: kube02 + apiServerURL: https://kube02-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube02 + emailClaim: email + redirectURL: https://gangway.local/callback + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email + - EnvPrefix: kube03 + apiServerURL: https://kube03-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube03 + emailClaim: email + redirectURL: https://gangway.local/callback + clusterCAPath: /etc/gangly/pki/kube03/ca.crt + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email +``` +To get more informations : [Configuration](configuration.md) \ No newline at end of file diff --git a/docs/getting-started/helm-deployment.md b/docs/getting-started/helm-deployment.md new file mode 100644 index 000000000..22ce74a24 --- /dev/null +++ b/docs/getting-started/helm-deployment.md @@ -0,0 +1,146 @@ +# Configuration du Chart Helm pour Gangway + +Ce document décrit les paramètres configurables du chart Helm pour Gangway et leurs valeurs par défaut. + +## Paramètres Globaux + +- `global.imageRegistry` : Registre global d'images Docker (par défaut : `""`) +- `global.imagePullSecrets` : Noms des secrets de registre Docker global sous forme de tableau (par défaut : `[]`) +- `global.storageClass` : Classe de stockage globale pour le(s) volume(s) persistant(s) (par défaut : `""`) + +## Paramètres Communs + +- `kubeVersion` : Forcer la version cible de Kubernetes (par défaut : `""`) +- `nameOverride` : Chaîne pour remplacer partiellement le modèle `common.names.fullname` (par défaut : `""`) +- `fullnameOverride` : Chaîne pour remplacer entièrement le modèle `common.names.fullname` (par défaut : `""`) +- `commonLabels` : Étiquettes à ajouter à tous les objets déployés (par défaut : `{}`) +- `commonAnnotations` : Annotations à ajouter à tous les objets déployés (par défaut : `{}`) +- `clusterDomain` : Domaine de cluster Kubernetes par défaut (par défaut : `cluster.local`) +- `extraDeploy` : Tableau d'objets supplémentaires à déployer avec la release (par défaut : `[]`) + +## Paramètres de l'Image Gangway + +- `image.registry` : Registre d'image Gangway (par défaut : `docker.io`) +- `image.repository` : Dépôt d'image Gangway (par défaut : `numberlyinfra/gangway`) +- `image.tag` : Tag de l'image Gangway (par défaut : `master`) +- `image.digest` : Digest de l'image Gangway (par défaut : `""`) +- `image.pullPolicy` : Politique de téléchargement de l'image (par défaut : `Always`) +- `image.pullSecrets` : Spécifier les noms des secrets de registre Docker sous forme de tableau (par défaut : `[]`) +- `image.debug` : Activer le mode debug de l'image Gangway (par défaut : `false`) + +## Paramètres de Déploiement de Gangway + +- `replicaCount` : Nombre de répliques de Gangway à déployer (par défaut : `3`) +- `updateStrategy.type` : StrategyType peut être défini sur `RollingUpdate` ou `OnDelete` (par défaut : `RollingUpdate`) +- `podSecurityContext.enabled` : Activer le contexte de sécurité des pods Gangway (par défaut : `true`) +- `podSecurityContext.fsGroup` : ID de groupe pour les volumes du pod (par défaut : `1001`) +- `containerSecurityContext.enabled` : Activer le contexte de sécurité des conteneurs Gangway (par défaut : `true`) +- `containerSecurityContext.runAsUser` : ID utilisateur pour exécuter les conteneurs Gangway (par défaut : `1001`) +- `containerSecurityContext.runAsNonRoot` : Définir le contexte de sécurité du conteneur Gangway runAsNonRoot (par défaut : `true`) +- `resources.limits` : Les limites de ressources pour le conteneur Gangway (par défaut : `{}`) +- `resources.requests` : Les ressources demandées pour le conteneur Gangway (par défaut : `{ memory: "512Mi", cpu: "300m" }`) + +## Probes + +- `startupProbe.enabled` : Activer startupProbe (par défaut : `false`) +- `livenessProbe.enabled` : Activer livenessProbe (par défaut : `true`) +- `readinessProbe.enabled` : Activer readinessProbe (par défaut : `true`) + +## Configuration du Service + +- `service.type` : Type de service Kubernetes (par défaut : `ClusterIP`) +- `service.ports.http` : Port HTTP du service (par défaut : `8080`) +- `service.sessionAffinity` : Affinité de session pour le service Kubernetes (par défaut : `ClientIP`) + +## Configuration de l'Ingress + +- `ingress.enabled` : Définir sur true pour activer la génération de l'enregistrement d'ingress (par défaut : `false`) +- `ingress.hostname` : Hôte par défaut pour la ressource ingress (par défaut : `gangway.local`) +- `ingress.path` : Le chemin vers Gangway (par défaut : `/`) +- `ingress.annotations` : Annotations supplémentaires pour la ressource Ingress (par défaut : `{}`) + +## Configuration Supplémentaire + +- `extraEnvVars` : Variables d'environnement supplémentaires à définir sur le conteneur Gangway (par défaut : `[]`) +- `extraVolumes` : Spécifier éventuellement une liste supplémentaire de volumes pour les pods Gangway (par défaut : `[]`) +- `extraVolumeMounts` : Spécifier éventuellement une liste supplémentaire de volumeMounts pour le(s) conteneur(s) Gangway (par défaut : `[]`) + +## Affinité et Tolérances + +- `podAffinityPreset` : Préréglage d'affinité de pod (par défaut : `""`) +- `podAntiAffinityPreset` : Préréglage d'anti-affinité de pod (par défaut : `soft`) +- `nodeAffinityPreset.type` : Type de préréglage d'affinité de nœud (par défaut : `""`) +- `affinity` : Affinité pour l'assignation de pod (par défaut : `{}`) +- `nodeSelector` : Étiquettes de nœud pour l'assignation de pod (par défaut : `{}`) +- `tolerations` : Tolérances pour l'assignation de pod (par défaut : `[]`) + +## Personnalisation + +- `command` : Remplacer la commande par défaut du conteneur (par défaut : `[]`) +- `args` : Remplacer les arguments par défaut du conteneur (par défaut : `[]`) +- `lifecycleHooks` : pour le(s) conteneur(s) Gangway afin d'automatiser la configuration avant ou après le démarrage (par défaut : `{}`) +- `extraEnvVarsCM` : Nom du ConfigMap existant contenant des variables d'environnement supplémentaires (par défaut : `""`) +- `extraEnvVarsSecret` : Nom du Secret existant contenant des variables d'environnement supplémentaires (par défaut : `""`) + +## Session et Configuration + +- `sessionkey` : Clé de session (par défaut : `mySessionKey`) +- `sessionsalt` : Sel de session (par défaut : `mySessionSalt`) +- `configuration` : Configuration en ligne pour Gangway (par défaut : `""`) + +## Exemple de configuration : +```yaml +host: 0.0.0.0 +port: 8080 +serveTLS: false +clusters: + Production: + - EnvPrefix: kube01 + apiServerURL: https://kube01-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube01 + emailClaim: email + redirectURL: https://gangway.local/callback + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email + Development: + - EnvPrefix: kube02 + apiServerURL: https://kube02-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube02 + emailClaim: email + redirectURL: https://gangway.local/callback + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email + - EnvPrefix: kube03 + apiServerURL: https://kube03-api-url:443 + audience: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + providerURL: https://accounts.google.com + clientID: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com + clientSecret: GXXXX-XXXXXXXXXXXXXXXXXXX + clusterName: kube03 + emailClaim: email + redirectURL: https://gangway.local/callback + clusterCAPath: /etc/gangly/pki/kube03/ca.crt + scopes: + - openid + - profile + - email + tokenURL: https://www.googleapis.com/oauth2/v4/token + usernameClaim: email +``` +To get more informations : [Configuration](configuration.md) \ No newline at end of file diff --git a/docs/how-it-work/auth0.fr.md b/docs/how-it-work/auth0.fr.md new file mode 100644 index 000000000..2fb9ec055 --- /dev/null +++ b/docs/how-it-work/auth0.fr.md @@ -0,0 +1,48 @@ +# Connexion de Gangway à Auth0 + +1. Créez un compte pour Auth0 et connectez-vous. +2. Depuis le tableau de bord, cliquez sur "Nouvelle Application". +3. Entrez un nom et choisissez "Applications Web à Page Unique". +4. Cliquez sur "Paramètres" et rassemblez les informations pertinentes, puis mettez à jour le fichier `docs/yaml/02-configmap.yaml` et appliquez-le au cluster. +5. Mettez à jour les "URL de Rappel Autorisées" pour correspondre au paramètre "redirectURL" dans la configmap configurée précédemment. +6. Cliquez sur "Enregistrer les Changements". +7. Ajoutez une règle pour ajouter des métadonnées de groupe en cliquant sur "Règles" dans le menu. +8. Donnez un nom à la règle et copiez/collez ce qui suit : + + ```go + function (user, context, callback) { + if (user.app_metadata && 'groups' in user.app_metadata) { + context.idToken.groups = user.app_metadata.groups; + } else { + context.idToken.groups = []; + } + + callback(null, user, context); + } + ``` + +9. Configurez le serveur API avec la configuration suivante en remplaçant les valeurs issuer-url et client-id : + + ``` + --oidc-issuer-url=https://example.auth0.com/ + --oidc-client-id= + --oidc-username-claim=email + --oidc-groups-claim=groups + ``` + +## Exemple + +Une configuration typique de gangway pour Auth0 : + +```yaml +clusterName: "VotreCluster" +providerURL: "https://example.auth0.com" +clientID: "" +clientSecret: "" +audience: "https://example.auth0.com/userinfo" +redirectURL: "https://gangway.example.com/callback" +scopes: ["openid", "profile", "email", "offline_access"] +usernameClaim: "sub" +emailClaim: "email" +apiServerURL: "https://kube-apiserver.votrecluster.com" +``` \ No newline at end of file diff --git a/docs/auth0.md b/docs/how-it-work/auth0.md similarity index 100% rename from docs/auth0.md rename to docs/how-it-work/auth0.md diff --git a/docs/how-it-work/custom-templates.fr.md b/docs/how-it-work/custom-templates.fr.md new file mode 100644 index 000000000..107ead3a6 --- /dev/null +++ b/docs/how-it-work/custom-templates.fr.md @@ -0,0 +1,14 @@ +# Modèles Personnalisés + +Pour personnaliser les pages HTML rendues par Gangway, vous pouvez fournir un ensemble de modèles personnalisés à utiliser à la place de ceux intégrés. + +:exclamation: **Important : Les données transmises aux modèles peuvent changer entre les versions, et nous ne garantissons pas que nous maintiendrons la compatibilité avec les versions antérieures. Si vous utilisez des modèles personnalisés, une attention particulière doit être portée lors de la mise à niveau de Gangway.** + +Pour activer cette fonctionnalité, définissez l'option `customHTMLTemplatesDir` dans le fichier de configuration de Gangway pour un répertoire qui contient les modèles personnalisés suivants : + +* home.tmpl : Modèle de la page d'accueil. +* commandline.tmpl : Modèle post-connexion qui liste généralement les commandes nécessaires pour configurer `kubectl`. + +Les modèles sont traités en utilisant le [package][0] `html/template` de Go. + +[0]: https://golang.org/pkg/html/template/ diff --git a/docs/how-it-work/custom-templates.md b/docs/how-it-work/custom-templates.md new file mode 100644 index 000000000..107ead3a6 --- /dev/null +++ b/docs/how-it-work/custom-templates.md @@ -0,0 +1,14 @@ +# Modèles Personnalisés + +Pour personnaliser les pages HTML rendues par Gangway, vous pouvez fournir un ensemble de modèles personnalisés à utiliser à la place de ceux intégrés. + +:exclamation: **Important : Les données transmises aux modèles peuvent changer entre les versions, et nous ne garantissons pas que nous maintiendrons la compatibilité avec les versions antérieures. Si vous utilisez des modèles personnalisés, une attention particulière doit être portée lors de la mise à niveau de Gangway.** + +Pour activer cette fonctionnalité, définissez l'option `customHTMLTemplatesDir` dans le fichier de configuration de Gangway pour un répertoire qui contient les modèles personnalisés suivants : + +* home.tmpl : Modèle de la page d'accueil. +* commandline.tmpl : Modèle post-connexion qui liste généralement les commandes nécessaires pour configurer `kubectl`. + +Les modèles sont traités en utilisant le [package][0] `html/template` de Go. + +[0]: https://golang.org/pkg/html/template/ diff --git a/docs/how-it-work/dex.fr.md b/docs/how-it-work/dex.fr.md new file mode 100644 index 000000000..6f82f9ad5 --- /dev/null +++ b/docs/how-it-work/dex.fr.md @@ -0,0 +1,53 @@ +# Connexion de Gangway à Dex + +[Dex](https://github.com/coreos/dex) est un outil pratique créé par CoreOS qui fournit un point de terminaison OIDC commun pour plusieurs fournisseurs d'identité. +Pour configurer Gangway afin de communiquer avec Dex, certaines informations doivent être collectées auprès de Dex. +Suivant la norme OIDC, Dex fournit une URL où sa configuration OIDC peut être rassemblée. +Cette URL se trouve à `.well-known/openid-configuration`. +Si Dex est configuré avec une URL d'émetteur de `http://app.example.com`, sa configuration OpenID peut être trouvée à `http://app.example.com/.well-known/openid-configuration`. +Un exemple de la configuration OpenID fournie par Dex : + + ``` + { + "issuer": "http://app.example.com", + "authorization_endpoint": "http://app.example.com/auth", + "token_endpoint": "http://app.example.com/token", + "jwks_uri": "http:/app.example.com/keys", + "response_types_supported": [ + "code" + ], + "subject_types_supported": [ + "public" + ], + "id_token_signing_alg_values_supported": [ + "RS256" + ], + "scopes_supported": [ + "openid", + "email", + "groups", + "profile", + "offline_access" + ], + "token_endpoint_auth_methods_supported": [ + "client_secret_basic" + ], + "claims_supported": [ + "aud", + "email", + "email_verified", + "exp", + "iat", + "iss", + "locale", + "name", + "sub" + ] + } + ``` + + +En utilisant l'exemple de Gangway, il suffit de fournir votre installation Dex comme fournisseur. La configuration de Dex fournit une liste +nommée `claims_supported` parmi laquelle vous pouvez choisir lors de la définition de `username_claim` et `email_claim`. +La revendication correcte à utiliser dépend du fournisseur d'identité en amont pour lequel Dex est configuré. +`client_id` et `client_secret` sont des chaînes de caractères qui peuvent avoir n'importe quelle valeur, mais elles doivent correspondre à l'ID client et au secret dans votre configuration Dex. diff --git a/docs/dex.md b/docs/how-it-work/dex.md similarity index 100% rename from docs/dex.md rename to docs/how-it-work/dex.md diff --git a/docs/how-it-work/google.fr.md b/docs/how-it-work/google.fr.md new file mode 100644 index 000000000..90dac5fb0 --- /dev/null +++ b/docs/how-it-work/google.fr.md @@ -0,0 +1,61 @@ +# Connexion de Gangway à Google +Il est possible d'utiliser Google comme fournisseur OAuth avec Gangway. Pour ce faire, suivez les instructions ci-dessous : + +## Configuration de l'OAuth Google + +* Rendez-vous dans la zone des identifiants de Google Cloud : `https://console.cloud.google.com/apis/credentials?project=`. +Si vous n'avez pas encore créé d'identifiants, vous devriez voir une liste vide. + +![liste vide oauth google](images/goauth-empty.png) + +* Sur cette page, cliquez sur "Créer des identifiants". Un menu apparaîtra. Dans ce menu, cliquez sur "ID client OAuth". + +![menu oauth google](images/goauth-add-credentials-menu.png) + +* Sur la page où vous arriverez, choisissez "Application Web" pour le type, donnez un nom à l'ID client OAuth, remplissez l'URL de rappel de manière appropriée, puis cliquez sur "Créer". + +![paramètres oauth google](images/goauth-client-settings.png) + +* Si la création est réussie, une fenêtre modale vous demandera si vous souhaitez copier l'ID client et le secret. Cliquez sur "OK" pour fermer. + +* Dans la liste, vous devriez voir les identifiants que nous venons de créer. À droite, il y a 3 icônes d'action. Cliquez sur la flèche "télécharger" vers le bas. + +## Configuration de Gangway + +Vous devez maintenant configurer Gangway. +Voici un fichier de configuration typique : + +```yaml +# Le nom de votre cluster. Il n'y a pas de correspondance stricte, donc cela peut être n'importe quoi +clusterName: "nom_de_votre_cluster" + +# L'URL pour faire la découverte +providerUrl: "https://accounts.google.com/" + +# ID client API. Obtenez-le dans le champ "client_id" des identifiants Google +clientId: "12345678901234567890.apps.googleusercontent.com" + +# Secret client API. Obtenez-le dans le champ "client_secret" des identifiants Google +clientSecret: "FRGegerwgfsFE_fefdsf" + +# Point de terminaison qui fournit des informations sur le profil utilisateur. +# Pour Google, c'est le même que votre client_id +audience: "923798723208-9pq62pkrnbhumipnqs4v0a1iu7ij01fo.apps.googleusercontent.com" + +# Où rediriger ensuite. Cela devrait être une URL +# Où Gangway est accessible. Ne peut pas être une adresse IP brute. Doit être un TLD valide. +redirectUrl: "https://url.kuberneters.cluster.com/callback" + +# Utilisé pour spécifier la portée de l'autorisation demandée en OAuth. +# Contrairement à Auth0, nous n'avons pas besoin de "offline" +scopes: ["openid", "profile", "email"] + +# Quel champ regarder dans le jeton pour extraire le nom d'utilisateur, laissez tel quel +usernameClaim: "sub" + +# Quel champ regarder dans le jeton pour extraire l'email, laissez tel quel +emailClaim: "email" + +# Le serveur API à utiliser lors de la configuration de kubectl pour l'utilisateur +apiServerURL: "https://kube-apiserver.yourcluster.com" +``` \ No newline at end of file diff --git a/docs/google.md b/docs/how-it-work/google.md similarity index 100% rename from docs/google.md rename to docs/how-it-work/google.md diff --git a/docs/how-it-work/how-it-work.fr.md b/docs/how-it-work/how-it-work.fr.md new file mode 100644 index 000000000..c65c54036 --- /dev/null +++ b/docs/how-it-work/how-it-work.fr.md @@ -0,0 +1,25 @@ +# Comment ça fonctionne + +Kubernetes prend en charge OpenID Connect (OIDC) comme mécanisme d'authentification des utilisateurs. OIDC est un +protocole d'authentification qui permet aux serveurs de vérifier l'identité d'un utilisateur via un jeton d'identité (ID Token). + +Lors de l'utilisation d'OIDC pour s'authentifier auprès de Kubernetes, le client (par exemple, `kubectl`) envoie le jeton d'identité +avec toutes les requêtes au serveur API. Du côté serveur, le serveur API de Kubernetes vérifie le +jeton pour s'assurer qu'il est valide et n'a pas expiré. Une fois vérifié, le serveur API extrait les informations de nom d'utilisateur et d'appartenance à des groupes du jeton, et continue le traitement de la requête. + +Pour obtenir le jeton d'identité, l'utilisateur doit passer par le processus d'authentification OIDC. C'est là +que Gangway intervient. Gangway est une application web qui permet le flux d'authentification OIDC qui +résulte dans la création du jeton d'identité. + +Gangway est configuré comme un client d'un service d'identité en amont qui parle OIDC. Pour obtenir le jeton +d'identité, l'utilisateur accède à Gangway, initie le flux OIDC en cliquant sur le bouton "Se connecter", et +complète le flux en s'authentifiant auprès du service d'identité en amont. Les identifiants de l'utilisateur ne sont +jamais partagés avec Gangway. + +Une fois le flux d'authentification terminé, l'utilisateur est redirigé vers une page Gangway qui fournit +des instructions sur la façon de configurer `kubectl` pour utiliser le jeton d'identité. + +Le diagramme de séquence suivant détaille le flux d'authentification : + + +![gangway](images/gangway-sequence-diagram.png) \ No newline at end of file diff --git a/docs/how-it-work/how-it-work.md b/docs/how-it-work/how-it-work.md new file mode 100644 index 000000000..e5cb4576a --- /dev/null +++ b/docs/how-it-work/how-it-work.md @@ -0,0 +1,25 @@ +# How It Works + +Kubernetes supports OpenID Connect (OIDC) as a user authentication mechanism. OIDC is an +authentication protocol that allows servers to verify the identity of a user by way of an ID Token. + +When using OIDC to authenticate with Kubernetes, the client (e.g. `kubectl`) sends the ID token +alongside all requests to the API server. On the server side, the Kubernetes API server verifies the +token to ensure it is valid and has not expired. Once verified, the API server extracts username and +group membership information from the token, and continues processing the request. + +In order to obtain the ID token, the user must go through the OIDC authentication process. This is +where Gangway comes in. Gangway is a web application that enables the OIDC authentication flow which +results in the minting of the ID Token. + +Gangway is configured as a client of an upstream Identity Service that speaks OIDC. To obtain the ID +token, the user accesses Gangway, initiates the OIDC flow by clicking the "Log In" button, and +completes the flow by authenticating with the upstream Identity Service. The user's credentials are +never shared with Gangway. + +Once the authentication flow is complete, the user is redirected to a Gangway page that provides +instructions on how to configure `kubectl` to use the ID token. + +The following sequence diagram details the authentication flow: + +![gangway](images/gangway-sequence-diagram.png) \ No newline at end of file diff --git a/docs/images/gangway-sequence-diagram.png b/docs/how-it-work/images/gangway-sequence-diagram.png similarity index 100% rename from docs/images/gangway-sequence-diagram.png rename to docs/how-it-work/images/gangway-sequence-diagram.png diff --git a/docs/images/goauth-add-credentials-menu.png b/docs/how-it-work/images/goauth-add-credentials-menu.png similarity index 100% rename from docs/images/goauth-add-credentials-menu.png rename to docs/how-it-work/images/goauth-add-credentials-menu.png diff --git a/docs/images/goauth-client-settings.png b/docs/how-it-work/images/goauth-client-settings.png similarity index 100% rename from docs/images/goauth-client-settings.png rename to docs/how-it-work/images/goauth-client-settings.png diff --git a/docs/images/goauth-empty.png b/docs/how-it-work/images/goauth-empty.png similarity index 100% rename from docs/images/goauth-empty.png rename to docs/how-it-work/images/goauth-empty.png diff --git a/docs/index.fr.md b/docs/index.fr.md new file mode 100644 index 000000000..ad05bbfd8 --- /dev/null +++ b/docs/index.fr.md @@ -0,0 +1,17 @@ +# Documentation de Gangway + +gangway +======= + +_(noun): An opening in the bulwark of the ship to allow passengers to board or leave the ship._ + +Une application qui peut être utilisée pour faciliter les flux d'authentification via OIDC pour un cluster Kubernetes. +Kubernetes prend en charge les [jetons OpenID Connect](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) comme moyen d'identifier les utilisateurs qui accèdent au cluster. +Gangway a été amélioré et est maintenant capable de gérer plusieurs clusters. +Gangway permet aux utilisateurs de configurer eux-mêmes leur configuration `kubectl` en quelques étapes simples. + +![gangway multicluster](images/gangway-multicluster.png) + +Une fois authentifié pour l'un de vos clusters : + +![gangway](images/gangway.png) diff --git a/docs/index.md b/docs/index.md index 1940d1fae..2d0b40690 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,17 @@ -# Gangway documentation +# Documentation de Gangway -bla \ No newline at end of file +gangway +======= + +_(nom) : Une ouverture dans le parapet du navire pour permettre aux passagers de monter à bord ou de quitter le navire._ + +Une application qui peut être utilisée pour faciliter les flux d'authentification via OIDC pour un cluster Kubernetes. +Kubernetes prend en charge les [jetons OpenID Connect](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) comme moyen d'identifier les utilisateurs qui accèdent au cluster. +Gangway a été amélioré et est maintenant capable de gérer plusieurs clusters. +Gangway permet aux utilisateurs de configurer eux-mêmes leur configuration `kubectl` en quelques étapes simples. + +![gangway multicluster](images/gangway-multicluster.png) + +Une fois authentifié pour l'un de vos clusters : + +![gangway](images/gangway.png) diff --git a/mkdocs.yml b/mkdocs.yml index 4d015bc5e..a3edd805e 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -43,27 +43,35 @@ markdown_extensions: emoji_index: !!python/name:material.extensions.emoji.twemoji emoji_generator: !!python/name:material.extensions.emoji.to_svg -# nav: -# - Home: index.md -# - Getting Started: -# - getting-started/installation.md -# - getting-started/quick-start.md -# - getting-started/philosophy.md -# - Configuration: -# - setup/index.md -# - setup/choosing-the-structure.md -# - setup/setting-up-languages.md -# - setup/translating-content.md -# - setup/controlling-your-builds.md -# - setup/localizing-navigation.md -# - setup/using-i18n-context.md -# - setup/using-alternates.md -# - setup/upgrading-to-1.md -# - Plugins Compatibility: -# - setup/setting-up-material.md -# - setup/setting-up-search.md -# - setup/plugins-compatibility.md -# - Changelog: changelog.md +nav: + - Home: index.md + - Getting Started: + - getting-started/configuration.md + - getting-started/deployment.md + - getting-started/helm-deployment.md + - getting-started/build.md + - getting-started/api-flags.md + - How it Work: + - how-it-work/how-it-work.md + - how-it-work/auth0.md + - how-it-work/dex.md + - how-it-work/google.md + - how-it-work/custom-templates.md + #- Plugins Compatibility: + # - setup/setting-up-material.md + # - setup/setting-up-search.md + # - setup/plugins-compatibility.md + #- Changelog: changelog.md plugins: - search + - i18n: + docs_structure: suffix + languages: + - locale: en + default: true + name: English + build: true + - locale: fr + name: Français + build: true \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 977da28f8..28596fb33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ version = "1.0" description = "Gangway Kubernetes configuration generator documentation" readme = "README.md" license = "MIT" -requires-python = ">=3.11" +requires-python = ">=3.10" authors = [ { name = "Numberly", email = "guillaume.legrain@numberly.com" }, ] @@ -18,6 +18,7 @@ classifiers = [ ] dependencies = [ "mkdocs>=1.5.3", + "mkdocs-static-i18n", ] [project.urls] From 16877f0f814703693be025f04a3886e1dee9a636 Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Sun, 12 Nov 2023 14:47:03 +0100 Subject: [PATCH 03/16] Update readme --- README.md | 98 +++++-------------------------------------------------- 1 file changed, 8 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index 07f07c59e..064a297a3 100644 --- a/README.md +++ b/README.md @@ -1,96 +1,14 @@ -# Welcome to Numberly/Gangway a new fork with multi-cluster improvements +# Gangway by Numberly -Gangway is EOL but still used at Numberly, we decided to fork and maintain it. +## Introduction -See the original repository : https://github.com/vmware-archive/gangway +Welcome to Numberly/Gangway, a maintained fork of the original Gangway project, now End-Of-Life (EOL). It simplifies authentication flows using OpenID Connect (OIDC) for Kubernetes clusters, focusing on multi-cluster support. -This fork aims to continue development of Gangway by Numberly corporation. +## Features -gangway -======= +- **Multi-Cluster Management**: Manages multiple clusters to reduce complexity. +- **OIDC Authentication**: Streamlines ID token minting for Kubernetes API server access. -_(noun): An opening in the bulwark of the ship to allow passengers to board or leave the ship._ +## Building from Source -An application that can be used to easily enable authentication flows via OIDC for a kubernetes cluster. -Kubernetes supports [OpenID Connect Tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) as a way to identify users who access the cluster. -Gangway has been improved and is now able to handle multiple clusters -Gangway allows users to self-configure their `kubectl` configuration in a few short steps. - -![gangway multicluster](docs/images/gangway-multicluster.png) - -Once authenticated for one of your cluster : - -![gangway](docs/images/gangway.png) - -## Deployment - -Instructions for deploying gangway for common cloud providers can be found [here](docs/README.md). - -We can use our dedicated helm chart that will allow you to configure Gangway easily [here](chart/README.md) - -## The multi-cluster way - -At Numberly, initially, we was deploying 1 gangway per cluster which could lead to a lot of WebUI to connect -our clusters. One of the goal of the fork was also to permit to Gangway to manage any clusters to facilitate -our management. Gangway can now take a configuration with environment and a list of cluster for each environments. -You can read more about it [here](docs/configuration.md) - -## How It Works - -Kubernetes supports OpenID Connect (OIDC) as a user authentication mechanism. OIDC is an -authentication protocol that allows servers to verify the identity of a user by way of an ID Token. - -When using OIDC to authenticate with Kubernetes, the client (e.g. `kubectl`) sends the ID token -alongside all requests to the API server. On the server side, the Kubernetes API server verifies the -token to ensure it is valid and has not expired. Once verified, the API server extracts username and -group membership information from the token, and continues processing the request. - -In order to obtain the ID token, the user must go through the OIDC authentication process. This is -where Gangway comes in. Gangway is a web application that enables the OIDC authentication flow which -results in the minting of the ID Token. - -Gangway is configured as a client of an upstream Identity Service that speaks OIDC. To obtain the ID -token, the user accesses Gangway, initiates the OIDC flow by clicking the "Log In" button, and -completes the flow by authenticating with the upstream Identity Service. The user's credentials are -never shared with Gangway. - -Once the authentication flow is complete, the user is redirected to a Gangway page that provides -instructions on how to configure `kubectl` to use the ID token. - -The following sequence diagram details the authentication flow: - -

- -

- -## API-Server flags - -gangway requires that the Kubernetes API server is configured for OIDC: - -https://kubernetes.io/docs/admin/authentication/#configuring-the-api-server - -```bash -kube-apiserver -... ---oidc-issuer-url="https://example.auth0.com/" ---oidc-client-id=3YM4ue8MoXgBkvCIHh00000000000 ---oidc-username-claim=email ---oidc-groups-claim=groups -``` - -## Build - -Requirements for building - -- Go (built with version >= 1.21) - -A Makefile is provided for building tasks. The options are as follows - -Getting started is as simple as: - -```bash -go get -u github.com/soulkyu/gangway -cd $GOPATH/src/github.com/soulkyu/gangway -make setup -make -``` +Written in Go (83.9%). \ No newline at end of file From b41ce91da2715936ff81f292700d3814d5e9c9ee Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Sun, 12 Nov 2023 21:08:17 +0100 Subject: [PATCH 04/16] Add gangway documentation link --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 064a297a3..2e73e55fd 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,10 @@ Welcome to Numberly/Gangway, a maintained fork of the original Gangway project, - **Multi-Cluster Management**: Manages multiple clusters to reduce complexity. - **OIDC Authentication**: Streamlines ID token minting for Kubernetes API server access. +## Documentation + +Checkout the [GANGWAY Documentation](https://link-to-doc.numberly.com) + ## Building from Source Written in Go (83.9%). \ No newline at end of file From 102b2c9c76da250e14420c829a947b5ae1c714c4 Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Mon, 13 Nov 2023 11:59:19 +0100 Subject: [PATCH 05/16] File should be in english --- docs/getting-started/deployment.md | 12 +-- docs/getting-started/helm-deployment.md | 132 ++++++++++++------------ docs/how-it-work/custom-templates.md | 14 +-- docs/index.md | 16 +-- 4 files changed, 87 insertions(+), 87 deletions(-) diff --git a/docs/getting-started/deployment.md b/docs/getting-started/deployment.md index cc8094e0b..7ecb43d43 100644 --- a/docs/getting-started/deployment.md +++ b/docs/getting-started/deployment.md @@ -1,12 +1,12 @@ -# Déploiement de Gangway +# Deploying Gangway -Le déploiement de Gangway consiste à écrire un fichier de configuration, puis à déployer le service. -Le service est sans état, il est donc relativement facile à gérer sur Kubernetes. -La manière dont vous fournirez l'accès au service dépendra de votre configuration spécifique. +Deploying Gangway consists of writing a config file and then deploying the service. +The service is stateless so it is relatively easy to manage on Kubernetes. +How you provide access to the service is going to be dependent on your specific configuration. -Gangway est maintenant conscient d'une configuration multi-cluster, nous avons développé un chart Helm qui facilitera le déploiement. +Gangway is now aware of a multi-cluster configuration, we have developped a helm chart that will made deployment easily. -Voici un exemple de configuration : +Here is a configration example : ```yaml host: 0.0.0.0 diff --git a/docs/getting-started/helm-deployment.md b/docs/getting-started/helm-deployment.md index 22ce74a24..c7fade2f6 100644 --- a/docs/getting-started/helm-deployment.md +++ b/docs/getting-started/helm-deployment.md @@ -1,94 +1,94 @@ -# Configuration du Chart Helm pour Gangway +# Helm Chart Configuration for Gangway -Ce document décrit les paramètres configurables du chart Helm pour Gangway et leurs valeurs par défaut. +This document outlines the configurable parameters of the Helm chart for Gangway and their default values. -## Paramètres Globaux +## Global Parameters -- `global.imageRegistry` : Registre global d'images Docker (par défaut : `""`) -- `global.imagePullSecrets` : Noms des secrets de registre Docker global sous forme de tableau (par défaut : `[]`) -- `global.storageClass` : Classe de stockage globale pour le(s) volume(s) persistant(s) (par défaut : `""`) +- `global.imageRegistry`: Global Docker image registry (default: `""`) +- `global.imagePullSecrets`: Global Docker registry secret names as an array (default: `[]`) +- `global.storageClass`: Global StorageClass for Persistent Volume(s) (default: `""`) -## Paramètres Communs +## Common Parameters -- `kubeVersion` : Forcer la version cible de Kubernetes (par défaut : `""`) -- `nameOverride` : Chaîne pour remplacer partiellement le modèle `common.names.fullname` (par défaut : `""`) -- `fullnameOverride` : Chaîne pour remplacer entièrement le modèle `common.names.fullname` (par défaut : `""`) -- `commonLabels` : Étiquettes à ajouter à tous les objets déployés (par défaut : `{}`) -- `commonAnnotations` : Annotations à ajouter à tous les objets déployés (par défaut : `{}`) -- `clusterDomain` : Domaine de cluster Kubernetes par défaut (par défaut : `cluster.local`) -- `extraDeploy` : Tableau d'objets supplémentaires à déployer avec la release (par défaut : `[]`) +- `kubeVersion`: Force target Kubernetes version (default: `""`) +- `nameOverride`: String to partially override `common.names.fullname` template (default: `""`) +- `fullnameOverride`: String to fully override `common.names.fullname` template (default: `""`) +- `commonLabels`: Labels to add to all deployed objects (default: `{}`) +- `commonAnnotations`: Annotations to add to all deployed objects (default: `{}`) +- `clusterDomain`: Default Kubernetes cluster domain (default: `cluster.local`) +- `extraDeploy`: Array of extra objects to deploy with the release (default: `[]`) -## Paramètres de l'Image Gangway +## Gangway Image Parameters -- `image.registry` : Registre d'image Gangway (par défaut : `docker.io`) -- `image.repository` : Dépôt d'image Gangway (par défaut : `numberlyinfra/gangway`) -- `image.tag` : Tag de l'image Gangway (par défaut : `master`) -- `image.digest` : Digest de l'image Gangway (par défaut : `""`) -- `image.pullPolicy` : Politique de téléchargement de l'image (par défaut : `Always`) -- `image.pullSecrets` : Spécifier les noms des secrets de registre Docker sous forme de tableau (par défaut : `[]`) -- `image.debug` : Activer le mode debug de l'image Gangway (par défaut : `false`) +- `image.registry`: Gangway image registry (default: `docker.io`) +- `image.repository`: Gangway image repository (default: `numberlyinfra/gangway`) +- `image.tag`: Gangway image tag (default: `master`) +- `image.digest`: Gangway image digest (default: `""`) +- `image.pullPolicy`: Image pull policy (default: `Always`) +- `image.pullSecrets`: Specify docker-registry secret names as an array (default: `[]`) +- `image.debug`: Enable Gangway image debug mode (default: `false`) -## Paramètres de Déploiement de Gangway +## Gangway Deployment Parameters -- `replicaCount` : Nombre de répliques de Gangway à déployer (par défaut : `3`) -- `updateStrategy.type` : StrategyType peut être défini sur `RollingUpdate` ou `OnDelete` (par défaut : `RollingUpdate`) -- `podSecurityContext.enabled` : Activer le contexte de sécurité des pods Gangway (par défaut : `true`) -- `podSecurityContext.fsGroup` : ID de groupe pour les volumes du pod (par défaut : `1001`) -- `containerSecurityContext.enabled` : Activer le contexte de sécurité des conteneurs Gangway (par défaut : `true`) -- `containerSecurityContext.runAsUser` : ID utilisateur pour exécuter les conteneurs Gangway (par défaut : `1001`) -- `containerSecurityContext.runAsNonRoot` : Définir le contexte de sécurité du conteneur Gangway runAsNonRoot (par défaut : `true`) -- `resources.limits` : Les limites de ressources pour le conteneur Gangway (par défaut : `{}`) -- `resources.requests` : Les ressources demandées pour le conteneur Gangway (par défaut : `{ memory: "512Mi", cpu: "300m" }`) +- `replicaCount`: Number of Gangway replicas to deploy (default: `3`) +- `updateStrategy.type`: StrategyType can be set to `RollingUpdate` or `OnDelete` (default: `RollingUpdate`) +- `podSecurityContext.enabled`: Enable Gangway pods' Security Context (default: `true`) +- `podSecurityContext.fsGroup`: Group ID for the volumes of the pod (default: `1001`) +- `containerSecurityContext.enabled`: Enable Gangway containers' SecurityContext (default: `true`) +- `containerSecurityContext.runAsUser`: User ID to run Gangway containers (default: `1001`) +- `containerSecurityContext.runAsNonRoot`: Set Gangway container's Security Context runAsNonRoot (default: `true`) +- `resources.limits`: The resources limits for the Gangway container (default: `{}`) +- `resources.requests`: The requested resources for the Gangway container (default: `{ memory: "512Mi", cpu: "300m" }`) ## Probes -- `startupProbe.enabled` : Activer startupProbe (par défaut : `false`) -- `livenessProbe.enabled` : Activer livenessProbe (par défaut : `true`) -- `readinessProbe.enabled` : Activer readinessProbe (par défaut : `true`) +- `startupProbe.enabled`: Enable startupProbe (default: `false`) +- `livenessProbe.enabled`: Enable livenessProbe (default: `true`) +- `readinessProbe.enabled`: Enable readinessProbe (default: `true`) -## Configuration du Service +## Service Configuration -- `service.type` : Type de service Kubernetes (par défaut : `ClusterIP`) -- `service.ports.http` : Port HTTP du service (par défaut : `8080`) -- `service.sessionAffinity` : Affinité de session pour le service Kubernetes (par défaut : `ClientIP`) +- `service.type`: Kubernetes Service type (default: `ClusterIP`) +- `service.ports.http`: Service HTTP port (default: `8080`) +- `service.sessionAffinity`: Session Affinity for Kubernetes service (default: `ClientIP`) -## Configuration de l'Ingress +## Ingress Configuration -- `ingress.enabled` : Définir sur true pour activer la génération de l'enregistrement d'ingress (par défaut : `false`) -- `ingress.hostname` : Hôte par défaut pour la ressource ingress (par défaut : `gangway.local`) -- `ingress.path` : Le chemin vers Gangway (par défaut : `/`) -- `ingress.annotations` : Annotations supplémentaires pour la ressource Ingress (par défaut : `{}`) +- `ingress.enabled`: Set to true to enable ingress record generation (default: `false`) +- `ingress.hostname`: Default host for the ingress resource (default: `gangway.local`) +- `ingress.path`: The Path to Gangway (default: `/`) +- `ingress.annotations`: Additional annotations for the Ingress resource (default: `{}`) -## Configuration Supplémentaire +## Additional Configuration -- `extraEnvVars` : Variables d'environnement supplémentaires à définir sur le conteneur Gangway (par défaut : `[]`) -- `extraVolumes` : Spécifier éventuellement une liste supplémentaire de volumes pour les pods Gangway (par défaut : `[]`) -- `extraVolumeMounts` : Spécifier éventuellement une liste supplémentaire de volumeMounts pour le(s) conteneur(s) Gangway (par défaut : `[]`) +- `extraEnvVars`: Extra environment variables to be set on Gangway container (default: `[]`) +- `extraVolumes`: Optionally specify extra list of additional volumes for Gangway pods (default: `[]`) +- `extraVolumeMounts`: Optionally specify extra list of additional volumeMounts for Gangway container(s) (default: `[]`) -## Affinité et Tolérances +## Affinity and Tolerations -- `podAffinityPreset` : Préréglage d'affinité de pod (par défaut : `""`) -- `podAntiAffinityPreset` : Préréglage d'anti-affinité de pod (par défaut : `soft`) -- `nodeAffinityPreset.type` : Type de préréglage d'affinité de nœud (par défaut : `""`) -- `affinity` : Affinité pour l'assignation de pod (par défaut : `{}`) -- `nodeSelector` : Étiquettes de nœud pour l'assignation de pod (par défaut : `{}`) -- `tolerations` : Tolérances pour l'assignation de pod (par défaut : `[]`) +- `podAffinityPreset`: Pod affinity preset (default: `""`) +- `podAntiAffinityPreset`: Pod anti-affinity preset (default: `soft`) +- `nodeAffinityPreset.type`: Node affinity preset type (default: `""`) +- `affinity`: Affinity for pod assignment (default: `{}`) +- `nodeSelector`: Node labels for pod assignment (default: `{}`) +- `tolerations`: Tolerations for pod assignment (default: `[]`) -## Personnalisation +## Customization -- `command` : Remplacer la commande par défaut du conteneur (par défaut : `[]`) -- `args` : Remplacer les arguments par défaut du conteneur (par défaut : `[]`) -- `lifecycleHooks` : pour le(s) conteneur(s) Gangway afin d'automatiser la configuration avant ou après le démarrage (par défaut : `{}`) -- `extraEnvVarsCM` : Nom du ConfigMap existant contenant des variables d'environnement supplémentaires (par défaut : `""`) -- `extraEnvVarsSecret` : Nom du Secret existant contenant des variables d'environnement supplémentaires (par défaut : `""`) +- `command`: Override default container command (default: `[]`) +- `args`: Override default container args (default: `[]`) +- `lifecycleHooks`: for the Gangway container(s) to automate configuration before or after startup (default: `{}`) +- `extraEnvVarsCM`: Name of existing ConfigMap containing extra env vars (default: `""`) +- `extraEnvVarsSecret`: Name of existing Secret containing extra env vars (default: `""`) -## Session et Configuration +## Session and Configuration -- `sessionkey` : Clé de session (par défaut : `mySessionKey`) -- `sessionsalt` : Sel de session (par défaut : `mySessionSalt`) -- `configuration` : Configuration en ligne pour Gangway (par défaut : `""`) +- `sessionkey`: Session key (default: `mySessionKey`) +- `sessionsalt`: Session salt (default: `mySessionSalt`) +- `configuration`: Inline configuration for Gangway (default: `""`) -## Exemple de configuration : +## Example of configuration : ```yaml host: 0.0.0.0 port: 8080 diff --git a/docs/how-it-work/custom-templates.md b/docs/how-it-work/custom-templates.md index 107ead3a6..63032d6bb 100644 --- a/docs/how-it-work/custom-templates.md +++ b/docs/how-it-work/custom-templates.md @@ -1,14 +1,14 @@ -# Modèles Personnalisés +# Custom Templates -Pour personnaliser les pages HTML rendues par Gangway, vous pouvez fournir un ensemble de modèles personnalisés à utiliser à la place de ceux intégrés. +To customize the HTML pages rendered by Gangway, you may provide a set of custom templates to use instead of the built-in ones. -:exclamation: **Important : Les données transmises aux modèles peuvent changer entre les versions, et nous ne garantissons pas que nous maintiendrons la compatibilité avec les versions antérieures. Si vous utilisez des modèles personnalisés, une attention particulière doit être portée lors de la mise à niveau de Gangway.** +:exclamation: **Important: The data passed to the templates might change between versions, and we do not guarantee that we will maintain backwards compatibility. If using custom templates, extra care must be taken when upgrading Gangway.** -Pour activer cette fonctionnalité, définissez l'option `customHTMLTemplatesDir` dans le fichier de configuration de Gangway pour un répertoire qui contient les modèles personnalisés suivants : +To enable this feature, set the `customHTMLTemplatesDir` option in Gangway's configuration file to a directory that contains the following custom templates: -* home.tmpl : Modèle de la page d'accueil. -* commandline.tmpl : Modèle post-connexion qui liste généralement les commandes nécessaires pour configurer `kubectl`. +* home.tmpl: Home page template. +* commandline.tmpl: Post-login template that typically lists the commands needed to configure `kubectl`. -Les modèles sont traités en utilisant le [package][0] `html/template` de Go. +The templates are processed using Go's `html/template` [package][0]. [0]: https://golang.org/pkg/html/template/ diff --git a/docs/index.md b/docs/index.md index 2d0b40690..e7350e2ce 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,17 +1,17 @@ -# Documentation de Gangway +# Gangway documentation gangway ======= -_(nom) : Une ouverture dans le parapet du navire pour permettre aux passagers de monter à bord ou de quitter le navire._ +_(noun): An opening in the bulwark of the ship to allow passengers to board or leave the ship._ -Une application qui peut être utilisée pour faciliter les flux d'authentification via OIDC pour un cluster Kubernetes. -Kubernetes prend en charge les [jetons OpenID Connect](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) comme moyen d'identifier les utilisateurs qui accèdent au cluster. -Gangway a été amélioré et est maintenant capable de gérer plusieurs clusters. -Gangway permet aux utilisateurs de configurer eux-mêmes leur configuration `kubectl` en quelques étapes simples. +An application that can be used to easily enable authentication flows via OIDC for a kubernetes cluster. +Kubernetes supports [OpenID Connect Tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) as a way to identify users who access the cluster. +Gangway has been improved and is now able to handle multiple clusters +Gangway allows users to self-configure their `kubectl` configuration in a few short steps. ![gangway multicluster](images/gangway-multicluster.png) -Une fois authentifié pour l'un de vos clusters : +Once authenticated for one of your cluster : -![gangway](images/gangway.png) +![gangway](images/gangway.png) \ No newline at end of file From 29af6b62514505460dd801ab9a81484ce7f4e245 Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Mon, 13 Nov 2023 12:00:07 +0100 Subject: [PATCH 06/16] Rename to how-it-works --- docs/{how-it-work => how-it-works}/auth0.fr.md | 0 docs/{how-it-work => how-it-works}/auth0.md | 0 .../custom-templates.fr.md | 0 .../custom-templates.md | 0 docs/{how-it-work => how-it-works}/dex.fr.md | 0 docs/{how-it-work => how-it-works}/dex.md | 0 docs/{how-it-work => how-it-works}/google.fr.md | 0 docs/{how-it-work => how-it-works}/google.md | 0 .../how-it-works.fr.md} | 0 .../how-it-work.md => how-it-works/how-it-works.md} | 0 .../images/gangway-sequence-diagram.png | Bin .../images/goauth-add-credentials-menu.png | Bin .../images/goauth-client-settings.png | Bin .../images/goauth-empty.png | Bin 14 files changed, 0 insertions(+), 0 deletions(-) rename docs/{how-it-work => how-it-works}/auth0.fr.md (100%) rename docs/{how-it-work => how-it-works}/auth0.md (100%) rename docs/{how-it-work => how-it-works}/custom-templates.fr.md (100%) rename docs/{how-it-work => how-it-works}/custom-templates.md (100%) rename docs/{how-it-work => how-it-works}/dex.fr.md (100%) rename docs/{how-it-work => how-it-works}/dex.md (100%) rename docs/{how-it-work => how-it-works}/google.fr.md (100%) rename docs/{how-it-work => how-it-works}/google.md (100%) rename docs/{how-it-work/how-it-work.fr.md => how-it-works/how-it-works.fr.md} (100%) rename docs/{how-it-work/how-it-work.md => how-it-works/how-it-works.md} (100%) rename docs/{how-it-work => how-it-works}/images/gangway-sequence-diagram.png (100%) rename docs/{how-it-work => how-it-works}/images/goauth-add-credentials-menu.png (100%) rename docs/{how-it-work => how-it-works}/images/goauth-client-settings.png (100%) rename docs/{how-it-work => how-it-works}/images/goauth-empty.png (100%) diff --git a/docs/how-it-work/auth0.fr.md b/docs/how-it-works/auth0.fr.md similarity index 100% rename from docs/how-it-work/auth0.fr.md rename to docs/how-it-works/auth0.fr.md diff --git a/docs/how-it-work/auth0.md b/docs/how-it-works/auth0.md similarity index 100% rename from docs/how-it-work/auth0.md rename to docs/how-it-works/auth0.md diff --git a/docs/how-it-work/custom-templates.fr.md b/docs/how-it-works/custom-templates.fr.md similarity index 100% rename from docs/how-it-work/custom-templates.fr.md rename to docs/how-it-works/custom-templates.fr.md diff --git a/docs/how-it-work/custom-templates.md b/docs/how-it-works/custom-templates.md similarity index 100% rename from docs/how-it-work/custom-templates.md rename to docs/how-it-works/custom-templates.md diff --git a/docs/how-it-work/dex.fr.md b/docs/how-it-works/dex.fr.md similarity index 100% rename from docs/how-it-work/dex.fr.md rename to docs/how-it-works/dex.fr.md diff --git a/docs/how-it-work/dex.md b/docs/how-it-works/dex.md similarity index 100% rename from docs/how-it-work/dex.md rename to docs/how-it-works/dex.md diff --git a/docs/how-it-work/google.fr.md b/docs/how-it-works/google.fr.md similarity index 100% rename from docs/how-it-work/google.fr.md rename to docs/how-it-works/google.fr.md diff --git a/docs/how-it-work/google.md b/docs/how-it-works/google.md similarity index 100% rename from docs/how-it-work/google.md rename to docs/how-it-works/google.md diff --git a/docs/how-it-work/how-it-work.fr.md b/docs/how-it-works/how-it-works.fr.md similarity index 100% rename from docs/how-it-work/how-it-work.fr.md rename to docs/how-it-works/how-it-works.fr.md diff --git a/docs/how-it-work/how-it-work.md b/docs/how-it-works/how-it-works.md similarity index 100% rename from docs/how-it-work/how-it-work.md rename to docs/how-it-works/how-it-works.md diff --git a/docs/how-it-work/images/gangway-sequence-diagram.png b/docs/how-it-works/images/gangway-sequence-diagram.png similarity index 100% rename from docs/how-it-work/images/gangway-sequence-diagram.png rename to docs/how-it-works/images/gangway-sequence-diagram.png diff --git a/docs/how-it-work/images/goauth-add-credentials-menu.png b/docs/how-it-works/images/goauth-add-credentials-menu.png similarity index 100% rename from docs/how-it-work/images/goauth-add-credentials-menu.png rename to docs/how-it-works/images/goauth-add-credentials-menu.png diff --git a/docs/how-it-work/images/goauth-client-settings.png b/docs/how-it-works/images/goauth-client-settings.png similarity index 100% rename from docs/how-it-work/images/goauth-client-settings.png rename to docs/how-it-works/images/goauth-client-settings.png diff --git a/docs/how-it-work/images/goauth-empty.png b/docs/how-it-works/images/goauth-empty.png similarity index 100% rename from docs/how-it-work/images/goauth-empty.png rename to docs/how-it-works/images/goauth-empty.png From 9dcad6ce793c11768fa15410267a08c17328bf0f Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Mon, 13 Nov 2023 12:03:32 +0100 Subject: [PATCH 07/16] Rename to how-it-works --- mkdocs.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index a3edd805e..ba8369aa7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,11 +52,11 @@ nav: - getting-started/build.md - getting-started/api-flags.md - How it Work: - - how-it-work/how-it-work.md - - how-it-work/auth0.md - - how-it-work/dex.md - - how-it-work/google.md - - how-it-work/custom-templates.md + - how-it-works/how-it-work.md + - how-it-works/auth0.md + - how-it-works/dex.md + - how-it-works/google.md + - how-it-works/custom-templates.md #- Plugins Compatibility: # - setup/setting-up-material.md # - setup/setting-up-search.md From 9024cd36a458509913187a7f969e26bc2752f94c Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Mon, 13 Nov 2023 12:04:00 +0100 Subject: [PATCH 08/16] Rename to how-it-works --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index ba8369aa7..bce97f88b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -52,7 +52,7 @@ nav: - getting-started/build.md - getting-started/api-flags.md - How it Work: - - how-it-works/how-it-work.md + - how-it-works/how-it-works.md - how-it-works/auth0.md - how-it-works/dex.md - how-it-works/google.md From 51d566fb9b52a18e0f7f11f8c019db4835098d19 Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Mon, 13 Nov 2023 12:04:56 +0100 Subject: [PATCH 09/16] Rename to how-it-works --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index bce97f88b..62eb671bb 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -51,7 +51,7 @@ nav: - getting-started/helm-deployment.md - getting-started/build.md - getting-started/api-flags.md - - How it Work: + - How it Works: - how-it-works/how-it-works.md - how-it-works/auth0.md - how-it-works/dex.md From b370154a2d259e1bba8e4d8ae9b0769abb175cb3 Mon Sep 17 00:00:00 2001 From: Ultrabug Date: Mon, 13 Nov 2023 15:02:55 +0100 Subject: [PATCH 10/16] docs: custom templates to use admonitions --- docs/how-it-works/custom-templates.fr.md | 3 ++- docs/how-it-works/custom-templates.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/how-it-works/custom-templates.fr.md b/docs/how-it-works/custom-templates.fr.md index 107ead3a6..981c1d674 100644 --- a/docs/how-it-works/custom-templates.fr.md +++ b/docs/how-it-works/custom-templates.fr.md @@ -2,7 +2,8 @@ Pour personnaliser les pages HTML rendues par Gangway, vous pouvez fournir un ensemble de modèles personnalisés à utiliser à la place de ceux intégrés. -:exclamation: **Important : Les données transmises aux modèles peuvent changer entre les versions, et nous ne garantissons pas que nous maintiendrons la compatibilité avec les versions antérieures. Si vous utilisez des modèles personnalisés, une attention particulière doit être portée lors de la mise à niveau de Gangway.** +!!! danger "Important" + Les données transmises aux modèles peuvent changer entre les versions, et nous ne garantissons pas que nous maintiendrons la compatibilité avec les versions antérieures. Si vous utilisez des modèles personnalisés, une attention particulière doit être portée lors de la mise à niveau de Gangway.** Pour activer cette fonctionnalité, définissez l'option `customHTMLTemplatesDir` dans le fichier de configuration de Gangway pour un répertoire qui contient les modèles personnalisés suivants : diff --git a/docs/how-it-works/custom-templates.md b/docs/how-it-works/custom-templates.md index 63032d6bb..4c0e15bac 100644 --- a/docs/how-it-works/custom-templates.md +++ b/docs/how-it-works/custom-templates.md @@ -2,7 +2,8 @@ To customize the HTML pages rendered by Gangway, you may provide a set of custom templates to use instead of the built-in ones. -:exclamation: **Important: The data passed to the templates might change between versions, and we do not guarantee that we will maintain backwards compatibility. If using custom templates, extra care must be taken when upgrading Gangway.** +!!! danger "Important" + The data passed to the templates might change between versions, and we do not guarantee that we will maintain backwards compatibility. If using custom templates, extra care must be taken when upgrading Gangway.** To enable this feature, set the `customHTMLTemplatesDir` option in Gangway's configuration file to a directory that contains the following custom templates: From 72b8b1f299961ac12dda066c1433beb35101db9b Mon Sep 17 00:00:00 2001 From: Ultrabug Date: Mon, 13 Nov 2023 15:03:20 +0100 Subject: [PATCH 11/16] home: hide useless sidebars --- docs/index.fr.md | 6 ++++++ docs/index.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/docs/index.fr.md b/docs/index.fr.md index ad05bbfd8..1e47f6928 100644 --- a/docs/index.fr.md +++ b/docs/index.fr.md @@ -1,3 +1,9 @@ +--- +hide: + - navigation + - toc +--- + # Documentation de Gangway gangway diff --git a/docs/index.md b/docs/index.md index e7350e2ce..7837ad8de 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,3 +1,9 @@ +--- +hide: + - navigation + - toc +--- + # Gangway documentation gangway From cbe697967ddea3cc2ddae541ee66ca6ed8edab8a Mon Sep 17 00:00:00 2001 From: Ultrabug Date: Mon, 13 Nov 2023 15:03:51 +0100 Subject: [PATCH 12/16] docs: google fix title --- docs/how-it-works/google.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how-it-works/google.md b/docs/how-it-works/google.md index 3defbace5..2614b53c4 100644 --- a/docs/how-it-works/google.md +++ b/docs/how-it-works/google.md @@ -1,4 +1,4 @@ -# Connecting gangway to Google +# Connecting Gangway to Google It is possible to use Google as an OAuth provider with gangway. To do so follow the instructions below: ## Setting Up Google OAuth From 9d01560522b93d6349aef1b3701139c2e68f054d Mon Sep 17 00:00:00 2001 From: Ultrabug Date: Mon, 13 Nov 2023 15:04:20 +0100 Subject: [PATCH 13/16] mkdocs: drop comments --- mkdocs.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 62eb671bb..d1021e72d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,7 +3,6 @@ site_url: https://numberly.github.io/gangway repo_url: https://github.com/numberly/gangway docs_dir: docs/ -# exclude_docs: overrides/ copyright: Copyright © 2023 Numberly @@ -57,11 +56,6 @@ nav: - how-it-works/dex.md - how-it-works/google.md - how-it-works/custom-templates.md - #- Plugins Compatibility: - # - setup/setting-up-material.md - # - setup/setting-up-search.md - # - setup/plugins-compatibility.md - #- Changelog: changelog.md plugins: - search From a9bdb0127106e60f61452f2c66284a9a651ea241 Mon Sep 17 00:00:00 2001 From: Ultrabug Date: Mon, 13 Nov 2023 15:04:35 +0100 Subject: [PATCH 14/16] mkdocs: use a lock logo --- mkdocs.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index d1021e72d..2d7d0a7d9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,9 +9,8 @@ copyright: Copyright © 2023 Numberly theme: name: material font: false - # custom_dir: docs/overrides - # logo: - # assets/logo_by_maxicons.png + icon: + logo: material/lock palette: primary: blue features: From 117cd9e955c43b43e4222398572fb70ba1165547 Mon Sep 17 00:00:00 2001 From: Ultrabug Date: Mon, 13 Nov 2023 15:04:50 +0100 Subject: [PATCH 15/16] mkdocs: i18n french version translate nav and set a different color --- mkdocs.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 2d7d0a7d9..5383b810f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -67,4 +67,11 @@ plugins: build: true - locale: fr name: Français - build: true \ No newline at end of file + build: true + theme: + palette: + primary: red + nav_translations: + Home: Accueil + Getting Started: Démarrage Rapide + How it Works: Comment ça marche From 4d694e01843d6692554ed9a53b31b0f6b2c2d52c Mon Sep 17 00:00:00 2001 From: Guillaume LEGRAIN Date: Mon, 13 Nov 2023 16:02:17 +0100 Subject: [PATCH 16/16] Screen with good tool name : Gangway --- docs/images/gangway-multicluster.png | Bin 55828 -> 61353 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/images/gangway-multicluster.png b/docs/images/gangway-multicluster.png index b0272580b152b154491c8992aa36c54862d3d1b4..f5584cd083040d88296af33024d6ebe5c2a67a0c 100644 GIT binary patch literal 61353 zcmeFZbx@Z3_b!ZuC=!ZJ?{NI zXWp52=FFM-z3(5tIrr?iW#7;Jd}6I@UDvff>@RO6h0*Tf-$g<~LK77ckU>Ja?Sh1K zV-@8(`~**?KN9|R!3+$WM+>HmB09`P&g+Q0WIPwbKZy*2nU@#x>% zMDqXlhhM(9i6lv@>OWs5Vpgn^C;g;jVPK_qc4A>CzX(q%T*7=3+mLoP*vZHfQ?mG5EB@cdV%ai_|1+502bGNfj^MTUeD}Y% zNVLHmH~zgZ5!k%<@9lrd!;kQ;ClWcJg_vL#N$%i3Ri@YZ{Ird4>ppV1whbjwPJ)vl zi-<<;*8{#`adzcCXOAgb|L*kDmAjGnheP6g()$M?KU1Pik_c7iOjBE~Y?R4^q~UFt zzEfoT2Mx<_ZLD(8-wvae%kScS!1$=0iHjVGVqH2Wt?dH=72 ztT{(MKE97Xr!1CV_ z*ws9$?kA)kvgXR+FQRe(+3V#f#Jnskg1DP#vEwWRL<1??)H0fgA_y|7HWDkmrwDM2 zcuf1)ol|}2!)Qx=S>J@EtxVvoq*nh<7L@z;K>Yz`OKoBGi?^x}U5qUpk<|gAHal5r2ys>FXWzO@ zIfbdO50m!pwo%&@J)x=-!)?u%w@Ic^$CaiUPqEqE>8nC)rQi~Fk;YAr8s;VJU~5d9jX(AHFe>95GM?)f{=Aw{@z>Py+Xgk?It_=$ zRHxASGNzJh+Wz49(~5>aiHB z$F_&4uHh3lMK<{hCboxhMh&I8xPg>e6ue7p?2J`(he{#FS<+9QV~3J`&nzU9$qoor zn?X}Hl}PTEp=MQoT9x#Su3057Y8~P|RVc<8tpSI2bT-g71(rpVQZ+})A*L*9j&EuE zIeAs;j=xp2y^XFRyC#or9HrDynofroMT%RfMBy+>itHWhTg0V`^lW638j7h6cnO=o z_S6IIBXPe~d+p*0jwq5;-})DqdOxl}=1O>0dZZ~xdw27ph~j8T-j~mRs^3v3+RKMh zE+`{)W?JsL`bqwz*HO?RtzWmEHSv0Bl7=YzvIOPVuCm9}E6PUUsr*&~&4ublSdy-4 z5h~63a)ktMf>)1B2y>$c`+E@$uIeV&%9Rc1nun?qel)O};45o{w; zroc+*o{WWU_-sWV;!~Q6fQUCxWlO#xM=Cxq^4o*(l!HX930+cdp~3?+LAD9@(8hNQ z&A0wW8#|4a{+~g{LFzjv8dp5VbD!qp#pcRzy1miMRIQ(ERy4e4%aO!UKkRr$OL<@Q zgUO~v%EIl>s0A_)c6C>DJQGvI=PMeE+?38cXpu9QllL%G`jgVr1yM<7QL(QID`-L( zYfMwz3Q`MRw6OYT=WsUFCI>BcF9;v~^YzP7fV(y*6xH7cp9hMFqRf{w$i=v95kT&E9*lIWGMhf1IVw#Min`g#u%y}3oU)aoaFOp2GXpqpp zn69Jn;11by-O!Es3xC>OoFfxTWp&&UIUZ(dBQan5$UCHOiWt-DvY*o|&U4u)9@80= zW+qC8Pt)`1>^<@ra=8j0K%( zoEauKeZI1vtDL)?c9%3_gVO1bp9Jlz^THc4Q`HNc(+hr@XFG2Nx6KV*UHAKmcV_r} zzD;krE=8J1{;jv}12-xed!?0(@vR_`I-bYbG}p*B$P9etKqZ~PxxdJMLbs@r#@<)& zr{`#9^TouE4Iir&d9nL4nmB|eImp8%NQ(~Yfm!iWk8K`I(~PFDi2}RGEvus9)Flcb8wsb6&ivnAxRPpjv}%9wpd%ONqnqavTP1i#q$-zx9`X6N5hY6U487_7`?7( z&7OIL;>NUfFR~_}PCz#G{ZC7QwA@hsS_$jP!W3)OvBMd=)h>Ch!nzL8{Mk@5k~K5R z)|p<__0w&IsWZ<i_L$tTbq;iXN0BhHQBY5iDQ|wEWy$A}rE2n3<@e>p$;7_WL8+y}dp$mf z9}>(*+iPm^T_p~fi&AB12w7~ebTt!YTX;zKbH%^*zs*1Aye=81=eYG4bvy@aV8V z0TWB~*HspAA>naJHu^G~FIfc-`IKq`qfW)#?h(mN^gSV1Xz@^(GUxMHi4)}~dxK2s z(VA0pW!yax;CP$b1n}9o2;;Aa$Dl#D|9q{~a(iJZ$tzP-!C)(R zZ1~7doHuQ9<3R97V^!;dJTdD?#SYCJp12aMkmRVPR9Mm^KCxdizW$H>4LzdE_6zbQ z`yebnwFySvkWZYA7duBSHDW=z7Wg+2D;CQVwRO+t@#(1->eS(>SmrI>$SE@B^3eW1 z$E+faj&5(ZAay&|_GtA0gW>zTb^!qtY~8_ec)^({qv=) zHucs~7WHY1H-RUnhH|C;W((xuVRHo^ir{@g=I+nf5_z~MUERs*&CCI)k8p=xWzdhE z4%9uE=4nM2Ve6|arIXSs<>!vBA7QHxPDBNZOTh1%@#wM&J-4U~NAGiYu z5UlZ4_!;MOr>sUhnO%FCyB8Iyi<=L8U)ZN4lLTmMUzu2n;vDGB+>PWr?-?+Nu1q%H z3$|H%b1BwE6_`v>=AT_KOofIjQD#+V9Xqt#W5;u{(d%0)T*4kp&$4tzw=WTBG8}jk zen`%NuYKh1U%_0f?!xqvIKMqkScjO^i?)>E#!tZ|M zZ+O0o^Y38V{y;;F_H~BPChSSbY>)o<2JTUpA~&$1aYwk*}|5s{d! z$2_F+_=>H&aM?dhSeNWWu8bCZ8s+-2a<6iwuudKVdo#CjC>H6jY{Vo z^3;dkWzvf;Y9)7xC(D^@ClzH>-|8O82NK6Ws<#mTSWs(RLQY1fhEm90O~c$`bup?Q z`b47k0U3JO@Ci!=CF9TXriF;}?7P*~;okMH*0x>9obQsJW(cG;D-n=1e@~H5b>n{f zociHE!Yoz+I5T?cmx}$0JH0Y~<{F<()|7m5PiDkvNeWwZ8J=3^dQ&)~VvH`E1PQA} z?0a`*O|E-;V77H@^QX3^pjxQ}T9VLinwY>m=QF*upN#6-(*9O22;C$Z-TUb0EcC6E z#$A1B_n2O_VgJ&ttf-v&Fk-@z*9%kIX6vcjCTEp>Bi^aC{xmXRWB(M|%9WM8au5#T zWnkkFn{HXBhXrYqt-ie@6u&EZGG~_kCQX9BY~OtV8B&0aDPCuyf3(+kk*n_*FJ_we zYEW;oa6(38w~(#{_m`8Dx2w)x-lR)qG3FCU?H^;b?>@h>_mup_hY~p@XY6CLFew;? ze|)T)TFNQh1`!DW6TwHeRvkZ1;(up^&!3g|7C*k-hOsS}Ej1QI=L9 zqQpj|15&I8ta&#tdql?_!H|->!5kcJRQhp8N=jLwL0$HTc;vMi{6XOoBpO=&LDrF| zq%v`ys}pQ929rwGEb_Fv^08bxdd)5eZ5xw(dsqlnVpKKEtf~3FltuPy&RR=6Z$T0j2_ z_2q1rmXm(%(RzO0o%ozYVD>GdR{?4I?lZ)>o z8`WArIl5dF9y)~%?vPA;5a%BzRM*7bEWM?+rfI(IBl`JE%cW28+K%{!=WN6t{%Pgv z>lKOOVb{{U?-eb|Tj5+93nF=Y0CUr=xL72ou_veGDrE9SisN~r+_a~7V0ZSVo<748D`Ing ztawj6S|;3&e}9rC+|gbY=P*@5eg6AV=b%9sTgu#TUPu49KS)7QvazRLm|R`)BgfDE zS~ta$*KAwvzW=bcWvnk9u+;$ENyK{3b+@0RFsZ$Di2&Vk;Slfl@cyv=N_S%&>igTN zD5UxLz0F5bZfF4{hYv~0fA&4I-19J}l*0{jFQP@q2?wL%jF?5L>s^$?#?! zYF6O&&sMn+mcBWpVKmGXhE~G$ixJG6Df|7VOZrU4)8A8uO4I||8OpN|BW#{}5Hk)q z_6?KaG5KotWgDLlk#`Pi4pALi8IA(>$SY6G_ow9g6doAs56C?zbFECe3kJ8hBe%F_ zt0S9G2IMbfy;55#1fxALRZ+9gx&DU69~(ZX0q7x5?g@7YS2R4rnDGyri0~rpRm)(? zcQds>o$I6Q!J;tfi~A#>_)ap^QxZk%EvMn(2RG-UVl9@<`^7Ak){@^gMkcJL7YtLJ z6NZ>oY9;*1kNr={N+qXnX^Q&V^+r#za7wM#PH!0DHP&C6xff`(775AvW2Ysh3dIf` zAFXvCGP}mvD%G~@8lz8BQ(LpLbn4WbDjnqnNmgHawf(h(+y@@Q8XHChO0FDu5c#P| zeMEmdtsE?%+g>=JC};R5a7MmW#VDkN_@mw%))6AEp?DoHliF^F-~B`OmDOY;_CHrk z1s#n%FpGM_jS4dpd#F2(j@t#48us@x?z#P$jn87h`K;lK!5XjL4}g+!Ign?| zoKoh)h$j~@{t)%Bk%@PPs-N@P(ZVp_w5MO-V)He_t$rfGYXmf73W+B(ZoA{8(*i4g zFR{!xStU@CD7D)H8)HWiA%c`aeuE#$24`5M8D{{~QGr}k)LT+|VYV!<_QaLIujXwj#;;nVYo8UQSx|B^4oN@0qqSSr zPk3@GVxKP1i*w(HO|bE{g{;Ox2hY0WY4#eIYgJ?ckFTGmm)~Y9p=){eOm}j z=yRu>Qx*0a>B}o|Oxms*zi;xPXzJC1B>3+8nvvRwKw%?NQltA6C=03}7*fevv z`kI<5B6}5F#&6KOj)Xs#2Bd>YJ zf%lbLPB8(!$g6tkg1=kzs_Vt{qh-#A_nnofR{FjsjA=g&lE&41yvFrxqVauL;JBts zDDClPR@WkjGg?S8N4|`;dzF&9ZsgqTT$DCjCw2|Nq6&G9OkuMaP|*jvE9};B52UlA zOn+|i_1$p}%V&{%N+e^WVM-w!Nq_}=$A=R4_4e@kZ(?SV;As4v*zNeg?%C+tvSM+^ zY#}NssGaujueuT>_E?wP%BvmD*|Nx-C{ml1{GHS*Cu_;;jaC918=aeYIPBap8y4?= zFw5(rB{>+A3iV0{*_UN6qvKEhCgdrUli>xbEL$7}Hgx&lN0Gx$*lA?@!{$>hH9Q*q zss*7sf+y_MB8GlfCiEX57x++O#`j3%U*rwVkYs;%tIj!&F0Mi$HHwQjx5u?s`0LBY z=BMuKN4~i0zPNjP*#$RuNbExr;jD)43fh1bnps-M$3M1pK1rRSql=Exri5$4;CMI2^ki# zzR6}4B@X=>)MN6QSlT`Nsk$lOpEvp`{0xJrwZbAAf+$JL9^+3cbJ1eR=i4Hxe#F>% ziKk5xY;x~>H7WB9%UON6MV`jvNffuTKKxDWjVQBL->nF&ZcSpj+UEL*#GcDvb(O=N zhaV0v4d2w?7Cv~uM>8Sw!liE*{ZeI3t(J&~^5AOHAs=(L7|lEWlHE_191$#kY??pl zCx(8>46`kg>l577Z_l@A!>0QrU;9<=YVaLS_F#){+M0w+ttgXv6Mu-{gx08v^=^Js z*e{_-xwxk%MqFnVv?1dUY%=|hs=wP5ns)_)ZM-g#V5 zsS3kbcs8aHj(CwdONn+7YN+~(du#HM&u^fE;e^35l!83|==U|KyhoVi1NphshK2gwI9XdN%npIMij7kVI@4j!Ss_=6f*_5z|Jn5ew`<_WrR=z?O7!`UU8{hHf zi&oZy*zPj^vK06;+64u;_>xi z+wxm~bV2)BvuIPX4q{nSfjm+x>vc!uW`fPEfbBtf&t|4t7c+-+9(!oD44k)(va;xH=E)`JthA{T9H&dg|Ex(&?+&c9ztUiog(VW1q&|`FB%Bg_H<2(Mr zQQ$J0sf{_QN6Hk(-q~dA(|@!ID@+(`pshh=a;iA0QH`&nq+V8ZN8$|*KCPkyABFc5 z!aBc84x=E3eUa1E?@_Cv2t!55-gE1dxIP^-x#3hOYE|pBo$Jwf_ZFSU_v+fAZYO1h zWLmBJ>F>8tub2Qgq>qWn#KQ_-Np;f~!Iqt*hp zh2r5wy-4Zdzg;N{p|AZ3>J5}guZ4Sa%rw(!$L-muo!$mlQosLeHX*T-5%D7-5%GG_ zj*zfNJ_<$or^oerNiYr#$w2W-en?Bst?1f7N+}6kVXdMypMvJ3a+4t9rq_S>#=YAQ zW-t~cZI_^0DjKoRtQG9rE9kKLVJP;3Q|9;LZ!Kb?Xa982dcWK^MS6Yq1>tJi__DUB zr`46Q)99)0zss0v`1fs+0f@Ir<&hTs3c+7`&f3=9vVq-l%xQe|K=vj7Unc}f@&@#{ zdR`W6vj*RXSMBpQ?7GSd4+W(k3jH%qB&1%Nkf)*{sRJvWde$Z;xujH7ZEFWC z=y9S6{|pleDe3FeHaFgor?nd9EHP+bzI?gH7}xecyNpTOOWn!R`!qwt!>6D0X7&CZ z{_Bq8>js+pCNJ;(``=-m3zOx5Ec|m8;BQF(mvpcH zJFLwAU5$Sr?!V+@12VLqdU4k6&OY9_eYi1he=ww|nx}w#lSo-tcVVj5SzKJapn8*C z=*H{YNt9x|yg%z)&fvL>k+rSbBaIe7O`9hn$&~)rkzQjtIy&wx^&GkIb@%if)i&p9 z)^js31pnj}E;gI2B5^&|+M23`4^vZ9WAW+e>CtJ{#RgxqXm>fD@fMGyo2+-MpENrv zRkP_6OmI1TL(m~{^w>5o5jzmYPOBqh6t^Hj^tr|XPI^4r_nqY)Rras(M%Po5+v zCqH=b;PhyV=iLwYYd4T}baX^Qni6N;geD}^Yc+b&s+P?!E-o%DjSLR{Hen(47&R$V zq7fApH8eDQ^ytxz+vtQ$25+65*vXKQ45ZBKPSSa74xM53pS_8~#KmnrMndX-1I6CL z=(kB(vmb6x46Au-AQ3NX=HF{uU8B+}ZHrG^dv>`mrJ!;#`aYS^@`00AA=Zvlt*xzX zUtixn!DSdW4xQRDEW*}k@v~)Q_z!TUrKNG$Z|<|Er=dZ8(* z+YWtW%a)gy4-O7Kuf2<;{}RDKm`Q39oHyCratW*Y`}=R9;?O94f6UB$aCx?sz-0Kq zt;=4?8-rx3Sic7mQJa(1u+Z!4>oKqtp12zCboivz)Xq=W3g}fzer?#X+E0J_^a(b; z^BZG^YPp&Hw98Q!>$C|I{-b`1Uq!KTaU0Ibr}2d+Cnx4LJ1twTM;yq{Y+y{)_FGdU zB4T3g@QK!6Oou;jliW02uc>6DCn07g@owzPJsb!cSlLI*a(gE(CdOhq_K<*}LlzyW zTM0q6@=aLAv7|WrPM;=!|84=_KGzzgFC_16yVu2vi-YqLy=&pX>1ylhax1TV%IHG> zpr)o~Dc*UrmBcNU%bDfIxJRQmMnd7h4inS+7JvHs^CC<5mb;Dpzs>6}%1p;uY|mgR z?Y5>M`rTk@Yl2jSgj#~hgg=!fkfu~YuxG?O`Rd~$B{H~vxQn#Ws#h!# cVVm_kb zOq;|g$tWl&7)l}G1d+oW`djMoN}smVy(L$F&SWf zzJc`WJrsf0XO8p1!bL?z(Nh#GEM>5wlhyV?0RhZ-(Wmn5siL8HGO?0&>%T284o1w! zN~ppDXmP|%OiUacjzy_oY1&WP`qNspFDx$RD;3TPjJU#Myi2~<`ri zSuFniu%B}DUP!zKA+c(L^qNEY`@4^Bjz5qJ3kz8%EE=O2-gmRF<^KBht3`2in2Edc~;Yik$IXpde#<>HE)xg}YN!F~K%It)vFZO4K8 z^7y@LYLMhck~c9vtJ%crP>v~!D&Ui_Ki%~{^9z&IV`NReSg)(banBV{41)KYbh9DZvuB7HV3S^s{q_y94VuY<_aGc3-lfggK-A z=7cwiYt*Uq@}P{Y>+4x&f7* zkl84#O=lG)MNw6?TD#fTc5QeA0GNlTzN}0kLH^sJYhoxoN}BMI6+o;~N;b*`FppUFX8c$Y@(-cdBwaZeBlGX`NB!a=O3LX~UgW>wJ{2 zTuebtZ4A*40LjeEOczQ0^5x4XPoB`x(UFnCu!!Mdwxw8W2ssY99#m9R#ayLAC~5%I z*todk8+M<6V&1SGR1&hMbO`P;_y*fH_%NS>3&RcXf4j-L87lte~I( z0|O(-&re)Rs^{0QWk8w?XIfNJ7Fa>2gH@=pP$(lJBRL4sQ~K~8JsO3dKutg=;r_6{ z+()DpP^am7Le9!sZt3?_6p$wp^U3q)M(4*n32v8;KP)$X7tZAtch53UHI2^#q!twy zyO>MaRddnMbZQqqg)Pd+z`$q9R4mX4d1~mKK^&yt1(-XWI|^R{gU!y)<|Gbk))o~J zSsuA52a2Ce7@tCy9ev-@Sv;FPU~Ykr7#GKk3pR%HVw^tv(brXc|NdQf@)$C@hwDg9g4jk-8Y<6stA%!n7?zER z$^o--)>@Z0Z#s1&)mdODb|S9NBx5UdJ0jd$fK$?|mUX@}*ehrOnl}nHoyn}Nvr`Se zSkzvQr>K0=ZX93)^Hkj&xW{bMmumsQDtWeQ_V`9!c4nJN+|GA^nDN(Cmz0!H7u4*I z>L+mZA>X=nD@7>4XcU}*7N{g16+1zIk-#>t4#&+Ut}e1h)_^~q{UQt6Um3`_rT(0b zP6Ln|QHEh$6BB9&Bd*tM*wyv)7E^+_5%siu@zKG2sFdr;LL}|@QC3EL)z#%0|7ib= zMQ0qxQK%GmTStenlX%V$;$fccA2&>Qy404_CF4%#f_PZWD%XoT&O@V%i;H25?e0sB z0jyKUJ#Lr9w~lPZG-6EmcPq~}tKCjlGFoU6bdbYt9XLukkj?a*ch4v&G$7QWe(FQH zSR?rfL8J`BjbWubLB6~HMLKk}`i_;*Y+`6-l!UFJ|Z#U9bL=th>AtnQbD=Rl8NI zbhgI}h6RZ~3)P{cz5O{gHOI;|4PfV3&m>{ACdI>wN);9}vQk__Mbbo2cmU1^lcvOw zkfPrK(=Mruio%PN#NDPUguw$}=ECJtEj1d_ygD5T6~g8QB8n(R=O=rb4l|x>`PKPx z!nyhRnl(Q)%FL&^4f|7j%L}rzRZ0w?iu%#j9na!weqb<2&Hn=P&E(f7Z7MMw7$ddW zOx@kvyV}p-$y2W`Q+CFF_z()g;^5&qfItuD-Wwk-U=yehNl3MPC`OL-m;X9Z=mARov-E;m{o6-J&Sjk4eNBF zqoh=-w92djW_-LY(Y`xxiQ0C0dd<#Bl%UtL}RwYi98v*x=OcYz>DJ9Dk9M|duT=&g_@+`8>ym_QJ`KnesW zxPmgG9p8!6bghK>DCVgQ2@$DQ*<@8QaB;b;|1OMW`os>b5)$e6MDHkq8fJW70_w71 zJEA@^5${|(g&;DU)m!K;yK@lJqwrM0XI#6?f&xUIk$l+xiTJX{<33>$b?1#z$U1{7 zGuX1FYx=u@$N_|GMV5Z2ehkx6)(&muA+2)=_6E?UBqulcY0}u(IOEN?-F|U;Pds*3 zSFEdxEjN-EZMAp0TnaFZ2GS*fPN^1Z3+lTKav%Ts46=%1zju_LoP0qbsd&qFKTwPsNr%P!%q__?SIksvBW*fv1iUx7Z zeIq9m&D)ujt1$L;ED+6`ccwtB$*URuhRz(BK|lAk~?p$gao zBAE6SUR@s5ueN~fEm5^y=}xPu`LH|R22zlA+@&{>HzRvV^TSRv1jEF{a=ZCZwmh)q zcdAlC=olF0JFH9_KNhSet$Vm2C5?Az2{|3MTL{cM+uMzn%z6@dcoHr9Q$??lyBAcg zK0lCh8~n(uqSq781>B5|p5A;|0|pNFu+Ryrb{Xj2b0EV^Mk94-^~%Q)91#eleZO$~ z+5zzLImBF~R8(m){phMPzZk2knFvdVDQdbf@88AKKZZj1I$*l+`fKNk-FE6Bk{`g# zHf#2}M~n5#)v0cfHci7svBC*URq{Z3ZH<*0+t}C$3N}L-V=mKg2^`<6)ls*GUUlvtS(Ke92P$Pi8nHS44PoJD^)w?Zz)BhANZ^J(M zU8@n8*#j&r2tCxhcZc)U2}&-HAvvcV<^lk2OEyl~EdIRi8qpf?O{RnhG@gyT&A`B* zUTt@P_8u4usE%IqN5)1*X7v|`1$C#{lMfCd$|(MHzJGyd265%y)zHvDAsLIPl&of* zJw2KL(O@Y!Zj?^}Z~$(7ftB^HsO?y&I+}8pk{cjnV>^NM7MGM{iRmIICkFsVJw;x% zs|MWWafRsIsPrvro%;q-8o)d9>(|~D;&cE&ZK&O*`xzqCng^hRcYW@YIUQ}fWFu!3 zBXDI9e)k}e%OCI=MD{8hO=V>zNNqQ$a{2X_r!1$xd5ni?Y@JO^)&UP4L2llbJEx(i zcZ0hjtS%j8SIBQSKo?*pWoH$~z5E#Ra&nmvj@dcs5-~V0^wlC3zimU;> z_GyKJg{uLgF3BWoL-9VK7JT?1EfmmJOagJCVPLSvbP1&t=I7^UXB$BRg37yEj4>Z9 z{s`n4#0S@bZ*X3rbu&G49*Gk|~L3$3&K>dn6^{cx>9Egyu##Zmp$1r#{d zuecLd9kfYu2Byh)_O7m%z+;9)KWY@zBgAIKTp)l;%Z6lz_2u~qz_G8B(7393tt~8& zzMdY-5#{XM9DU7p1LQEm(*kG*i%73nIbs1&0@C2~Z45KmN+6b|VI9w&J@c+eRl-93 zRC_S2I_-Al(p$0s2_O5)a@KJvZsZjc{qyH4WhSE#tp%5Q`Bhb?b!VHZH4cTNCT8AC zra!9U>OviRUvC3Nx$`T|rP_XKqVj+~ArWYR7f5G^?LV-hC!flemkokiW!2Ty<>X52 zHpYO7-BRD(TuN}$C^J#^F@Fs*AEj#35(LfF`4SIeZ~hoh0^PaTFn2?x?B6)^(}s9K zKwAulQ^->;F#ZrF4@f2-AD@FmMW4Y#zQK_Zs7c|Gk>(Q>md(D{yczEm6%;P_60S@} ztHMn8Gd*WP^KyY&kBV}D2+*`@BL@cQ9~2bi>udFj5TXI15q21sQgb9vRlj^ZraR7g ze>rJn4Jybhm<%Y1bhy&enwy%Uy7WTZ=B+B9KYtEejUdtp+b2C;=)!Dwr2f)&bE1;= zRS6&pd)QW+OUpW2!0boNX% zC-B?1tnp*`O+?DQ(NC|=>aTKKeOdHgexs|L4-u!U1QApEr;vcnN{2cl;i~8AJjkhE zSw^P+HpvIflBl9lle&w;anPn*K<{7>EsBn{Q*IY!TQVscy4B>Ch$!x#5Dli z3T9lhL0kdCT%m6MXnk}Kh*r)x7=o7tZWqSCzLKuy0E>HRyE+(SR<#19NzqNc(Cz9H z=Dh(t-CC8$@MvqgpqtLTav>s-Kwn2k4M9|g^Nc5sAz(lWXQZauw2YXnX>uEZ-5kei z9)DU2mSmoSaU`8O#Q8342@RM#^lm499Se7VuR{P~klSm3+Xj>^9f8T?366{35~sPq z>RKx9;dWjKR~#g-#G%*taCLFSdW0$%Cut9NIpd8D4NwQ*Iy+c9^5!|$f=UdfDe5$X zQPbsM2ncQTFNX0wY1EzOm#`VO&S2Huz~FoV1k0V?7sNeWRdyTf+D$%Gvgu$90U82& zGh5;+s#!Jz#n#r={%dW)=>L~N1;bRhNG}E%8XFsn^Rx`8zsUlA646ZFO{8A!u(vne z?RNis#$aJsu(&uq03$LQV#y71D-)Zo^G3SeQ$Z%;^Ks|wKB7Tepjv(Z^4nN_ z4**$h)%ecNj`dQvsne}`pnRY}^;b_U5fG=PHS_JTxBht6@0#YdyQKXC1E8h|m~0OH ze0@&=go&7z;(%Ls3~QR=9Ox{8`lL|Mx=1sn zWT)O9c+V51#v>GEqfoA(NPr5w1kOtI$|8~3UQt?l2SWWelaP>5-R0@pwNmC!_&l!X zX^|TEy~}43POA610o1oFUR}rEf;`U2uUbt#1KZ*oqkeV{Th6o7TgS^OL4%A2-N0m| zxKExwf4=JPlHAhLg4{&}u#`Acd-Gy&B;B){qm)cI@McMDgY9+xhx^nBuIinLfr{Gnip|S9Jg+=PXfp#r=*PU z_aK3g{d12OT0tAn$jNm_bGcPa+E286h}<3c!~-x}zR@gk{7=u1fV#Kg0hsw_AA zd>-CIQ_(94ho%}hDcA9_9y}lh&jQn23j_;z6n72OiuEM0*5b!aSZveyQu>ZTB^p(` zYv_Zv#ywaaqE2Km(DlbbtrCcL8pHpPos)AzWzhN^M_2#>Yj(m5M80Axs@OlUX~qtM-WIlPuLmzU{pb|2wE^_C`!YVBPEW|lK<+%~RZ>*UxI7i$2OU?-{s{_F zMpeH^Yihm;oreQrjd?hYq`>`KO&DCCs^wU2cSZ2I=u_)3QY81oK``?K{csRUW%Z=e z2#A*pIIHjt{fUg$F^2$%IXsw>(M(kPs;|It9JDqa(=O|f;<=DhRVCyJH##?U@1;jl9E3fYN%hi>Qx(rG(k}#*KQBgN~ zH=|qXkJo@6-MPT=7n(z3oxtpk3J=HL|7NX{ou9AJBN^c5hp@w{kV`-iA*}hGBKi7y)}z{2 z+}w45_DS`)<$b|-^XjQh$#`*-mmj=)K;3p4wejn0)|9*&E zK$59Er>x8lOq*)~z-3eFEarCZ82~Lcy||%zw=!O&S8k!Ol^7w@Z?BtbXlQ^)dY$65 zIw1<~$?M7A`yO2bZ3Xq0*=BN56R10H@&mtuU@vEJYRwd>P0h_& z1mleMi%>r$F%bRT=g^><2R9aB)qs_jmY+$mk2MEBxa{WGqV(-=(oYuOpdgIG9K;hSw$R7nB)u3E%*PhI!!BB>`$^K&Z0UEX1UCW4zqh>QcHsSuiwf)KG}apCXjX!2N;m&(F7Smw@(w z2r!y54Qee0lgGUUoYt33n&bWitdi;;V(O(glAtT0$T~bUwY|WkpFx zXI7nd%M%k+lf0W-LH_hmU&Z7m@adaO=y)#@D|sZ0%Xw}z-EqxnLh#-@hyw_cm7raq z>VUtxH4WY$z$T#8Skos5je?_aMGYz%nh#)5OO|xO*oHm|LJ!^AEiYHnqxp`4hjC$| z+o@{aaAKe1z@YN^mq5h}Q7IJ5ZfIcKktzeG2<8HGzxBb1g6?o>X(`CoxgDq?O|7lK zVQb;<8_4$zW*=qVflZS9#^L(LB0Du5d|dVeaQfsmOC5G*)5Ie+0CnAt8%gM@mY*Dm zX>ZUk`>8}MEY@XycCAj|ILT;~c}NbrDG@;-N$IxI?Eo8dBF($HyUi@Wx;&v)$fcyG z$1osdHB?*z3D^!D}+46OAg z@k6>++pY`-{W>!$jm`1tXjY=|@OSmowm52O!CodJ-}=)_8$*%Rq-Wf?iYd ztR8fzHWeqaRN=KTIYM;rp9!(S!MqZje;fV!t95$~4SZuZW1f}xO;kkKW zzi*d5n~4k_dO!97p7gTFS~UEW1I}$|Dl1b(7-(xJZ=)OXsFH|#NS{%Zn~Yk4Jyx^@ z+UbtArM^|U4@ZZeovDVXL7GL`Db;Z@?rwnh6_TsB=r1`44g{z{mBWx{U8wt;<@PymN}RUJF|jRYrmYGoMfI+ zQD9?Z4^7YPIB+5#DHJ3LiF%8T_Xr9LFFDgngMNT6*WUKF!_lTXznwzJC-z6I(mc}N zx4g2mSE1vZ+EaQ8{T{cg3wz)ko12@^YBS8`zwjDMpzu39h%YNEYv4$|pqbNu4oV;Y zrJapUSWe6#bfuY?nVTPwa5_BJ{e+SzNMIjP!fsisFpivAIY>f1$KDx`Nop<#3<;X0 zFWfHAp}#toXpQ9od;a6-nx#IHdwR#%*eUd9pobf=-%Dqh9pDt_9yIzaLWpe;YzAcK z-^OYmxThN%-viSrx$we=QzQ488CY0wN;U4Hp`n?ZZ^79akszMklk*=xei#m2)|@w&<`y^XhRNz_ik@* zzpCR2!}|I2C&)T%@q!WVyw1(osyfXZgwIV`GtGChN)-rLOe$P2oUk}wjC~=)juP1y zPDxFjUtMK)J$Im|FMwSaC!snAa}S7fAhhMdaRQJ;v-=t#lU2`H!V|jFR{dz2w6s)O zL7@(OAkgd!V;CEQ=OYE02`r}g_#e$n^e!GVE7FyeKLOI&>FQTdumz01uKE0D+D)WC zXYP<E#OoWLOeV?0s`mDb4Qk#$rs*=1>q{{>KDQW zdxrWVnH>!=B?)O4IG%7ogPejwCZ`1&P>)9492^|1tctR-3}y3Urt?o-_uALv8tr43 zIyD?aLqa$?ISsD-nzcuN|K8siANlo5L{U*uQ?nk}H@M00Du51X5krRE+PF(NE&T1A zmkv%$N?b#n@}2gAp78>#{$I>$#H5)^~q@e<(ZC6_zPrYX!(>!MQQ$dG&>K_>|FV zb8dF7KQeSr!mg{U>sQ1!eqy_)Dxhk*)cLL0c1=M?^2W69i(_m!my>qLXE2=m%@25L zb@e_qAG`u&X^hIZCPWa#d_I9A({+!aHJD7Hr=#ZUK75FFosz-jGM@MyQCfNc zjhX~bM{s*+4E^n#oT^e+{?rGFUBodkF{Q@0hlM@#v==!Wg_UBk{Q*0I_Tp+61WGDK zt+|oy9zlP$e2!jMG=tK7qQammv!1yix7+2LxLE+%QRtfjK`X8E%H0}AQiFz}E2a;e z^ZUSvd=Kxn3(ZrMC)Cv9G~lHP(0Fz%=;`aT{v;9PlKb=+dc^(Pn)q-&ZoT}i^VHCq zj;D4!w~LqrqCxMCP89tsi-bY@Ci4zh{}OJtyhbL}(EslXYXANF80dv7oF@RM!+>@B z=m^}sjEjQBE<@xW(zrgx?cr5a@4mNFQ&CAT37%}vd~SH=X}7x{NW}5-U>w3s#HFvf zA~%<2MO>FfY*MG}lu3Ifjqd1_NO3&fV%Q)?47tFamzQ_232c?o(NPzy%F{*-m{}d; z-BDh~RXuu*8iP+f*$`8MNnr;rnI$J!L_}RMDSZr+U-9d zHeDUakQ!h+0J|L3wA>huPf%!J0fT9lfgWS@uR@@FGjIwDOvuD;e=1Cr>o;x~@(4OV z$t+GBOml_MJ+C%T{+723?CYU8l#;FKdPNg+IM}C61@2^tz8C{qnQPWQy-`?Io5_Kp zz~JszICfCMci_|9-7H*B>u$LJy%=rB5Da}cmh2=(n8Y=TSczKNJ zpQt2om=|RtDLn0-M8lac>hC#Vw>*3L)Q4O}S-HUw@IM0+QDe)S!33}H}I4veJ24u%jY$R46w+4}z8yP*1 zpfoHZ0s^pV(g4fo>%#2UTvS+iU%a!c%LVZMXi`8{@eVZ&4Gk@=yootf^T9F8wP9ML zq5L6WG?`z(c+pw)2I>{V9yZn2R~T5$%*dEBT)Mk!MP)qyZvdAX?|7o()^)tl#9}ip zag3axl^B)r$#Ey$nw0BPOi<+Xma}iMQ+(|Sa zELfn8nyjpBp!|kNQ$<+Hvn?eE`ouM@itnaGxI8IaIPz}5%r{Fnz0ukdqq8YKF7A7N zw4b3l0=3^GzS;EJYAbyH_HE={lLjVapO_!GoO9fDtJV7V_s2GY)9OOhshIivK~h{y z`@EvMmY}4yJ^dP#r8kgcY#6JOekERe;bDiZfZA=gwiyyct>muPc&vK=`qHwhii%?s zwrt*vOzA*$?1gE)pOiTg-hF!q=7*JQOjYu z8#51o6Hv9vH*Qj2CU2Wbez9AU{<#&CZy+IH$=_9o+$#Pu4u(4x1bJRNBo?f4= z(7$I-P1h_-NW=WcYy&b1*|(3NTn1n0Z@AJ1`@ji|-luzX3Q)X4YN^+SqBOW#Au@j=x%QgjgFjvN zEKFLY`1Q*d>-Nu3RacI2Z^gH_Z{n!AkGe{3DmZwgLOc9k(!j5i_r2flC3*D3Q29A4 zeP+#_J5&?VmKX_Y>otOp6})A8EIKb#p!eKc*Or8MG}kYAHc&qKcEFi4mm?zbQ`c?Y zyxDrgOV$HkYEE><<0~rPu51*O?G_mx?)m=onx&}0z+#so$AS%nJgbe;r}$0FD%UO8 zuwla?%|n+jPjDKxcgd1N*eI{<_d%+L<=F!%bg^T|Y&dIQzm{(P>iG=3`Sj9-s-x|p`ktTH4A zi>Bt@@)uY4?=2Xg!=Jx?-2pX)&igs45H$FXDw+{dQHZIk*$4TZi1mVJTlq%x?;wiK z-+bx#@#B#zgB-s-AD;3hB}~mDpzN&GC1X?_(N2pkhbJJEXa~;`!p^2eI z1#Z@yJ9jQf#X2=GumJIlMc4_W+_vj5GZ8o9cl;<;k@fTI<*~3Rtj=oa1VKdxX%uW+ zGYkqD>eRAxih=?Om1v^f3pb8WT(WA_Yxa+zU9q?CL^P`T{u&P|fAR1QeO_tzml!jK z^KUx#SI}LLPE|!k!yC1oC|+GUJMI~V`zKF`j*S-ce8=wLa7TCyIP!=%g5eps!W|q z^2#cA+4Mn!2eV_3&wtciU7Yl6eoFe_N9DhMd`wyNqKB)iYoz0urd&zc+K+WkiJ@0@ zqykE~0lmCUn>LLeJ-Td!`~-2aVL@`?9kYEB-^OlGd#_;ybE7~`iX(K$eu<@hSA>gg z?AMm;HI;SA?6kfk=j89{A4FUm+|l)aPDuV8A&>S-w|;3etRJ?cvLH4rIQRpGW#OVl zFnm`w7J~c9tu?o_q~5vHpN|F5Cb^oTqP}?XV#E);DE4)p!aY*Vq;8?(kS*%2UhN;T z=IU*eT8^9w%IEXvm!29meB{V=Rq~q?3-eVY$orBeiEiBQK`tw4W7W~4MR zeb+9L5*v?Xg+K`jQ1z$uPMnm5+x_BX8-v6xvjZRQ+b81c+RDyXc5m@-`k6q)3EGO% z4mqbPXiW30e#hRpp?$~V)$zeontpuJ3E2`K898z0Oh+ye*{>jOEjpl(f2&_sR+hH5 zHnuJHhsKz)vXT;Ycf-M|rY+6Q^Ar`m#;SF|2lejT_wtYf6c9v2MBr)1C_3CPEKGr6 z;pRLVE6*&D{L|K)81Z`u>{ff*5&BR23T8i+hlAks$ z;MT9e^z=^TNJK%mY(EScGGwBPNJvnSPzHkk((gR6>&8kwRwDXQ5P6@8I-%8Hzb+d6 zb3J*J(kwqtY)3<$ju24P>S}4(64fOoimbo4#|e^P-OX(-9c?KQ1#{lKc>_s8WVCDh zcF5w-w{o5GA3WH9&Y9di4?8bSNkdy(bx*^0&|6Va(FBFBn2N~AC|IYUnVVq(FoHww zcyheM6t|nB^@T@?+#5&anzVV*47^TeR@MN`q+7S5(j4{Qy^G%zeSIfU+UnJ-^{)gs zu67^sntWjQ{$p0U$`Fr?0!UF{L+G`_c-wS&d9=jK1kscCxJ4xF@~3N#m=sxYUICGA z*REZyTX-To&H125E-Lrs>2cy>*cQMJsgyZpsQ14m3HpiDofkWL4IRpxH!~ZTrk}Dk zLnK9p%k-|Z`n{s5lP29JG{}$Ehf-eZI`7X6d4jV~126w@JY+7iZ(a&f%zHNy1g^7;)3C=so9- zsCUt#13Be8Qa(~zLKVU5?{WM0@2_5e&{{=_gGZe7ra*YbMn}uy(kD$?uBA0tRXZj+ zI^)Tc+$XWZ*(1~1(mT%AHz>%66AT66q73RZU9sYLodIWI*|YaXGvD9Y9UE~*I#|JG z3t-O9t{C?T(ee5~xnl}^F4T+$AKbc{GTFn2m#VDs!v|3nkT+z^`^lH0qYEKKdFS}? zUKJa^02y9)Z~Wud!3MYdbo6^w)rWWQc2>Q$#pdR(Dvw|-c(|HI$931O`*8n0UMuXm z>6p_7#>VG@gQr;4tUxhfZEuu|tZpoM zk2o(pqh$L}rvDNQT3Xk+iHHbkd3kvimG!gD6{s#jbMn@BI>iCg-p1GobkL)BRXvY9 zicd`Rn=S7`$;Zl-D}fm#zyOZiLfoHt!)r)JG#YL2gnCajzJLFo#B;)>AY>!#@=etq zD0(p_#`WuyzVBVG3{JFuGue7)E4y&lu3de;T{Uc$LHk_=R@&B(YUJ@|D`E@`>|ibO zS1Ar9p4H8uGZX^T0&edp*M6^YKI8b$KR>@l2Z~rn=V3SBz8xYa%05IEM!E2oXGIC@q+Bbu$kLGeR^`_Z%ogeIwSqtJt@Fo3k3Kti~)!Unxv`5 zJU&R2^Vwx=|@RsH4@$pX$RuR!BT$?j(lYAT`M&99mY;1?W zFSyJg9W##2N6h~>4ESy1r!(Q^MAEk%z=G?i-Wj*hP zhkwCl=WoAYarQo@aLyvpF6vON5$CBoD*Nf2R5kmV9i$R${AHDTyyorOibj#ecGEeD z?7I4f24%<6<=5pin%&Z>HT!jE)t`hI$-Si>%t}Y)$Rk0YLn6rPX|>-g)C8qY)33%t=G%axC=+RRP7T3rP5sDx5JYR~c3-S!8(xg?{SFcW%l^PTAd}Qsn zZ);6y*3h|EHeGv9yKhXp)lTYwIN!d5`oDPg%y+i@tgxKZr%pwV9;ze$7^letn()F= z*W~Z3s%_!?`SZbYo2Gw%Ugj7ruh7`o7+n?d<~3=h6(^NiTU!yfA8H!^&dez>Ek;Lb z$XATBR+#Gg6&cc+>#yHgv3&Uzh1!ot&%HFN!u`f?dioI;aVWG~7xgV$BK>czu&_Ik z5kdvh7q)+S`La9rdLGH6H>%uBeR7xDpfdT; zoaz*VhV`Y`qAHbs2?Da zfy!dRo!YRw7|z;?3Rx=yh-FTtUqi2DElLssldY_x5}kK$)|FHCl8^)x+6srqXbv~o z)YSAgKi|JNnDD zwm-7b+j^bVrH%&n?Qlc9tYg_tVB@iYG9N#F9P}Z|Tqsfnq-B378aH|Jik5?))$;#m zvG0**Itz?pbxD$x)z%77^nJ>{%en>zyLawvsIO-s#?*MKC48sg7bAd1%zD!%se*q1 zL0huaiCOpBZ4=-Mh!mwHqas z5sQQ7>p*_2_1fxqeGQFhJ`L~VwR@BQ;w4KqKk)1}ZrnH?|LB<(NADgf!n>0pyJ3=2 z&#uLIZzmN~-|&ItD?bAe)=gg$aC_EYk3vEzRH^NuOXPoR0e0Uou|IGyJqcADLP-Lp zbmG&RIY8OQh6bSqjq5epdL4(tXEox+*Q>AcMF_3xQvaA!^JJS)Rfg-o5@T@8s^CTu zriNWS%kHCM%KU3!6@lnsV{KC2X6(Vz>;;HIDP$@}A7Uf1W7ooRR0Z_w*H0%@xiHDf zj~=f;AQ`Q50JhuE*iW`@8G0jd%C7kDpVB?tEo5z7|A3+4E|*>l?z`4~#0je4K#XJ+ zk&@<;dP!0J0Ky(TW$m{2NzoMs?W%>=_JXvb zVF}WuG6%)7va&Aw7XT&Onh?634HjPbqID&%JEsM+Rcc$JYpB(4A`-S7<}e zpW|)B%J1I2qkarc)U?3tuRj6svuDo+@(86X1cJbDBkF&QjAr<*0&|e*1f+L1RQOHz zFq9jT(qc|bh1|Gs+b;Gzy4TC$;p4wjCG#v)*+pW+h!!aP=g*(>X1!Mx&Z45i$k32t zj~$e(b3Cs{c?Jds{^pUuoIZW}6on(8ffp9yN@xF>YQRIGVu#HR{`f0C9GEgb)N2X_ zh)0jYyXb(=w6tDiWf7N`|8$lcq6s9@*Y{I41GNAwv2)~*WT)G#SiANu@+lVlH*r-=Ucnm?<-s`lsVtC`T?9v-wJqmw zIn&o)%{+(q@81)`AYF2$V8M3VwuqIh$5ZLojP))~b00Z&Y#1vNOeaoL(=}_B+}z8r zz$8>aBBrFc2+NM4^e$>ROP+ZVyWqe9xGZju0!U|NQ@AAfdbljE`W>27jyf^%hT_2a zUG__2*`=kW0SnNVqzuEu7vc`MSM~&1Dip#A$;oGK4UMW+-P^W2B&C>K_k#x)Rnw4^ zR|=HRPRy^7XKUm7xg!%=W`{q1{1_Jq_Jj4BK$;HdgWQ_q!WEAgF#;-$V)l<8?}9cs zKwfNtbo-&_T}x{2U*X zX$EL+)(NiDeW=R@C!sb7(|NDjiS&IL=q(b|sSK@!% zRA>I%IO=nczi2Qd;_~HoM71RA`uFX-#BR1M9s{^Xp2OP3WuD`u?d#LrTu3vJhg-b% z!t1WOB4If~Aue_dt=|5R`^LV2bfM1dthaZad)xVa`}UE2#<*p+KA`&ec4}%cr7*8rfU~2?EA~9kYRv*^pu1jMt*~8h%iCd z3}NWGZ<&Z+jIr-9ntl58@j7}m^Ti9Sj@9dML3Kf14nm8>$6>jvCs;*lZ_Y^`1^k^J zK5J>Uhl_GC#0vhXr{_DYDMW_%CUYPK~Qd0xFD79c#XV-?{{na6VG>G;q&_nsurzt(&A!cP!+WO*?JF*nDf#fxqeCAC4H<$8(vXbzMQ%^{~km=LrTiL zz-%o|&DJ6E3ACOVAy`UFwxJzR8YNozF=!B8>@RR4f~2!FJ(+n`6-aZiEE zE94-q$bo&bJOJ@NZmj|vf)^gwl%t4J5~t(h?A%cKM)O7yU3w@D`U!CsevH%+FX$jZ zzu?;eynDT4^sc|~Z#XYq9uPER(^8&WRjdU3d(4Ikq-b9Pqj-1I0Yfb(2=m%(B*DYkG;C%qT8S1KtBhNs2AC z)17LRPzudZnR_`KYT0Mx>al8jcW&RF_2R_@v4xtNHXtm(5P*PdCJdoekj*BP#K3Z? zb+#d4YN+YZqt^obxwt53c$KcM_{fnXB_w=Dm#Skmx^$H@O{$QHBViN)ep8l``1m+9TOz(@buA_nH6U{re6w-Q3&2q6=g}CQZ6BK&ilE z5nFMZ>D}ex2QOXPbYjTV5s?-=lH+GYJta}Iq;d&}5j;FRz-E>C&+Chol@t}RS~Tsb z!Zap738A1ul!5YyCoZ2NfI$3)JCvxz!Q{Eq!ZF`mOFI%Q;DX>s86 zvFiqiZnU*^|9t-+qb(9N@4C{T6}LAw9-%HiaN^286y7af`&@b2iIK%w07_4sm1)@~g)sa|FxH8@Q)=rRwU%r@o zN@90M+_HFISO`NL1B@3{hv#g^#W~$|*%EI^Y>(t;(xjtqn&Xy$DIK0!`S%i(c`YEZ zwpi5TgcSosUy~Fee9vrkc0kS!+C>}6gY4b=gwO~Kd8Y5$mo9am_al>IN0a`n^kkkOW!zsT8HgLUmXy!kB^|U z!A4oygXz22%-13s7$W0y8Wv+d10iLS1a>ZQCF+^+w-jVr?)5$X|D zLgubBG(=~)ktgV@ebUPX-%hY`iFkOTv^4F->YbHYfH}cz+ND#b#IT15pZFkRIcoTb zZGSl{6CT3vW5!ZbQhfR!Tur1z>_l|(EHhJAUmsJG2OW;!cBS=U@6#UU?(+z1i||$@ zYAGhQDLcyXbbu;4z~|4ZTFila_J`;qElVOh-gH*Kd>NMUy#%F1V?z9uQ}oj42sXtdMeR&@^} zo0pkqa|i$h*W6gS#?8%*Iwd2cpmXPp@q$!Ruc~_fbrGV>_HsO$&^jS?c9(F>IvrMq z5z7Y#J}q%Dlv~U931w$|Fuw1oT}4^hl9%U4jvDnb&E55NCwy8Z`OTi5=)kBDk1?D# zXyi+J1pUL>9U6I$a0zmUrF{DMu|tZFXinz%GV58>ms$M>1@O!c4*PAE0 zo{6AhRcYStdC7?vPoC5Qqu}*3-fCZKG>*dy*4u6%H#B`UcO2FF`-cZc9C;~j>Tf6& zO~#9Ojzi?1)bH#9$=k$R$fiIuzkdBPk_$L>>J;vbEyWY_^YfFd%6wyN!@mwCuQqTX z=~%LkYi%Cr{uvP%9PG-XdrER}I@*5eXv`XXHYkYR7)|Vu(qGM>l>sUW@*C3n^z2EF z-kpr&-o2{mz~8=|GiT0C@DKTo{rmr^=~s0pGSddQAvA8;RXr>)TZob&nj*G6FL5B# ztRsF91}Rj;e0)*hurrZ*BLT{Xww3-a}q z5mk>X-1a*7R%+nN41wJPe!>Tj6Ei1c8$RpTq+P$-(326cp1$khy?sa^G!ayY-m^37 zOLEVIhN{xD%Tw}7UqS7|Z}jw3-0{uJuxsNdk4~38dn80j_H3FHeDdie5fK6DSZ_yP zU4OdyS9!M5s!L&EVc&PWWaXivUC19`O^+=}AQ%piGpcWE-tpS<96u5k_6b5|clA4U z_tkfJ6!dzSXkr)YHQ@1+Cm44@>TUi@+E?B1b!;n67u;V{Q?q33dUATWn4AzLnLYNS z2MMp)hzh`*nmPXrIpKr}ra#ce6||>;*=lcZhcl6~4|JfkjW#z2`do8%b=7x$mY+dP zu_Wv`Oaw0!o!X(w=vk+xUN&(_*i~a(udcbXd{n z>neG|N$x;n&weRYBk@VkGhPrmPEFND8a8>F5+g_6F?-;N8gk>GpgTK0w3NS5J}fX6yU!& zn=}Flw4Ar<+LuWar%!hvml$4S4Rc1)5Z^rAm{yOw*|D#sj^P)MA5Yy;ekx9Bqx))& zrJ2rCFQBRpFpQTuA+)CA!QKI?fW-AL?H82upV9_L(gm#?b@;b$hmRcDaMyWz{*_f; zv#UY957Swo%Y(e;n|>8^sB;F;gTZfaIJ*u-O9wO%qJ{cqw~b{*x9r2-DbPfaR~=u& zPY5iQp>9IfTYsL0i>oU|>BZ?D8}@u`=A2s`I;ZTCP(4&G<^3ay9pViJ^I0F@Y5#&({1bur@eI%5xAPV3kz`onixC(kCC!HU#vtp8zq!aZOvFderU}+lFLDWkp3#QBNd@bk`I@bvy_a-XrJPUwXwk zC*w9nTnu72-ub6FBH(^Uc5vc8fBwv;pqti{Qb!(Vm~4H<^0-5we z$jxpY92F8dD^*wb5ET_0Yeb6EKu_K)?LD{O7e24SC{6M;s?>Oaj=lDrI^@pknuj(dsNrdOr0NK;w;i@ zc9+$JtJs1nP!bLpavFb5rHq-GFMStKR3Z?BJ3=rh?hW88I%bE-! z`05ohmt#kdiWdojn=LQT7qXr3=jSzQwmD~R%2kV^ti4mc&3Wit zI7i=P+T4i~pMZzL!yo45{eo1L2=P7h^y>@Y9E`N6I)pu@r}*8wvyw+?!iJiRN2lHN zC}6eC;$J&}TO&sNkT_vjS z-F2f7VsAW5T(6sf$X+nn*$b+1mp`%YpdM#eI zbm{S$^DBkspkpqGh*-Or6BhiHDran=Ma@kJ?dmX4%Xqa$oa5^TI;COq<^-#t1X2x? zUnxXzDedHGdFqEM*nh+klATqg#=@5=SiX{^9)zbx~ zNOtUYR4j>wP$Q8Y1;{o@h!Arx87SC`y-VEO?pn@2{S@`Zkme1zAuAya=@D&!B-qqFHHtr$O0rt(RL6#}K@&|i3_{GGp zQAyuOv3`;xS&9 zU$7aOIi`1ZX>DsQEw!jmC)YFKhx&?~;V!?74385bT0Hlo-GcX64Nc8UMGK0TF4)EC zxESCf`*cUyv%&T0oMnq>%i{`rh_@%+QlpmTdlNha`_)2qlF9Z6|M9X)G*lad%D3kG5qIGO9Gr?kS%D`aYBJ2pOVdB9646?3>ZGip-px zz=WWPTvJ;9$LwrwZOwaoh+b?#D+PD{U7Ow(nGGE6&%=9(Ea>$&Snfov;^&d66#UOr zkdouG_oSkE4jWr=zCAr(y?$MYd;WfQ898DOn%}QJz8}2DC_8&2;}m}kSCH{7Z`iCY zedejySz3Mv#bqsaY`DBY(pxqECz=#8f<{KoXn%&(OuI_dR9mYpzF1qkU*Y8?(|`z4 zzb7h(8guohbIJ#b&Ty(+ZL~#k%|1glt-*uO@U~x&{Cs_Nm9k?fDkhw7*WEen2N!|N z2GWx}tL1LB2@@`Jtb9H64eEWQVMC`+_m(_LuE*z>M6VY?vyMF9T2g#4Pb*XDRv&e7 zOs}Xq*}ob>x$|Zbq4{N!OJ)S;9QV03zP1 z(q-qyOW&0rpSYyO-5*kyo`hX*9U(mzVf$|&pc@zvvG(DcrpMnjqtkt5dvEMCFHzaC z-Y)delm+>zNoHM5Y)Ro|`lIhF2^iI{9KS0!gd#Gm?6El`O1FU4ztbpOaaupGy(8Wz^*(eprh!jT)dO{S&9g;F>%JX^}ZEbx%S z+T&O<(1*VBkjgcj22g^Q_+mrDvvvRY7ApJ1n2Du_WSEnsJ?ef3zNq=GbnC5jw`Skx zS%eNpYo@}?5&ed{&Z1xI(CDEvzX$%e7T`C^j>g6_?Sm{fZ=N76EiPK}`SbnHZ6Zm7 zRF}W^%~`EFWx@WX7uMo}NtBWz{d0UtQ?E=p>q2eRWu3Jo=&9>B4E6gtXj))!KtQBn z#wxG42j{16^z<5A@~gR2wARAPe{NXWRbMafpT?5%Gi%TPO^Rwq(rXwaPVj_4aF&vS zN71_c)LZ3!mewpm)D+_7&{HPT@|?nw<<1xVL&sT+1GV_h_;l8`e_4BplYQ(UOAQMd zljjSTEsJ`vBC^Ybi__-jJoKBE>bPjrdRsCQS+%1}?~amAn7fmsoKo7aq0=4>Bw+YU##}4V(C5Ur$e(xsI$^MuiNWb5>|-l8y%FE)rj? zrzfEk`if0iTUcly_~)IYa| zE~e1Y%1ZXgqZ!kun@!fS*l1~a1tp}o*y4gnO%084Iw$?DW*|1UXzS%@4+gkb8PPdp z$caXxZlT>d1(?KMps#cDohkvhi_7OmOpwdz8+Sb9VGoVqSu4vDy9}}vmF_7fb{nCP zv$JC1LqUD#SNUwsKS4`u8xH;xB4AvtsA+3Q9MV7ZY|ZvTerL}vzZsLe1JFY_L`;h+ zjRwm;Do4o}98&49@aP<8aK_@GT!ClmdD7W>z{`aZm%`uWH}!pjuJoGO^xRNEDmZUm z(9^HmQ$8Aht$4UT>s^_?fq}3?$!HTLTRl@a)YA2`PE<@(6oa}@5$l_n$Y};{?fzlW z`=+S04^s-)NpwT>;JtgT`KDu)$rf){yt6kpl&Ez4b&c)cvT0!1eiB7a7o7Kx_di59h&mQAyi$|AWX zw3@?(h%GzUThuc@e|5JpV^B{4OjoErqOsT}%zEEfRYvd1gi4BNWgj2n^?9{-Qd5o3 zPRibqQ2lAzk77jUu!U5LvUL#Wpj$E>IWibNX~n10bsklB5_hccmvCy{BgJkb{+aBk z{Ywxtck9-3Zp_uI5~^F~4za!@^R>`tLXOpxQ|6hMt}0kODsgyndTcs&i2B%)mGa=P zgob&x4W2UD$qV9pUw$V$WX!JXHuK&Nw0>X~p)$0|y0fli(e*nLr_!RPrOWm-%FDRX zsC7M347=dt@hYv$P>Bxtd4nQ1zF#DJNWZwIOr`hCo6=5J+TFVBf0q;e!&i26irba% z8}sqH?{4&p9evU@c{CN5%}=qkS!$WL6CoQ?j&CwF9Ojbur@l;+-qI}tL`1wr+u>6> z3?N<5n~}rA*s~bJKc&|d2i~w2tVi~JZ^7>b@BNJue=P`7O3b{9(8j-^Nq%4t2GBvR8*Ac zAiI75$vsF5U@BMi4dT#b+HVj59sp{>KVN6XpQ+f?UZWx$5|$L^M0e?76x;l9`bm*D zfMB7nMEqb%N;8cp*%&*WoDkAt?_*+Yihc#DTLc<XmflcfR>Q%~u&4Pk!%mH%&8g=R>RSB&1D#2X8HLi9P-9UYE<+ z;HJlqrKuQ!&qswuM-tREGpA3N+!0H-PYe&Ix7)!%^4CSc@XF0{R8#i(yBPxGK6FWm z>+_ZI7|loG9vvN)@cTHtyTc!u<^lbV5ExCca{U{?W^`y88M#1$<2mQK{h98vD4j09 z^%K`ohjsp>_PYZbrU>^fVgsm1)DBZELRA8R0cAmhO+{-xQxLJLs;Wi*bHeHY;hF|` zJ}QCyded&=9kLIuAZyL;%1{}n#oBexN*uuLn+rp|9%??r8XsJ~L1wrUa}e;=;8uLB zs5-qt1Wqyc$wQ;j7DkUXp3S;=SAKHD*a*3KQm(jJ#fj%`CSL5q^GEKK+2=0WSLj>{ z^&XhV6F^(a%okT(m3=nnd6WO3A-<`xSxzQ&U}?sd|?BE}zi#+-_-i zq-8(YKuubt=W}$He-eb_rL&EMm9f`-Vt>5y%)gOk{FkXF zJ9Mg>VoiD8L{U;z{wU!rXI-g#kyy7-?%r7U14WJlMSsGxig)IP1ex^NMLxCEzpQlI zNW7?YN7SMQvQ#5&!fnani2VgxHWk(DmcHKIW0-M;#(lOgckCbR&XI zw}s+OlYXK&uC0SQDjiF%(5K-tf(N72owCiA(q8)ghfUwtw$yR&e3zawfBcFYHB2Ex zK|T{@`u}WbkhZTqlz9zR7imkUHle{)eWAwAn|brUX^i&yG_7K>zE6sDg^@w=y<^m{ zE3=b^m-_mCfG8+6_TbX}^TU?=FOU=uQP0TCJlf}tPey3;folclecJPN4|MA_w~Oy& zGcsG21;OE=6YKjA{}uFcD+IXIfCY1cwU&yI>L2Fiq_<<;4a;iEf3wu=itox=1yi^& z(}68GQPVJEX*faVglAa2pRAZ^jxW9$qz+ zwt2(;y${z}myE@FNOl@h0nsI=`C-PLC4o&_1j|WY9{Ap^%LDB9lJcX>%@J>YideR4 z=0Cgl>}es~&q}9ng4D{`O`-X(X;qcEH<|-9uE&!V1=MbON}__Ze0noDD2SmGI;A~H zy`1gxlvMZPfFTt+trn5n70(m&^pdfT81MRkc|G1I+k;zSG|E}Nc%+8UU8%Kd!RF1E`4sAET^=;n)p=je`-xA>>RwK3 zTe2{h)<=Q?*9_CV?&_K;m-5n6ZtAgzFIJ;;%-l0#;6VMc6ZEH%RB0x!oprmJbOu9- z_5XYeYO{inyS6EIW65%*c$@QGF2|s}B-)uM_64>@Xg#2>Kk&vvWk%FEUcC(F;m~i} z_7V9@Ne{s9Ubtft*y!EuR*Fw8(Y3Slav=Fky0p`KYRcQB+}}K5ATFXBma$E_xJZF z9k{vT_v8>7Zcu1Ri)up}v5s`bcH61Gq>}Fb|^{+3$Z%*K7g+YnpkLX#8HaY`IDd=pdcs!Cuv7b zQi*7?$+Ut84>qz6c)dBee=)>mUqL+9=P81{vE6|DZJiq>QM$|H>b$nrey*)28 zgL8V3!jHOmaigheF;Ee4a%SEDQo(+HUn?r27f3BofYeV&FBQ^-bRE5{Ih4HY{snav zc`}tx2oeAVs#r|Mec`phLeI7&0#13{lTGGp&@sP=o6f95w%?nLz{5d5Lzkd(9>^5$ zaWw0^3yA03nVDUqC(6tk=+aV)Ks_*c;=Y2#lH* zSXELo&TGL8Lz~i!<*qlPqIRQwWBtH&n0)HGo!KBHSN>5#$t552P%7fjuoL6@)3+omJZwHKp1CzK&p!{PmnO3ilJ*ldYbexgzEet70%?4 z)AqJco-<{);4x)VsWc&Jlg?Rzi4IZo*t>FNpW(a5FpLK1BTUNy@KfT68`EgvpeMXN z?=vNAaLiZqZ$=Eh1EjUD!r8j1hGm$`k}w{QeKIrqENCP7nryQsLJ#@}9Xxmtnar5^ zJD0aSK@f;~?+Lz|`iPG9-y1fza2N-lP@ zx;g(YdDLhFLzTL(Px&9rC;d}?8>lKO6gDC=Yf z8xqH?v?<7v*b0IIW!$)nNlE!RIj86Ue#l#c(`2t2)Q5I6GL|?L9E}1Lkrjo_w0cg4 zPVfp`Y3w`kIkip3_x2=P_HUnGtPC}>ue!bF^Jm?siCZi!{}2KEX>NvWq$#8w*HUUD zk+GrxMDV-j!?LDbyB!@R?)>p>W(w2e;>Tiln)L64kzf8SfX53n5I68N1X6#}q)GG$ zrJW~vTuKFr-f&oONEA-2aV{tK#<@bMLxn8Q`8e25$Xgs|ZblY7oU-U2l)H1@-g z6ItL=nV5(vj){peJo}tHF)N1N2)PXTH;y(*aFR-hB4^B+HSmP0P)q{p(?ab6Y8+Qu9T*bkUcWW zk@8ztPHcabhF3gfraPu!6emg?W5=TeRNNspn)xokjJB!`oh@)0v?kexFzU6XP@~PB z(%R5%l9(rYGMs>zX_N#>q`V=71VQ6q3tH}9UaRa}pC!Yzq9Sf~$)(rS!3rH& zvBtDBceviWjPW>5EP^{j_=KL+q=!vR+%m@r-eKOU&%ZB@TX6J()&O8|;A-<%m# zjrGP<3A1bHnX4diETUsu*{|~oVa=M_0mV5Vl5OU4X3=vhH|Fc(+WsxKa^+XJEtikm zp9;fxZr^s6-~EHCPNKRoj6uM7Qx%cKO4L2--x=H45?l1Lq16(hW&Ku zi2B~U(a57$Sc`T-j=lb;wr_J8FYp%VBTN-4SL<}ywQS2&@WOCqXNStJ;|KRBFDp|( zibU&2MvjaIje)m2qqlz9+7edI@5qaJqNK(wm;dU_XUae%-jtR*HNy0;YKO5)4UkJ` z$%HB6w^{z@bKgjconqb$kH{89I(sfQd1B*|q3ivPKUdKuyh)+gXSKAHe0LvNqNMpF zkk!$bSMZZVO`R{s-)mxoKr3@mY1`s){n!=V-3F#EWz6(3fnzr|Zi!C6TX>ohzsMmQ z)7jSA^U4OPS?=rp+^O3?BKzc~Or5IL{-DEPrp@3H`C)JCOST&+OW{Y^ytLjz2Q;6l0~RxbC@!2A`=;l~waD~@ z!8c5-Y3NT6UD>GfdNx`S?fJr`5m$*mIM{Pw+HK9vU37JrgCVldJqg{cu!k8C_MuUi z&ivez5GtGUKc{Rp*{g@pdNpQaTWeyDQjJF^9y}McGm!V!1cB#(i z$;+pH50^Tn7>=jK7GR9nR3yQXDNv03L_;PdVsTs!Nf2Qg4%Q%yectzT8L_+YC(iOc zrd+l;{4=6!!C;gT`}SN#tajnT{p^3t(xvcZyd;CKCH^f4S}^Co2H0m#q@T6$DwO{3 zAEDQ?@Urmxw@7W@Hs62C%)GUjRVlm@H2y7S`#RvuM{_Te^K!vck7i~&vzf*BQtnfROgG2!lQX2H+c4ug%^vS zyjsvcZujAq3A609C;A;*Jl=iXc0SOubYZ6iZK8(noEbDoWs$p-@Y^AZQJ1?~X7Knf zyk7D2MTvuA(8|MPRTM{^{n4k<_v7$NpXXLD>B1}Ki8?6%2+B|qZ{Ow8WWV({oX`7o z?sAT9Y-ZwxVvVww@rH8rHT*7=BqkqxR6+n{DEIC3fr}lXQ7c3m7w_3zo^Mf(xcH*5 zH>%evj-m?a*we2S-;G52HdaZm>2gIaw`$wtuRkj*tvQh*`&2ZhCi`?uzAnjEgj_7v za5sHoKI1aKyies=hPebQQ2J6gJwjDJ@9*9e*)=6ObE(;(zE=Wy|Hq$!1S%qRjl-L4 z9JgNCFg7UJj=zhfEqk^f`@68m=J6QK8>aV+F{B*oY`3kJJNGgc2LbMGI0&F35EGwa`!6&> z*zWvf_*NPpX&cVJ&=BBj#R=9Dc+ffDI;=F#`O}mP$uR`(3xeCz+w}=jbV-?&wH)hZGi-D$ltaxHSo$vB3Ov|nm+$BTUt7f(3 zAMd6f2mGhyx8U`8Bm&BS6Q&*w30zN^^A1@P0;^k$Jtc1ooe}A?+OUOuec0X>t4l*! z#Vaxku||V0s4o9&M|_sEZ@^Q+7>eG;73O$8c8LISLPyX)xgYs|?nM~Of+x&t6(UBv zkGDxJj{@~Ui!lo?jIwtEZ{e$$&!PBc3uBe=-6cAE>;1-d)E!AqT~8eoz3cr7ok1xi zKbY~cTbPsv9DefkC+TlsXo$nZo&p}*($H4)WAAQq0!YIE6wpUZM%fPU$L+0JHu_9h zSSP>*#eF*1pYc2+7(ub+E5RQ6M^~y;01%VtxFIcpXMSxHdv7gWo0(|S$u!9qZnqgR z)egF@fEa_X1RM`MwwNKazgQ|JYK82~)d1~#ExjaEfAOr8$As~B+P=|wtnKrG{%?Ji^gXP8C$?P(;)4 z5+D@9h#u|n*ymNkFh-bS;JU=grGIU7ze5Y3b!j}<{BnUUzFpX2QVgqS*iDGzGuh}6 zL4aHLus03t2}lY^8ARd5hSIN6^?F)jaO?c>A&^)*`MSu!nQvdUeV-q&G0=>MgC58!gCb@ivmWQIPia3 z2(aJoP-=R&2^PcZnqXlX{Tf5|7b!9$=76L#pg+%*OBaHR4Q*eBR){Hxc|vXoNLO9_ zBXcyPRXB*u3i^z$o}Ox^F*yRX6wosPoGl3Z+)7EsbFMpN*Ly3*8@POv`^xfu#H_J7?=a;_t#LD-+rgN-%Az|$^9cy?_Iq<{ zX~0k!EzBFNcr{N8dKrbeR=K7A`r1OfH30SR`aWY_N+~wA))LnqPDvZ_X(&SmQ4i?2UxwgE z@1P?s;nDixlWOvI>(`aW+3uq1udpu!e(0KK-YcKAW}7^7({DQ~cf4I^KirS2zQ1>I zZ67yb<~uJyu`5TsYWHiRJAftzQTENBe0`n1hZcgCw{7V!OjjQ7qga!am+Q(Q68dq% zxUW~*hItVe9ZR%r8k)=X8dF9FxlUOc5uSPcI}VmnpaEsIaSn=q_p5a_advlg@4c6k z`_VJS<JhdP#@f|d7sXZnyc^t} z741NAXR67YNz#am-U(S6LcL7kqperpnNqpjT|I8o(|(&IxSV&VGugD*Y;|$b9%G!% ztY;as;#l*jAB5LCj~(fvAG?d5#4EO3!~ z8)G)qL_bn_v03{=w$pL_Bb5o>O9U0Pon39z98HzZqFp0<9h&*ujxl!0t3Pi%Js5M&Tr#DkeLgsE!=ESJ8u{T~!7`4mH z@O30u^m^M_fXFOJ-0IEPeSKvLmhG)uF@Y+=uC3aqRI$LME0EFUud_>;kbKth8SEdF z(JNLytgTcgdCUx-Tr_B;`?lN)4NEq6$|uLmDc7RE16x06 zv~kxF!a}ND`_bp*Yo0QSEMba`$y%f>SkvMjqS%2wmW%8tEY>FOOZQTvyNhL2DZ9S@1Y*fr=2Hj;=T<33(&fiC+PFa4qS;LxAcyb4K zisZMwc6WOA9v?NEjLMc9qfZLHZ*I}fykjzF}hqBqjKUaP{Ey3FjIp6I#oFrB`^BBKS37iYeJK(kD>h z@UsexW+}Sa`E71`bL*$hy)Z~5$%<_cAgE`CvVMQuJdc;5j>#Y~fi0_f-{|_O)s&3( z%ymMuUg04N$e7Q+>{u=-M*FA^;ET|T^_jn{V1!XW;#l~PE9*u7&^-l5PAneJ_{Dd^ zEO2AvR9JJm8sWk?JZc?pZ>0@Bwm9vm9wz0@Yj6SlOM~!Z!8iM{6{&IiQMGL*5LQqBl-fq9TW%klI{K1 zhVW@{5&!>0!>S1)BMy*t*&u}1B59+({Vy;O1XL$i%nVvBnl|~O?()BJ`V4QSMVoxI z&(FHFb;j%sSDs&(H>lU;C&3NF`H~UJDYIs~MaRjv+kczr)>BV?$D~152QP{dV&vJY z9k*J3p853~Own@b+*^Z>$S?c8;bDox`~!sT;Q}jSd4)YvcX?oW(oT`*TAT z*tJHR*WfEqXD!R=VkumcH`nBSxuEdq)31<-y&f7c{&xPD(|2yuT})*5Hg4*V-ai}U zhUoW7bBs4!`9-+bzM+JNw^!c}G`3!(@aNg(A%$Ys;t26Y`kvz-RBc9>%@!Qb26&^{ z78N^no*&uB6eSTiE56Gx^Uw5t0v#ZKi8UTeQ;2F!Jb!hJUsS3dRf`ES8r40pPBu%>KCcUsSNQ* z53i5cdE2(vs<6pW`OUUROaQWb*Y+Z?{HbqNgL~ll`P+&kr>dPzBqPxAB6zB*ljZf7 z>5b1km#G=~wbjbraldyUEJ(#ZFJRe`F}t+On}S+Dz1Mr)IaWT(t~1V{;KZI?wW|zu z2kW@S-E;hsaJsg`Y;)>nzvZR1m%8_{FGy|tw6!|=YDM4>QS~KS+l-c!&59}b)KR=F zW><9|Pf3Yh?rz@-ir**LKE75k>&Kgm8pSeO_tvCN_|ds1tJSq~`uZ3dgKO>Wxe3=5 z;&%r7gnUq&*$~&c*QWW+iQ??LKX%^<_^A5*LO{yAV-}8@THCfa-@KE(R=dM&N$P_) zJx13BALzf*UNzpl#z;PA_g{X%b^Pw`st3Z)f6sf`*E%q4ciXQW2CLV;`Dv=sJ6JW% zyym*5+BS)vzhx)48GWi{#Va~b2dZU#FBvI+Z(9SSFkgHv{G zTBW_yGC06s^v?S|Ym7(#Zu_`1J5T9m$j-%`zsjc-XAk_75&rxCY41G4n#{Vr?>wX6 zj0((%GKiEB1qA`6N*_c-rHP1ikd9Q5PJmcOP!LfNkS@JQ5s(@PDk9PndZ?iZp$7;A z0wHZ?QVA=;YN}Xe=p_! zr-$(8Yi?MK8*2W`T6n7`_h?SzvKGpxCir@T;u!PWyarh&^71z4kz2iV%JtLxaf`jn z+mBEiVj^cto-a+G$+jAbSdcw(IWz32945~(zAey4c`94Z(zxnOs(*Hn4hKC3DmzCSI}3Yp3D3{2Nq{P=k5h*0334l$A5xKRVB=NOBwcb??Wv1-X*E!tLhOM{J_vt?emRCJpjZKXt74 z$AxzvnpWdbDi2imIpH~a-*PvR3tK;(){|{zTs4QWP^`na?J(CM4izjNoebVGtZ^W@zIQ~8DO~%?JA$~D1&&)bT^^l4a*kjUVL0gnJ zqqnTCBKyRVCwf-(4C0wN+YZHFkm%p#5F_ODvp`q5#-*YsF zy^1`b6*gyD^tJ#CuSC$S;&r{X7suXQUnj5YluwO0_1oP~H5u=W;(3UsmJ8Tyo;Cy3 zhs{QXVt1nbJWIsqMr!Qcahk(^bu|HR%b}T|-U$Sbe7aRs{h*HvrjJ8Ah4gpQ#>f|7 z|3rsT-MVMUw4 zxKX_Div!|YMh}&8P`TcZ9*8AvdJq@!Wb}<@HiPo$0~yT1zCTq)`L~_=qQ!=njj5~b zD4&kP3HSNBa)olW9eUmTrHrhrmR}Q)C+d9wOa7F0rHQYJb~YbWEnCbbs+SoJDx>HT zj2R4w`_#@RD0$#ADh!#wSbAL8`Mkcw4A^-j%7sk|kUsvi4E`x!R{?E07*$uFZ3CUR zJrlj_v|-((vB~SRV%=jkx@10nMx9-6EEQ8q&vVpTSW9NV(^WV#Qj#mD7hp|X?^}2z zu(c7rsmS?FIb`vJ#`Lfd`rRb4EH+8X!C6@HR-*2KeQK1EG{y4sTUli! zwB2;gsa?V9Z1QD>5j8w*j|6_}sh`?T=`&C<0k^Dsp;vkvFSo*5x`q3!YP+0#H&5W# zGp$eg25Xx(Soy0%95<2?yIuDny82^ofrI4T`;k9B*xSB=kK`*>;}^f7aPL#PY(Nbd z3+i%nE}(sNH3 zB)o|^ZBVKirD6>0;Ig}?o#NBvpcA6Pjz{ybF;7jk`dFbt+?yJ@2l|-uY1^gNOx;K( zb#?wH%GgtK^pa)8O8rN%B*b0XrY4myWHP-!c5^W+Y%XgQ7T3^F!^;3ICZzS*P z)@-*1;jB4z)csWa#{BkMhB7`4v$cA}WwYB5L$B)_Q~KR!XU=dz5A8{`JeF%UEXZF{ zLwkqiqAn`=*#?B1R4OnFyGlk!hrhz-g1|McOSeeGv?yj5<%Xa@9(-PnB zmUxbta?=p)e>wZF)vagWqNqDyU;gbTY{no<`|wRMN#{O2MC z_J`lgAbGnp!yfFKlBS=FSj=W2mPdsJd~ZwafwA2kVHZB`z=3iro}g_lk1T=>@y6i; z58r?TbC`lRFwG2@tBLIE)2hr8I^%(I?+ATlCXLB5ifSs&V%1s{F$+jhd@6JhGTk|I)0dcgswYi z(0nLxd{*65Cqci0R3RgK%ZNQ`75_(&!3Lj1t6Y{(guwo8EhDn_$>kvCR2r0ZirJ@y zpB<RLM_Vqe;E^*V6cS6Nb{8Hv$am?FDjdBm*g{T? zrrixY%4IJ;7_|6I-ps{D5cA4Bxbp`O*P$CRdA!RWMNf4Yx0^nSC0c+R=WjRR93E{) zgogWnKue95yT~3)Iqx|0lctgveY`|jRqlujw#p3!Zr3zSR*&xT$zzy4q6QX2U!7Op zIL!7q@sgmSPpY&hX^`rrTeIx<~gfHqSWWr)I-H@xRXHH!`vKwfA_m5mJjIY0I z(@>Nsll#2KfXQy__Pm8+fX6VE;1{qowqP24n2mSC^-iGtbAkOiysEPqsVNcxyG84% zO=cpkZ(WYYc`O*+ygGF^8?GbKKP4x9r!IaXRQ7TbWaHtCFb(a}W@Gv#1Nb22yK0-FdPJT*F zaan>5RL^-yZsg1-YA|aquDc((EZAJ-mQdr!m??s{*PvRcR}hx6da1-=pAl7YJf^i^ zv&wK;U77X0(=AJj9_eH9S=F--e^lTi%_P&hc@jjOO7e#SJO*2>j`xiG{=5G9|B}6bXY%sxYJc}p3uDxgBP-PIs`??14 zal|buD@J8oqeLQr^xoD(DQlDF#YLvh?XGuZ=XyICxRAi7!lCW+hpf;O8xYoG=(MZtyx3THQ9Y7_#cB(zHBT=g^GHH7deP6ixS~d9tiL_YdlOo|12oF!c5b9k0lrOvvn^xX58EJ*|X1`A0Ga-^6uzFbIF^yu%*+e!J{P zOh~Rv%eQBJx;Mb2#1l6Adu>@6Mw`#UWowHq1TEdSluus?8y01fme}3>U1|;^tA&Ax z>)pvRdHfLAI`Q(#$zMy2U13oQ3&kZ+u6-33Ew`U5Q2Io8x~uZ?@*qCfzTV)F(=)n#514Ro#FNKfY%m2cP;{TDfJB|Om_`Al33&`29dtv4CwVONb9eX1Z z!rSTwWozQVZp4j$tZn`VYn!|I_a!)ge%v^LtI^*#A=)c1cMKF++Z$@|gE#5Xit3H= ziI(tH$>}>?=jRJaZ@bPP!)9b@i1-~4bd0kkb}SNDb|f2X~K z5*onNG})BeN#0J|Z13M%G25`Y&lqez)P z_^CH*2gF|ZI7uISddb{^1G$jw_X~MT9HC|lsR+khh1KTFe(gx*HW&EoAA%rIvxsy4 zd@82JdmY}9!PD}Q1PLz=7Us1yDLF%gD>x>CoFU-{E0IuLk85c($!21)BC-x-0a74R zLu644AB-FM$!bObY5wmkZSjYy@V|SoPS(g;6ruqU|9Ldve~sviJm`NLMUj_#G5rM+ zm$@&2d#4Hp8BG7WK8UQvK{sb;fo{HPAfFd!0x!~&2tJO(gi z=yP)tT|fVABN70DlwJ>)#)%amcp;6G6M0vX0DnPQQ-xT?11aetU;|eT?+2bp&=!hm zxpV>&84dLHOF_1T2q?&hrBGt|XoS2Oym_bgi|N;;k9FYj9-w#vSq*d@B%DK5z~0X5 z>>9Cq<|jx_7mnjPI$--92v4-wNkaXAUw?{)-@bWyAgmGS7YN3I-GlYdWy{{*{t^Ua zKs58$sAk(zV~BD&$C56cm~h<($Dh~g==u4f0AwG+=UC+B6TcX7{TUee=~~$v%d08T zbNl2bSN%mieGA~B|JaVc0{+M=;82ZJFQ(k^^}Y=qg+MmOkw0?fkZYgU%56{ZEbru= zpBfZtf4F@n*xeyDOV=3M;#h9`UHM?M$%7l4$wzF}f@coG#qV2OO-{$AW!-?fw(u!C z{omxTzMt*?a|8zhI(hi$mMp|b{}4lhaBnP;mdZ=(COOPpo&R&+o;qh{>c3ckH=eBr z6ML$FQ}IXuq(xW6T$h~HA;fOEJjD4O2@khyogWtoD=f=3_Pr>UKOz26591V`W zAd=;?>%)lzPQAPW6|{1(7jhe9w9?WoUplJQ$F!z^$+^21cOr2@XV~@!Y_in2ou5^G zS6L5C`RRHqF24l_k@$;9C~%3XPWQ)j_l zLsPXkmM<06>tnX-o;BHA0|VTH`Zc2IB<{Kg^w$u;XmU!RUM9leIKPbi@H5YK38Wvd z3SWfp#uua(2?$oBBIz;;|K1Z66}tNzy77*qF!JXJsYR>*HBJ?a6bJ^{^fQ!EeucE) zn;%{%{%BPXr7DpPFaX7a4$4v^)oBcP15gBLm~DJ-&y~l3YDvq=0j>fH3P7%~KN@^q z#>5!FE?^LU2eCa3q#gte%#)xuFn1aN%=rkc2C}OGhHtmSBZLBzk+FMiVj$aRs38|$ z34j?xR{&s~pgN#F{Ui*ar=*002S{p&qy^hf!M<%EUi*LC$3+-`GI7Im0IxtF%MBx z`2EKp5G+w{pP&4q#sN9Sh~fZBR3Iq&AWL7ju&@At7gS+{1+72Y45&0xkr3t>Q7YR2 zSZ>buEwoGF>BLPeSLE^xFXW=m01}Y~5)~BQ0fb%a+BHN&HqcY{A;bYc=?y0b1v0^c zeFLCU;B!#G13522#v2U);|*X$f$phONsFK{hfM{?aPS;UzJ53TH zzwG@8TQ`QZiB%~fTmZ|Vg1#k$aR99Y5qf~zz5|HM`R3zNFaQDG^X?Xsg8;g(IMf#g z5k~}=aM%@1L_`6^w+7}e*$jgynNBwmEzt=G8jihy1YC1N4hL970uEgJDu@^w=%Sz! zL%2Vk0vcDy$|L?l%lhp%kJuEZo=Jgp4Z2w|@CBgActF83+`*tn0+1293#ewCxWy0% z{46k(yaT{}%OE`hfqx+5qGtyxjlzsn(kvBde9$8cY^%@=N*a^QWRM4JqkvsD z>ya@jwP^wi=!UVnWkfMjY!7<-qH{>tCIUGEPJka@fh?zs~ z0%Y_=UCz`z?s>^#2+Gxa!ZQ-gy>t}3*&YgT{+xpBB$$R~Kn_uL{ z0(zVg{0!Vg5@02px^SDD@L)M#^`ys&1(j(QuepZ6UZ3 z*r8_u0ci-C2oQDhSHKuFyHR{-`l`TwacK5JRSL8r33`DFu<%fAKCa0<4PHM8kO&kH zYo`h}*u4(f@&@c88MMn>suTbfS5B6}o@cg*rsH%Hu-{01P-`I-7L@E0F9#qm5K?KO zOyV{`-GG2187}ZTedg>yF^8-|6+k&oy!=|MiEOI^;yviQpiDz)Nfx!0nIsQcAjtt! zHbKin0vr3o@x09Et?pF_PsXvg`M6iRdla8n`*{#(H^G6az}?hu#=wrD(Br{;x&7gu zzOO63I6>kq^q%kU2ickw1ZcpX6oHe#UzmCZ2^fUZ7^qDF?SJD&SuP9YM_85FwZNT& zx0zhs0$YW;M7tVw$v3l-YERhoW0pG88&fSUfUqDG7ik$m0xCR=>7};NBZ2*oFQS}Zn0}V;JKHBIvs$zK>(fiOQd>v?4}5}rP+U(h%?}{!!#6*G zfxU}DsIt8ufis}?-iApnKopQ!p~eCE2p};RLtk6oB|&}mF>JlKm;rlfykqp5$)hnyfV6hsE9H%DvWd~6rS@52MYCb7bNQRF~xQ0SpamjH+dJjEFgJ7__U z?H26nMJQzg?Eno2lks5ZHg$Go>HQDk1uoZ{%qR3_H@*U;6{ufGUht{XG%(^k4s|zP z!e#bcj~L+|AXG)&-2zz41e_BbShvsxCIhQaD72ij35?3vPY=fdoy)gnB8f8qM1pXv zQZWqxtC#$%PRR;sUA_6eO$W z*QX=?Q;~>`6U{;|rh_B72WEm)SE#;gJ(CW2WsboVi23`}RzCd5Zl~Kxd}rO5TI&V_ z0Z?#MIImUUTsHWFxm`%CMyLb0m*U#_0;gUP8qzKmSGDg46TquOA&@9uMQXH`IOGd5 zA?@bxejU&$Hl>vhs!STbLj0sZjF8U(q6OFxYTNg~c6Qz1-39i;MvBmXYF$XI$M1fa zj<;eA16P_AqpJYPF+kEm@Boeg^b-JV7a64QmcT9WKpz3)21)J_WU9mf{RtvJ)M^>I z+js~{J_d5^g}3n4vzd2uGC~3YT42Zvznlq%u?w<1(xA|yO7NOA&@2Fh{G!04*$1KTIUy!)QxxYr!y6-mLHh;N|V!(|~Y$N$3dWvDj~{!t3Z zThnxqZD6s5c;qyo7!eE=ilsj0vIJ}nyyyZ{=?AxnS6C=CU6KH&1pEM!Kmyy*K?ll@K;|eo$qvXdgRTkA2AN}cCn4hml3)Q1iVR}_ z(ZS%o0?({_@>f)A3amm)fQEuCq!Gpi;rPHjz!mwlp2-FNw-_q2hHN9R5_9C5P)xy| z4K>LG;Oc;&KNlu$B6Z$>>Qwa`d3ifv9os7Av zF)sSc&yNo}93vUSg3;+uL@3WvuWf&?d#{;GSgH;thxs4lVlUxuJD|DW!VN{nfzpn> z85+%y^E!-m%3p!#OJ6t@&OrTshHr3&5B5UduxJJ+ zT740L6CnbB_wN>_3grgJvDfGJLo7--rUfAq!XDw}#s+UYH2n7cg2`~fvi5{@fJXCU z7sRc~>I%!Q*>6SrNPKO`XZ`?68qZ!e5!?Y4+YHBZsS@tK@9SVy4lf0*q;XD*EfyfXKBFuQ7| zWmGb^h*H?Od{m(9&r@g1o<6zoHw8UMZx($|bIs<*+^Zd@=g05kP~m(Vb)IUDH#zt5 za@ajByeja!=+*sK6;OV0M8$f)zMae~`rf%o&nbr!zfmBQ-fi>N=x~EsO3*^Q8T8~U zwFnlnXV33*NIZJao5l7*v#4W#WUb8WPN>kH;8;Z#6~F(1yb+Cbc=DJatd*{oBEZJXeR4E z);|)B`r~YPKQ^G{eOdIG&9g;Ivx_c+%3^NpMg;o87dJ(=su{k{)%bX>&$cyhBbL$k zbS$Pk;Rg*n(yg4(W61NQjyQt|m-Hg#SEQ8j351b8Q;& z)&(^7!#@@u?QqMI6D1kc9#YhmBUw@j@a4vaj%vZkPU8})jJ=JmmxrLjtcV=;YI`oC z&0DuUxp1qn?Rhcw`Kx{EZE=uxz4-+iSA1uhzbvff>!*iw40iVuE~C$#FbJ97a$jJX-q(VX zxDf2BKk=BoWT2;8_CvNqTr9EPk=fuu)K7kb7n9g&zuFTAR`hU(Z!D!Mv`VG2Kwd&j z#@qL@{>|ho+GoXU?~KN2QVFlPPR2juTh*gDnoIkB+s9t=Re7!TsVx>g^Ki4scnp7F z>r<^5&4gYPI&(T4rl;Q2c@hbqtbc0_dt{-^D9uA5x&B>I&Gc@-+YXsAc6?$G+%dMw zXOl#5JEJ2s6BjSzhxIo)8%~tHv)CbwSIDm`#Ad!ti|@7V!EwvbdxUi`HlJpj(8m2K zEeGuyDLSHJHI8_OhbvM4)e}6ADK%fdr?}`hzxiFgWu@q-G0XG5x&e0#95=`C3EK^X zhE75mB`hwOnl)J}25%!}J$+t|C znN!u%ujF@zhbXFzvqhUP%PO&F?_q@Rc5{fNI4HF;-RrJN(K1`tzyiml{&Giqow5Rx4Af8vzr4< zQC0{r;WhnOSe*R}#u*3jr?rH{{rzcJ!BOY?1*XI0A!4T`Fs z?}{1Il)GN3E>4!dc`D%|qGCg@KylwF;i zkZ<_pRBrCtlm;@Ng|BKnu6ZlpVKG`CAD%I*Go|U_;ohQqf63a}WYrJPbV1{Q$t;#3DDGcZNKTA}q#8Bi& ziUYm+9vRnIl$NTvWggCvku!Tn3*feBqK!5qy)j8SY>{CO-9yML8h{Wz1PB@nD~%8js5-0>!r)di=5INyQZ6x$O7VCD|#e!P(d%zv{CO zo9U(O^ziPa7JG(*vUZ>FjE4JgU+G@gBu+bUB3O@phr+5V<2M8@;TRB^`n^!Fx+=(m zD$OPzR*XIAM|0t+8mp$#=%}gEfzF5D5(L9Sz+v$4BoZ2emY48;x5SQFGGfYgExnmB zG+`lJjY|v9y?CSE-n5M{`yT^3au4!!(;CF_7QqyLBchehx$q1L_W_0Utd(Voo|)0u zIt(Anc_U`=a!lzIznr;bW6nc5_5Ke>ao!4Yqtya@qE}D09*B<6JcOZr8)O|;T+=HW zCWNw|x#AFE3F1wP$%S7cj+~ktq=eAh9-1Va-X;gLmiYzS;Cjc5cmvbt?s96V4wjM+ zd*u+Z_KsvDlQ`{maPn&{m~`&0P6~b<=RHV4J#d+&?!^6!Z`h(^3A+CL12SVdU1C}!=e5N72 zj%4PQxwd9UJ=)e{JTBNgi1ee|=-laWM&RI(B2HntMihs7S3AQxyh(S^^C7(~_d4!# z($NZiXRS$9>AkN{Rjw8NN%lED2`!<^M{w>1?;nW6j(p86b7!T$ZP zJY0(xadvz}D~h=~MVO?$6#P7;Awk8{=IR7jfBkqc5Z~i6Ftz$|ZMdFQ<(zHzCfjzYO!0%9FJd}j%=!EZno&8I zDF!o!aUIohvGOPMuJWhIOs8?R2aSbq_>l+4@C9Fv9=TP&o3S{J+T^WU>xvz0^Gn5? zMx`sp1T6lsB%C(do9xH(3@b}dXu~BKSRR`W_B7|z;7?JW&eZ%gne%1FPo-2LX-uq7_!N+ zh>XXLp+Ot3a>q55vWl@hjqY2a^VaDLg5l$=;kPv}eXP%Imo7Zj|^ z#_Skj-j)mdEu$NwHma)wyQ{79?UsY56eSkx+`2|!Ag)=S7UrY%Cg0gylz;a&yKe{b zvp%?70jK!wO9h@8=(iyee|Ec(2VcEbYFH!H?m!xTepY*0)!*B?086nym6wxgtFA8F zE~9K5Jp0XBo#Ed9jlNu$gUv6YD5B>Fb+p)famQ|~r8%aVjt+(N_QMpTZYRHDq1bpW z`*C^T7^bM^6zU?;wtFaL*)iWjtjKD(dUqj7gt_yuhe=5`xJ=x*ZZ<~h&zqb5s$*5u zG2D(X3J95FBn~~t74%byKfEtFgx)l8xfcC&@fL}X9${g~#0F@pJ39K9X);pltY^O2 zo%J1ioJ%U9sY{8jVJPUO5x<3;){IMZoEMk9WY>J{7rv5{hcy=FlaP)z#D56>ZR#;;wX>li}o}P6(z$?Tf1fFJ8f(;jtj^53sr9VEoGBaWLKr$%CXxGBr`kL zzTk>ogrk^rI`>;=9)%vw1OxNFAx5gb3xD;>vsg_8IGm(BCqokQA)k3}@8vTUD%{R;@mL%~2BlY3~G~?KZKq^SDNrnb0#@ zNs2@&W3t;b^Tz7dcBo2&!Fkk|r_0_B_wg8PdJQ(y%PqL4ZmoT~A6kA19RM>&J;;d&qXFD9A!&PZIy&vF7({PF76x9-V>96bg5ffvYv z2mK+st1*e9TZyT!sn}GFVfM$R#7FXM)Jq*z3VBEUV_3hHP`|^*Xs%S|Pd4eAqQc^6 zEyCDMlT^E%V>B{QW;gliyx^KgKxJ`hY578>hF7_Z6ImC3?8d#RI&O^FP^D}Io#wkE z>h5nP&adih0N>_AN6yTBo_bk&AImX$}pDJd>T~9 zhvaZct0g>D8v5QnwOr1_iY00KtEqPm57qYQ9WO+Y*L-MJyHypm6&SVY)8AGt652mj zK9|{uG*Ygd_d~INE1~+4(&Eq?`~($r+n1&KwB1lgS=YceT2-=S?q>W`80k7@j3ktKL+XmUi%|h}RUt7BG?%Bh(di9dpO=RLA6oo98 z4jf*c@2A3ex7F%392oT2^lnM@gr?8#vv3j*dr1I|KD+C-6t!4V6LPu9D0R4B5f?l~ z<0ZdVf<^a?1buf3dgo+52()MT=ecoVP;CG8E!~oqSzglVK<4fg`$Rl`SDNGB*RL zS0M}zVjzSH`J$SqR*la(obytOg!rAM4#dS*nq_}`Kk18T5_|Ui@NeTv(f&IU@o^#e zG{oM9A@=5P(U~%FA$~~+s*~_V8D&NL?k|ZAzX>-^V#)g0?x}PO?h_8#ichKFifUGs z3mN#Fm6=NT@Y#;;H5F!WMq~zI%Rjb{^CK}$;R}?e@#KPkJ?5CvPhMDk6`{0w|uaQ^fGb zjqcIWlomVKpuT(Vy>jDQ0lp{*sDjuD`piv{SjFH6AKO=zk^9uWTPt-Of3NFgf;QA7 z1RWTvy+PqAxD{^&xA4;?pZ2%w-q6jyk$+PJXsTbIsxI*iA9S#ku!T(5`&axz539*0 z+VNcTEp`%$>6-KJ3$^kc-zRSm=U@09E=?ZycD#TC83$0Tw?6QUJabtJmKDGJ#(O4^ zW^~Bm`4kdOMxl_s0>2=cgx-o$Mg zzAlz zFZ9z&_1o{dQmi{$LQHw0nt{cGeaRL%;E=C`{(fLbW0!ClQU`V6-P=lh5O@ilJ3$+K z0BrsQEGU%MhCMi8*KQXV*q8F&d${D?6R@!i6fS|JZ%~QBBS6hUF{mbd`ZUKIYmRF} z`_Ao0M?uMse{bTzN__Z9{NGr4AIrG`s5$gVYvu`5z=cA*P}y+NB(-PmeI{bPhfRD_ zZ$ZESI>a@AMuE~B-e>)S@7=Yd2SoYX{#X`$391caP6nFHTl4Mf zeUEg+l{Gd0=Dmyv7|CDn#mcM7Mc~f;7Io|V0hZj6(ggGih1<~37tT*NPmkC)akG%m zi`ss?J+mL7@ray`zb&%n7r_6+$^Y=gAphNS|GqZ@X6@N?vHLqHv}ga-e-yhqIr?`A z=*3?LAnkMiuXgy$9>5L+{^}Qhub1~%JN(rS&>#L9Fa8=gk@4|=VE&NBWFI11+HhNp R7Le|i92!9y>5d_!hwg^| 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