From 677acb47a95416f15e972cccdaf54d13df6f7c97 Mon Sep 17 00:00:00 2001 From: dk670466 Date: Mon, 23 Dec 2024 14:03:11 -0800 Subject: [PATCH] Revert "Merge branch 'develop/gateway' of https://github.com/CAAPIM/apim-charts into F151322_MySql8.4_support_develop" This reverts commit 7e6c328e16633a44c33defa874aeef5518832d6d, reversing changes made to 1f8fae83f6ada848315f4b4229d642312bdced0b. --- charts/gateway/README.md | 129 +++++++++--- charts/gateway/production-values.yaml | 55 ++---- charts/gateway/release-notes.md | 1 - charts/gateway/templates/_helpers.tpl | 15 -- charts/gateway/templates/deployment.yaml | 21 -- charts/gateway/templates/ingress.yaml | 5 +- charts/gateway/templates/route.yaml | 53 ----- charts/gateway/values.yaml | 60 ++---- charts/portal/Chart.lock | 2 +- charts/portal/Chart.yaml | 5 +- charts/portal/README.md | 133 +++++++------ charts/portal/charts/druid-1.0.14.tgz | Bin 9388 -> 9453 bytes .../templates/apim/apim-deployment.yaml | 9 - charts/portal/templates/ingress/ingress.yaml | 4 +- charts/portal/templates/ingress/route.yaml | 2 +- charts/portal/templates/pssg/pssg-config.yaml | 45 +++++ .../templates/pssg/pssg-deployment.yaml | 183 ++++++++++++++++++ charts/portal/templates/pssg/pssg-pdb.yaml | 18 ++ charts/portal/templates/pssg/pssg-secret.yaml | 15 ++ .../portal/templates/pssg/pssg-service.yaml | 30 +++ charts/portal/values-production.yaml | 84 +++++--- charts/portal/values.yaml | 75 ++++--- 22 files changed, 620 insertions(+), 324 deletions(-) delete mode 100644 charts/gateway/templates/route.yaml create mode 100644 charts/portal/templates/pssg/pssg-config.yaml create mode 100644 charts/portal/templates/pssg/pssg-deployment.yaml create mode 100644 charts/portal/templates/pssg/pssg-pdb.yaml create mode 100644 charts/portal/templates/pssg/pssg-secret.yaml create mode 100644 charts/portal/templates/pssg/pssg-service.yaml diff --git a/charts/gateway/README.md b/charts/gateway/README.md index 7b3add26..c0646cec 100644 --- a/charts/gateway/README.md +++ b/charts/gateway/README.md @@ -199,13 +199,16 @@ The following table lists the configurable parameters of the Gateway chart and t | `service.annotations` | Additional annotations to add to the service | {} | | `service.internalTrafficPolicy` | [Internal Traffic Policy](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/#using-service-internal-traffic-policy) | `Cluster` | | `service.externalTrafficPolicy` | [External Traffic Policy](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip) | `Cluster` | + | `ingress.enabled` | Enable/Disable an ingress record being created | `false` | -| `ingress.annotations` | Additional ingress annotations | `{}` | -| `ingress.hostname` | Sets Ingress Hostname | `nil` | -| `ingress.port` | The Gateway Port number/name to route to | `8443` | -| `ingress.tlsHostnames` | Register additional Hostnames for the TLS Certificate | `see values.yaml` | -| `ingress.secretName` | The name of an existing Cert secret, setting this does not auto-create the secret | `tls-secret` | -| `ingress.additionalHostnamesAndPorts` | key/value pairs of hostname:port that will be added to the ingress object | `see values.yaml` | +| `ingress.openshift.route.enabled` | Create an Openshift Route (Requires Openshift) | `false` | +| `ingress.openshift.route.wildcardPolicy` | Openshift Route Wildcard Policy | `None` | +| `ingress.openshift.route.weight` | Openshift Route Weight (0-255) | `commented` | +| `ingress.annotations` | ingress annotations | `{}` | +| `ingress.labels` | additional ingress labels | `{}` | +| `ingress.ingressClassName` | Ingress Class Name | `nginx` | +| `ingress.tls` | Ingress TLS Configuration | `see values.yaml` | +| `ingress.rules` | Ingress Rules Configuration | `see values.yaml` | | `startupProbe.enabled` | Enable/Disable | `false` | | `startupProbe.initialDelaySeconds` | Initial delay | `60` | | `startupProbe.timeoutSeconds` | Timeout | `1` | @@ -508,25 +511,71 @@ config: ### Ingress Configuration The Gateway Helm Chart allows you to configure an Ingress Resource that your central Ingress Controller can manage. You can find more information on [Ingress Controllers](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/) here. -This represents the ingress configuration for Gateway Chart < 3.0.0 you need to configure an Ingress Resource for the API Gateway +If your ingress controller is private and you would like to create an ingress record/route for the management service you can use the following configuration +``` + ... + rules: + - host: dev.ca.com <<== standard traffic + path: "/" + service: + port: + name: https + - host: dev-pm.ca.com <<== management traffic + path: "/" + backend: management <<== will target the management service + service: + port: + name: management +``` +New Ingress Configuration Gateway Chart >= 3.0.31 (openshift route support) ``` ingress: - enabled: true - annotations: - # Ingress class - kubernetes.io/ingress.class: nginx - nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # Set to true to create ingress object + enabled: false + # Set openshift.route.enabled to true if you are using Openshift and would like to use routes + openshift: + route: + enabled: false + wildcardPolicy: None + # weight: 100 + + # Ingress Class Name + ingressClassName: nginx + # Ingress labels (also apply to routes) + labels: {} + # Ingress annotations (also apply to routes) + annotations: {} + # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" # nginx.ingress.kubernetes.io/ssl-passthrough: "true" - secretName: tls-secret - hostname: dev.ca.com - tlsHostnames: [] - # - dev.ca.com - # - dev1.ca.com - ## The port that you want to route to via ingress. This needs to be available via service.ports. - port: 8443 - ## Define additional hostnames and ports as key-value pairs. - additionalHostnamesAndPorts: {} + # When the ingress is enabled, a host pointing to this will be created + tls: + - hosts: + - dev.ca.com + secretName: default + # - hosts: + # - dev1.ca.com + # secretName: default + rules: + - host: dev.ca.com + path: "/" + service: + port: + name: https + # number: + # - host: dev1.ca.com + # path: "/" + # service: + # port: + # name: https + # number: + # - host: dev-pm.ca.com + # path: "/" + # backend: management + # service: + # port: + # name: management + # number: ``` New Ingress Configuration Gateway Chart >= 3.0.0 @@ -567,6 +616,26 @@ ingress: # #number: ``` +This represents the ingress configuration for Gateway Chart < 3.0.0 you need to configure an Ingress Resource for the API Gateway +``` +ingress: + enabled: true + annotations: + # Ingress class + kubernetes.io/ingress.class: nginx + nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # nginx.ingress.kubernetes.io/ssl-passthrough: "true" + secretName: tls-secret + hostname: dev.ca.com + tlsHostnames: [] + # - dev.ca.com + # - dev1.ca.com + ## The port that you want to route to via ingress. This needs to be available via service.ports. + port: 8443 + ## Define additional hostnames and ports as key-value pairs. + additionalHostnamesAndPorts: {} +``` + [Back to Additional Guides](#additional-guides) ### PM Tagger Configuration @@ -610,11 +679,27 @@ OpenTelemetry is configured on the Gateway in two places, system properties and These can be configured in values.yaml. See the section below to view examples of how and where to configure this. +- config.otel +``` +config: + ... + otel: + # If sdkOnly is enabled we will inject the above environment variables + # Note that this is container level configuration only. You will still need to set the relevant cluster-wide and system properties below + sdkOnly: + enabled: true + # Used to inject additional resource attributes for tracking with the sdkOnly approach + # these can then be used as an additional filter in your observability backend + additionalResourceAttributes: + - test=someEnvValue + # - test1=someEnvValue1 +``` + + - system.properties ``` otel.sdk.disabled=false otel.java.global-autoconfigure.enabled=true -otel.service.name=ssg-gateway otel.exporter.otlp.endpoint=http://localhost:4318/ otel.exporter.otlp.protocol=http/protobuf otel.traces.exporter=otlp diff --git a/charts/gateway/production-values.yaml b/charts/gateway/production-values.yaml index 7b0a1916..ada377b2 100644 --- a/charts/gateway/production-values.yaml +++ b/charts/gateway/production-values.yaml @@ -186,24 +186,6 @@ config: # If you are using an earlier version of the Gateway, these will be ignored. # minHeapSize: "1g" # maxHeapSize: "3g" - # The OTel SDK uses the following environment variables to gather information about the container - # NODE_NAME - Kubernetes Node - # POD_NAME - Podname, also hostname - # NAMESPACE - # CONTAINER_NAME - this is always gateway - # OTEL_SERVICE_NAME - - - # OTEL_RESOURCE_ATTRIBUTES - # When using auto-instrumentation (injecting the OTel Java Agent via the OpenTelemetryOperator) these values are automatically set - # When using the sdk only approach (no OTel Java Agent) we set these using built-in metadata fields - otel: - # If sdkOnly is enabled we will inject the above environment variables - # Note that this is container level configuration only. You will still need to set the relevant cluster-wide and system properties below - sdkOnly: - enabled: false - # Used to inject additional resource attributes for tracking with the sdkOnly approach - additionalResourceAttributes: [] - # - test=someEnvValue - # - test1=someEnvValue1 javaArgs: - -Dcom.l7tech.bootstrap.autoTrustSslKey=trustAnchor,TrustedFor.SSL,TrustedFor.SAML_ISSUER - -Dcom.l7tech.server.audit.message.saveToInternal=false @@ -286,17 +268,13 @@ config: # If you would like to use the built in OpenTelemetry SDK uncomment and set the following configuration # otel.sdk.disabled=false # otel.java.global-autoconfigure.enabled=true + # otel.service.name=ssg-gateway # otel.exporter.otlp.endpoint=http://localhost:4318/ # otel.exporter.otlp.protocol=http/protobuf # otel.traces.exporter=otlp # otel.metrics.exporter=otlp # otel.logs.exporter=none # Additional properties go here - # Additional System properties are appended at the end of system.properties - # Defined as key/value pairs - additionalSystemProperties: [] - # - name: test - # value: test123 # If enabled this will override the default listen ports and their configuration in the API Gateway listenPorts: @@ -907,19 +885,17 @@ otk: ingress: # Set to true to create ingress object enabled: true - # Set openshift.route.enabled to true if you are using Openshift and would like to use routes - openshift: - route: - enabled: false - wildcardPolicy: None - # weight: 100 # Ingress Class Name ingressClassName: nginx # Ingress annotations annotations: + # Ingress class + # kubernetes.io/ingress.class: nginx nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" # nginx.ingress.kubernetes.io/ssl-passthrough: "true" # When the ingress is enabled, a host pointing to this will be created + # By default clusterHostname is used, only set this if you want to use a different host + ## Enable TLS configuration for the hostname defined at ingress.hostname/clusterHostname parameter tls: - hosts: - dev.ca.com @@ -927,6 +903,7 @@ ingress: # - hosts: # - dev1.ca.com # secretName: default + rules: - host: dev.ca.com path: "/" @@ -934,19 +911,13 @@ ingress: port: name: https # number: - # - host: dev1.ca.com - # path: "/" - # service: - # port: - # name: https - # number: - # - host: dev-pm.ca.com - # path: "/" - # backend: management - # service: - # port: - # name: management - # number: + # - host: dev1.ca.com + # path: "/" + # backend: management + # service: + # port: + # name: management + # #number: # Additional Environment variables to be added to the Gateway Configmap additionalEnv: {} diff --git a/charts/gateway/release-notes.md b/charts/gateway/release-notes.md index 480df827..81387e4a 100644 --- a/charts/gateway/release-notes.md +++ b/charts/gateway/release-notes.md @@ -91,7 +91,6 @@ config: ``` ## 3.0.30 General Updates -Release notes will also be moved to a new file before merge... **Note** Gateway restart required if using preview Redis features. - Support added for running the Gateway without [Diskless Config](./README.md#diskless-configuration) - Uses node.properties which can be mounted via [Secret or Secret Store CSI Driver](https://secrets-store-csi-driver.sigs.k8s.io/) diff --git a/charts/gateway/templates/_helpers.tpl b/charts/gateway/templates/_helpers.tpl index c552e97b..8f24089e 100644 --- a/charts/gateway/templates/_helpers.tpl +++ b/charts/gateway/templates/_helpers.tpl @@ -203,21 +203,6 @@ Define OTK Image Pull Secret Name {{- end -}} {{- end -}} - -{{/* - Define OTEL_RESOURCE_ATTRIBUTES Environment variable - */}} -{{- define "gateway.otel.resource.attributes" -}} -{{ $resourceAttributes := printf "%s,service.version=%s" "k8s.container.name=$(CONTAINER_NAME),k8s.deployment.name=$(OTEL_SERVICE_NAME),service.name=$(OTEL_SERVICE_NAME),k8s.namespace.name=$(NAMESPACE),k8s.node.name=$(NODE_NAME),k8s.pod.name=$(POD_NAME)" .Values.image.tag }} -{{- if and (.Values.config.otel.sdkOnly.enabled) (.Values.config.otel.additionalResourceAttributes) -}} - {{- $additionalResourceAttributes := join "," .Values.config.otel.additionalResourceAttributes }} - {{- printf "%s,%s" $resourceAttributes $additionalResourceAttributes -}} -{{- else -}} - {{- printf "%s" $resourceAttributes -}} -{{- end -}} -{{- end -}} - - {{/* Validate OTK installation type (SINGLE, INTERNAL, DMZ) */}} diff --git a/charts/gateway/templates/deployment.yaml b/charts/gateway/templates/deployment.yaml index 6466d57e..20ec4c02 100644 --- a/charts/gateway/templates/deployment.yaml +++ b/charts/gateway/templates/deployment.yaml @@ -354,27 +354,6 @@ spec: {{- end }} {{- end }} {{- end }} - {{- if .Values.config.otel.sdkOnly.enabled }} - env: - - name: NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: CONTAINER_NAME - value: gateway - - name: OTEL_SERVICE_NAME - value: {{ template "gateway.fullname" . }} - - name: OTEL_RESOURCE_ATTRIBUTES - value: {{ template "gateway.otel.resource.attributes" . }} - {{- end }} envFrom: - configMapRef: name: {{ template "gateway.fullname" . }}-configmap diff --git a/charts/gateway/templates/ingress.yaml b/charts/gateway/templates/ingress.yaml index d7d373ba..7759d832 100644 --- a/charts/gateway/templates/ingress.yaml +++ b/charts/gateway/templates/ingress.yaml @@ -1,4 +1,4 @@ -{{ if and (.Values.ingress.enabled) (not .Values.ingress.openshift.route.enabled) }} +{{ if .Values.ingress.enabled }} {{- if $.Capabilities.APIVersions.Has "networking.k8s.io/v1" -}} apiVersion: networking.k8s.io/v1 {{- else -}} @@ -14,9 +14,6 @@ metadata: {{- range $key, $val := .Values.additionalLabels }} {{ $key }}: "{{ $val }}" {{- end }} - {{- range $key, $val := .Values.ingress.labels }} - {{ $key }}: "{{ $val }}" - {{- end }} annotations: {{- range $key, $val := .Values.ingress.annotations }} {{ $key }}: "{{ $val }}" diff --git a/charts/gateway/templates/route.yaml b/charts/gateway/templates/route.yaml deleted file mode 100644 index 8e8a1b1d..00000000 --- a/charts/gateway/templates/route.yaml +++ /dev/null @@ -1,53 +0,0 @@ -{{ if and (.Values.ingress.enabled) (.Values.ingress.openshift.route.enabled) }} -{{- $gatewayFullName := include "gateway.fullname" . }} -{{- range $i,$rule := .Values.ingress.rules }} ---- -apiVersion: route.openshift.io/v1 -kind: Route -metadata: - name: {{ $.Release.Name }}-{{ $.Chart.Name }}-route-{{ $i }} - labels: - release: {{ $.Release.Name }}-{{ $.Chart.Name }} - heritage: {{ $.Release.Service }} - {{- range $key, $val := $.Values.ingress.labels }} - {{ $key }}: "{{ $val }}" - {{- end }} - {{- range $key, $val := $.Values.additionalLabels }} - {{ $key }}: "{{ $val }}" - {{- end }} -{{- if $.Values.ingress.annotations }} - annotations: -{{- range $key, $val := $.Values.ingress.annotations }} - {{ $key }}: "{{ $val }}" -{{- end }} -{{- end }} -spec: - host: {{ .host }} - port: -{{- if .service.port.name }} - targetPort: {{ .service.port.name }} -{{- else }} - targetPort: {{ default 8443 .service.port.number }} -{{- end }} - tls: - termination: passthrough - to: - kind: Service -{{- if .backend }} -{{- if eq .backend "management" }} - name: {{ $gatewayFullName }}-management -{{- else }} - name: {{ $gatewayFullName }} -{{- end }} -{{- else }} - name: {{ $gatewayFullName }} -{{- end }} -{{- if $.Values.ingress.openshift.route.weight }} - weight: {{ default 100 $.Values.ingress.openshift.route.weight }} -{{- end }} -{{- if $.Values.ingress.openshift.route.wildcardPolicy }} - wildcardPolicy: {{ default "None" $.Values.ingress.openshift.route.wildcardPolicy }} -{{- end }} ---- -{{- end }} -{{ end }} \ No newline at end of file diff --git a/charts/gateway/values.yaml b/charts/gateway/values.yaml index da4bae47..d982e872 100644 --- a/charts/gateway/values.yaml +++ b/charts/gateway/values.yaml @@ -186,24 +186,6 @@ config: # If you are using an earlier version of the Gateway, these will be ignored. # minHeapSize: "1g" # maxHeapSize: "3g" - # The OTel SDK uses the following environment variables to gather information about the container - # NODE_NAME - Kubernetes Node - # POD_NAME - Podname, also hostname - # NAMESPACE - # CONTAINER_NAME - this is always gateway - # OTEL_SERVICE_NAME - - - # OTEL_RESOURCE_ATTRIBUTES - # When using auto-instrumentation (injecting the OTel Java Agent via the OpenTelemetryOperator) these values are automatically set - # When using the sdk only approach (no OTel Java Agent) we set these using built-in metadata fields - otel: - # If sdkOnly is enabled we will inject the above environment variables - # Note that this is container level configuration only. You will still need to set the relevant cluster-wide and system properties below - sdkOnly: - enabled: false - # Used to inject additional resource attributes for tracking with the sdkOnly approach - additionalResourceAttributes: [] - # - test=someEnvValue - # - test1=someEnvValue1 javaArgs: - -Dcom.l7tech.bootstrap.autoTrustSslKey=trustAnchor,TrustedFor.SSL,TrustedFor.SAML_ISSUER - -Dcom.l7tech.server.audit.message.saveToInternal=false @@ -286,17 +268,13 @@ config: # If you would like to use the built in OpenTelemetry SDK uncomment and set the following configuration # otel.sdk.disabled=false # otel.java.global-autoconfigure.enabled=true + # otel.service.name=ssg-gateway # otel.exporter.otlp.endpoint=http://localhost:4318/ # otel.exporter.otlp.protocol=http/protobuf # otel.traces.exporter=otlp # otel.metrics.exporter=otlp # otel.logs.exporter=none # Additional properties go here - # Additional System properties are appended at the end of system.properties - # Defined as key/value pairs - additionalSystemProperties: [] - # - name: test - # value: test123 # If enabled this will override the default listen ports and their configuration in the API Gateway listenPorts: @@ -907,22 +885,17 @@ otk: ingress: # Set to true to create ingress object enabled: false - # Set openshift.route.enabled to true if you are using Openshift and would like to use routes - openshift: - route: - enabled: false - wildcardPolicy: None - # weight: 100 - # Ingress Class Name ingressClassName: nginx - # Ingress labels (also apply to routes) - labels: {} - # Ingress annotations (also apply to routes) + # Ingress annotations annotations: {} + # Ingress class + # kubernetes.io/ingress.class: nginx # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" # nginx.ingress.kubernetes.io/ssl-passthrough: "true" # When the ingress is enabled, a host pointing to this will be created + # By default clusterHostname is used, only set this if you want to use a different host + ## Enable TLS configuration for the hostname defined at ingress.hostname/clusterHostname parameter tls: - hosts: - dev.ca.com @@ -930,6 +903,7 @@ ingress: # - hosts: # - dev1.ca.com # secretName: default + rules: - host: dev.ca.com path: "/" @@ -937,19 +911,13 @@ ingress: port: name: https # number: - # - host: dev1.ca.com - # path: "/" - # service: - # port: - # name: https - # number: - # - host: dev-pm.ca.com - # path: "/" - # backend: management - # service: - # port: - # name: management - # number: + # - host: dev1.ca.com + # path: "/" + # backend: management + # service: + # port: + # name: management + # #number: # Additional Environment variables to be added to the Gateway Configmap additionalEnv: {} diff --git a/charts/portal/Chart.lock b/charts/portal/Chart.lock index ec265a08..e6b4fd96 100644 --- a/charts/portal/Chart.lock +++ b/charts/portal/Chart.lock @@ -12,4 +12,4 @@ dependencies: repository: https://kubernetes.github.io/ingress-nginx/ version: 4.10.0 digest: sha256:37372a7aae49609a719e1e1d0f9f9c6ba66b41caaeed4892981db2b50289cda4 -generated: "2024-10-14T18:34:34.4433706+05:30" +generated: "2024-06-20T19:08:34.36457+05:30" diff --git a/charts/portal/Chart.yaml b/charts/portal/Chart.yaml index 9671a529..ecfc4cd9 100644 --- a/charts/portal/Chart.yaml +++ b/charts/portal/Chart.yaml @@ -1,14 +1,15 @@ apiVersion: v2 -appVersion: "5.3.1" +appVersion: "5.3" description: CA API Developer Portal name: portal -version: 2.3.11 +version: 2.3.9 type: application home: https://github.com/CAAPIM/apim-charts maintainers: - name: Gazza7205 sources: - https://github.com/CAAPIM/apim-charts +engine: gotpl dependencies: - name: druid version: ^1.0.0 diff --git a/charts/portal/README.md b/charts/portal/README.md index 4eeaf175..10647c8b 100644 --- a/charts/portal/README.md +++ b/charts/portal/README.md @@ -3,29 +3,6 @@ The Layer7 API Developer Portal (API Portal) is part of the Layer7 API Managemen ## Introduction This Chart deploys the Layer7 API Developer Portal on a Kubernetes Cluster using the Helm Package Manager. - -## Release Notes - -## 2.3.11 General Updates -- Added a preflight check (initContainer) for the core apim/ingress deployment - - This resolves a race condition that occurs on slower hardware where apim/ingress starts before other dependent services are ready. - - This is ***enabled by default***. - - This only gets added when you install the Chart. - - A Helm upgrade will ***NOT*** restart the apim deployment if you have already installed the Chart and are upgrading to this version. - - A Helm upgrade will restart the apim deployment if you installed from this version and upgrade the Chart. - - If you wish to disable this, set apim.preflightCheck.enabled to false - ``` - apim: - ... - preflightCheck: - enabled: true - ... - ``` - -## 2.3.10 General Updates -- This new version of the chart supports API Portal 5.3.1 -- Removed PSSG container -- Upgrade to 2.3.10 is only supported from 2.3.8 chart version as per the Portal version. ## 2.3.9 General Updates - This new version of the chart supports API Portal 5.3 - Upgrade to 2.3.9 is only supported from 2.3.4 chart version as per the Portal version. @@ -107,7 +84,7 @@ This Chart deploys the Layer7 API Developer Portal on a Kubernetes Cluster using Solutions & Patches](https://techdocs.broadcom.com/us/product-content/recommended-reading/technical-document-index/ca-api-developer-portal-solutions-and-patches.html) page. ### Production -- A dedicated MySQL 8.0.31/8.0.33/8.0.34/8.0.37/8.0.39 server [See TechDocs for more information](https://techdocs.broadcom.com/us/en/ca-enterprise-software/layer7-api-management/api-developer-portal/5-3/install-configure-and-upgrade/install-portal-on-docker-swarm/configure-an-external-database.html) +- A dedicated MySQL 8.0.31/8.0.33/8.0.34/8.0.37 server [See TechDocs for more information](https://techdocs.broadcom.com/us/en/ca-enterprise-software/layer7-api-management/api-developer-portal/5-3/install-configure-and-upgrade/install-portal-on-docker-swarm/configure-an-external-database.html) - 3 Worker nodes with at least 4vcpu and 32GB ram - High Availability with analytics - Access to a DNS Server - Signed SSL Server Certificate @@ -245,9 +222,9 @@ This section describes configurable parameters in **values.yaml**, there is also | `portal.analytics.aggregation` | Enable/Disable Aggregation, requires a min of 2 analytics.replicaCount | `false` | | `portal.license.secretName` | License secret name | `portal-license` | | `portal.license.value` | License value - ***Note: these are not required for Portal 5.x *** | `` | -| `portal.internalSSG.secretName` | APIM secret name | `ssg-secret` | -| `portal.internalSSG.username` | APIM username - auto-generated | `auto-generated` | -| `portal.internalSSG.password` | APIM password - auto-generated | `auto-generated` | +| `portal.internalSSG.secretName` | APIM/PSSG secret name | `ssg-secret` | +| `portal.internalSSG.username` | APIM/PSSG username - auto-generated | `auto-generated` | +| `portal.internalSSG.password` | APIM/PSSG password - auto-generated | `auto-generated` | | `portal.papi.secretName` | PAPI secret name | `papi-secret` | | `portal.papi.password` | PAPI password - auto-generated | `` | | `portal.otk.port` | OTK Port, update this to 9443 if migrating from Docker Swarm | `443` | @@ -321,7 +298,6 @@ This section describes configurable parameters in **values.yaml**, there is also | `analytics.affinity` | Affinity for pod assignment | `{} evaluated as a template` | | `analytics.additionalLabels` | A list of custom key: value labels | `not set` | | `apim.forceRedeploy` | Force redeployment during helm upgrade whether there is a change or not | `false` | -| `apim.preflightCheck.enabled` | Resolves a race condition that occurs on slower hardware where apim/ingress starts before other dependent services are ready |`true` | | `apim.replicaCount` | Number of APIM nodes | `1` | | `apim.image.pullPolicy` | APIM image pull policy | `IfNotPresent` | | `apim.otkDb.name` | APIM OTK Database name | `otk_db` | @@ -415,6 +391,30 @@ This section describes configurable parameters in **values.yaml**, there is also | `portalEnterprise.podSecurityContext`| Portal enterprise pod's security context settings. Overrides global.podSecurityContext settings | `{} evaluated as a template` | | `portalEnterprise.containerSecurityContext`| Portal enterprise container's security context settings. Overrides global.containerSecurityContext settings | `{} evaluated as a template` | | `portalEnterprise.forceRedeploy` | Force redeployment during helm upgrade whether there is a change or not | `false` | +| `pssg.forceRedeploy` | Force redeployment during helm upgrade whether there is a change or not | `false` | +| `pssg.replicaCount` | Number of PSSG nodes | `1` | +| `pssg.image.pullPolicy` | PSSG image pull policy | `IfNotPresent` | +| `pssg.pdb.create` | Create PodDisruptionBudget (PDB) object | `false` | +| `pssg.pdb.maxUnavailable` | Maximum number of simultaneous unavailable pods | `not set` | +| `pssg.pdb.minAvailable` | Minimum number of available pods | `1` | +| `pssg.strategy` | Update strategy | `{} evaluated as a template` | +| `pssg.resources` | Resource request/limits | `{} evaluated as a template` | +| `pssg.nodeSelector` | Node labels for pod assignment | `{} evaluated as a template` | +| `pssg.tolerations` | Pod tolerations for pod assignment | `{} evaluated as a template` | +| `pssg.affinity` | Affinity for pod assignment | `{} evaluated as a template` | +| `pssg.additionalLabels` | A list of custom key: value labels | `not set` | +| `pssg.podSecurityContext` | PSSG pod's security context settings. Overrides global.podSecurityContext settings | `{} evaluated as a template` | +| `pssg.containerSecurityContext`| PSSG container's security context settings. Overrides global.containerSecurityContext settings | `{} evaluated as a template` | +| `pssg.additionalEnv.CONFIG_8443_TLS` | Enabled Port 8443 TLS Versions | `If not specfied, Portal TLS defaults are enabled.` see [Portal TLS Defaults](#portal-tls-defaults) | +| `pssg.additionalEnv.CONFIG_9443_TLS` | Enabled Port 9443 TLS Versions | `If not specfied, Portal TLS defaults are enabled` see [Portal TLS Defaults](#portal-tls-defaults) | +| `pssg.additionalEnv.CONFIG_9446_TLS` | Enabled Port 9446 TLS Versions | `If not specfied, Portal TLS defaults are enabled` see [Portal TLS Defaults](#portal-tls-defaults) | +| `pssg.additionalEnv.CONFIG_9447_TLS` | Enabled Port 9447 TLS Versions | `If not specfied, Portal TLS defaults are enabled` see [Portal TLS Defaults](#portal-tls-defaults) | +| `pssg.additionalEnv.CONFIG_9448_TLS` | Enabled Port 9448 TLS Versions | `If not specfied, Portal TLS defaults are enabled` see [Portal TLS Defaults](#portal-tls-defaults) | +| `pssg.additionalEnv.CONFIG_8443_CIPHER_SUITE` | Enabled Port 8443 Cipher Suites | `If not specfied, Portal Cipher Suites defaults are enabled` see [Portal Cipher Suites Defaults](#portal-cipher-suites-defaults) | +| `pssg.additionalEnv.CONFIG_9443_CIPHER_SUITE` | Enabled Port 9443 Cipher Suites | `If not specfied, Portal Cipher Suites defaults are enabled` see [Portal Cipher Suites Defaults](#portal-cipher-suites-defaults) | +| `pssg.additionalEnv.CONFIG_9446_CIPHER_SUITE` | Enabled Port 9446 Cipher Suites | `If not specfied, Portal Cipher Suites defaults are enabled` see [Portal Cipher Suites Defaults](#portal-cipher-suites-defaults) | +| `pssg.additionalEnv.CONFIG_9447_CIPHER_SUITE` | Enabled Port 9447 Cipher Suites | `If not specfied, Portal Cipher Suites defaults are enabled` see [Portal Cipher Suites Defaults](#portal-cipher-suites-defaults) | +| `pssg.additionalEnv.CONFIG_9448_CIPHER_SUITE` | Enabled Port 9448 Cipher Suites | `If not specfied, Portal Cipher Suites defaults are enabled` see [Portal Cipher Suites Defaults](#portal-cipher-suites-defaults) | | `tenantProvisioner.forceRedeploy` | Force redeployment during helm upgrade whether there is a change or not | `false` | | `tenantProvisioner.replicaCount` | Number of tenant provisioner nodes | `1` | | `tenantProvisioner.javaOptions` | Java Options to pass in | `-Xms512m -Xmx512m` | @@ -442,16 +442,16 @@ This section describes configurable parameters in **values.yaml**, there is also #### Common configurations across multiple containers | Parameter | Description | Default | Container | |------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|--------------|-------------------------------------------------------------------------------------| -| `.additionalEnv.DATABASE_POOL_MINPOOLSIZE` | Minimum number of Connections a pool will maintain at any given time | `5` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_MAXPOOLSIZE` | Maximum number of Connections a pool will maintain at any given time | `30` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_CHECKOUTTIMEOUT` | The number of milliseconds a client calling getConnection() will wait for a Connection to be checked-in or acquired when the pool is exhausted | `30000 (ms)` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_MAXSTATEMENTSPERCONNECTION` | The number of PreparedStatements to be cached for a single pooled Connection | `50` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_IDLECONNECTIONTESTPERIOD` | Test all idle, pooled but unchecked-out connections, every this number of seconds | `60 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_INITIALPOOLSIZE` | Number of Connections a pool will try to acquire upon startup | `5` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_MAXSTATEMENTS` | The size of global PreparedStatement cache | `300` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, | -| `.additionalEnv.DATABASE_POOL_MAXCONNECTIONAGE` | A Connection older than maxConnectionAge will be destroyed and purged from the pool | `0 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_MAXIDLETIME` | Seconds a Connection can remain pooled but unused before being discarded. | `0 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | -| `.additionalEnv.DATABASE_POOL_MAXIDLETIMEEXCESSCONNECTIONS` | Number of seconds that Connections in excess of minPoolSize should be permitted to remain idle in the pool before being culled | `0 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress` | +| `.additionalEnv.DATABASE_POOL_MINPOOLSIZE` | Minimum number of Connections a pool will maintain at any given time | `5` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_MAXPOOLSIZE` | Maximum number of Connections a pool will maintain at any given time | `30` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_CHECKOUTTIMEOUT` | The number of milliseconds a client calling getConnection() will wait for a Connection to be checked-in or acquired when the pool is exhausted | `30000 (ms)` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_MAXSTATEMENTSPERCONNECTION` | The number of PreparedStatements to be cached for a single pooled Connection | `50` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_IDLECONNECTIONTESTPERIOD` | Test all idle, pooled but unchecked-out connections, every this number of seconds | `60 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_INITIALPOOLSIZE` | Number of Connections a pool will try to acquire upon startup | `5` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_MAXSTATEMENTS` | The size of global PreparedStatement cache | `300` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_MAXCONNECTIONAGE` | A Connection older than maxConnectionAge will be destroyed and purged from the pool | `0 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_MAXIDLETIME` | Seconds a Connection can remain pooled but unused before being discarded. | `0 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | +| `.additionalEnv.DATABASE_POOL_MAXIDLETIMEEXCESSCONNECTIONS` | Number of seconds that Connections in excess of minPoolSize should be permitted to remain idle in the pool before being culled | `0 seconds` | `portalData`, `portalEnterprise`, `tenantProvisioner`, `analytics`,`ingress`, `pssg` | #### Authenticator specific configurations | Parameter | Description | Default | @@ -503,7 +503,12 @@ Portal TLS defaults if the parameters are not set. | `apim.additionalEnv.CONFIG_1885_TLS` | APIM ingress Port 1885 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | | `apim.additionalEnv.CONFIG_9449_TLS` | APIM ingress Port 9449 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | | `apim.additionalEnv.CONFIG_1885_TLS` | APIM ingress Port 1885 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | -| `dispatcher.additionalEnv.CONFIG_HTTPS_TLS` | Dispatcher HTTPS TLS defaults if not specified | `TLSv1.2,TLSv1.3` | +| `dispatcher.additionalEnv.CONFIG_HTTPS_TLS` | Dispatcher HTTPS TLS defaults if not specified | `TLSv1.2,TLSv1.3` | +| `pssg.additionalEnv.CONFIG_8443_TLS` | PSSG Port 8443 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | +| `pssg.additionalEnv.CONFIG_9443_TLS` | PSSG Port 9443 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | +| `pssg.additionalEnv.CONFIG_9446_TLS` | PSSG Port 9446 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | +| `pssg.additionalEnv.CONFIG_9447_TLS` | PSSG Port 9447 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | +| `pssg.additionalEnv.CONFIG_9448_TLS` | PSSG Port 9448 TLS defaults if not specified | `TLSv1.2,TLSv1.3` | ## Portal Cipher Suites Defaults Portal Cipher Suites defaults if the parameters are not set. @@ -516,18 +521,25 @@ Portal Cipher Suites defaults if the parameters are not set. | `apim.additionalEnv.CONFIG_9449_CIPHER_SUITE` | APIM ingress Port 9449 Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_RC4_128_SHA,TLS_ECDH_RSA_WITH_RC4_128_SHA` | | `apim.additionalEnv.CONFIG_1885_CIPHER_SUITE` | APIM ingress Port 1885 Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_RC4_128_SHA,TLS_ECDH_RSA_WITH_RC4_128_SHA` | | `dispatcher.additionalEnv.CONFIG_HTTPS_CIPHER_SUITE` | Dispatcher HTTPS Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,ECDHE_RSA_AES128_GCM_SHA256,ECDHE_ECDSA_AES128_GCM_SHA256,ECDHE_RSA_AES256_GCM_SHA384,ECDHE_ECDSA_AES256_GCM_SHA384,DHE_RSA_AES128_GCM_SHA256,DHE_DSS_AES128_GCM_SHA256,kEDH+AESGCM,ECDH_RSA_AES128_SHA256,ECDHE_ECDSA_AES128_SHA256,ECDHE_ECDSA_AES128_SHA,ECDHE_ECDSA_AES256_SHA384,ECDHE_ECDSA_AES256_SHA,DES_RSA_AES128_SHA256,DHE_RSA_AES128_SHA,DHE_DSS_AES128_SHA256,DHE_RSA_AES256_SHA256,DHE_DSS_AES256_SHA,DHE_RSA_AES256_SHA,!aNULL,!eNULL,!EXPORT,!DES,!RC4,!3DES,!MD5,!PSK` | +| `pssg.additionalEnv.CONFIG_8443_CIPHER_SUITE` | APIM ingress Port 8443 Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256` | +| `pssg.additionalEnv.CONFIG_9443_CIPHER_SUITE` | APIM ingress Port 9443 Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256` | +| `pssg.additionalEnv.CONFIG_9446_CIPHER_SUITE` | APIM ingress Port 9446 Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_RC4_128_SHA,TLS_ECDH_RSA_WITH_RC4_128_SHA` | +| `pssg.additionalEnv.CONFIG_9447_CIPHER_SUITE` | APIM ingress Port 9447 Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_RC4_128_SHA,TLS_ECDH_RSA_WITH_RC4_128_SHA` | +| `pssg.additionalEnv.CONFIG_9448_CIPHER_SUITE` | APIM ingress Port 9448 Cipher Suites defaults if not specified | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_RC4_128_SHA,TLS_ECDH_RSA_WITH_RC4_128_SHA` | + ### Portal Supported TLS Versions | Name | Description | Supported TLS Versions | | ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | `apim` | APIM ingress HTTPS/MQTT-TLS supported TLS Versions | `TLSv1.0,TLSv1.1,TLSv1.2,TLSv1.3` | | `dispatcher` | Dispatcher HTTPS supported TLS Versions | `TLSv1.0,TLSv1.1,TLSv1.2,TLSv1.3` | +| `pssg` | PSSG HTTPS/MQTT-TLS supported TLS Versions | `TLSv1.0,TLSv1.1,TLSv1.2,TLSv1.3` | ### Portal Supported Cipher Suites | Name | Description | Supported TLS Versions | | ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | | `apim` | APIM ingress HTTPS/MQTT-TLS supported Cipher Suites | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA` | | `dispatcher` | Dispatcher HTTPS supported Cipher Suites | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,ECDHE_RSA_AES128_GCM_SHA256,ECDHE_ECDSA_AES128_GCM_SHA256,ECDHE_RSA_AES256_GCM_SHA384,ECDHE_ECDSA_AES256_GCM_SHA384,DHE_RSA_AES128_GCM_SHA256,DHE_DSS_AES128_GCM_SHA256,kEDH+AESGCM,ECDH_RSA_AES128_SHA256,ECDHE_ECDSA_AES128_SHA256,ECDHE_ECDSA_AES128_SHA,ECDHE_ECDSA_AES256_SHA384,ECDHE_ECDSA_AES256_SHA,DES_RSA_AES128_SHA256,DHE_RSA_AES128_SHA,DHE_DSS_AES128_SHA256,DHE_RSA_AES256_SHA256,DHE_DSS_AES256_SHA,DHE_RSA_AES256_SHA,!aNULL,!eNULL,!EXPORT,!DES,!RC4,!3DES,!MD5,!PSK` | - | +| `pssg` | PSSG HTTPS/MQTT-TLS supported Cipher Suites | `TLS_AES_256_GCM_SHA384,TLS_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA` | ### Portal Request XSS Filter The value of this variable should contain rules for sanitizing malicious scripts @@ -656,17 +668,18 @@ Portal Analytics ### Portal Images | Parameter | Description | Default | |-------------------------------------------|----------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------| -| `image.dispatcher` | dispatcher image | `dispatcher:5.3.1` | -| `image.apim` | APIM ingress image | `ingress:5.3.1` | -| `image.enterprise` | portal-enterprise image | `portal-enterprise:5.3.1` | -| `image.data` | portal-data image | `portal-data:5.3.1` | -| `image.tps` | tenant provisioner image | `tenant-provisioning-service:5.3.1` | -| `image.analytics` | Analytics image | `analytics-server:5.3.1` | -| `image.authenticator` | Authenticator image | `authenticator:5.3.1` | -| `image.dbUpgrade` | db upgrade image | `db-upgrade-portal:5.3.1` | -| `image.rbacUpgrade` | Analytics image, per Portal version | `db-upgrade-rbac:5.3.1` | -| `image.upgradeVerify` | Upgrade verification image | `upgrade-verify:5.3.1` | -| `image.tlsManager` | TLS manager image | `tls-automator:5.3.1` | +| `image.dispatcher` | dispatcher image | `dispatcher:5.3` | +| `image.pssg` | PSSG image | `pssg:5.3` | +| `image.apim` | APIM ingress image | `ingress:5.3` | +| `image.enterprise` | portal-enterprise image | `portal-enterprise:5.3` | +| `image.data` | portal-data image | `portal-data:5.3` | +| `image.tps` | tenant provisioner image | `tenant-provisioning-service:5.3` | +| `image.analytics` | Analytics image | `analytics-server:5.3` | +| `image.authenticator` | Authenticator image | `authenticator:5.3` | +| `image.dbUpgrade` | db upgrade image | `db-upgrade-portal:5.3` | +| `image.rbacUpgrade` | Analytics image, per Portal version | `db-upgrade-rbac:5.3` | +| `image.upgradeVerify` | Upgrade verification image | `upgrade-verify:5.3` | +| `image.tlsManager` | TLS manager image | `tls-automator:5.3` | ## Subcharts For Production, use an external MySQL Server. @@ -798,14 +811,14 @@ The following table lists the configured parameters of the Druid Subchart | Parameter | Description | Default | |-----------------------------|---------------------|--------------------------| -| `druid.image.zookeeper ` | Zookeeper image | `zookeeper:5.3.1` | -| `druid.image.broker` | Broker image | `druid:5.3.1` | -| `druid.image.coordinator` | Coordinator | `druid:5.3.1` | -| `druid.image.middlemanager` | Middlemanager image | `druid:5.3.1` | -| `druid.image.minio` | Minio image | `minio:5.3.1` | -| `druid.image.historical` | Historical image | `druid:5.3.1` | -| `druid.image.kafka` | Kafka image | `kafka:5.3.1` | -| `druid.image.ingestion` | Ingestion image | `ingestion-server:5.3.1` | +| `druid.image.zookeeper ` | Zookeeper image | `zookeeper:5.3` | +| `druid.image.broker` | Broker image | `druid:5.3` | +| `druid.image.coordinator` | Coordinator | `druid:5.3` | +| `druid.image.middlemanager` | Middlemanager image | `druid:5.3` | +| `druid.image.minio` | Minio image | `minio:5.3` | +| `druid.image.historical` | Historical image | `druid:5.3` | +| `druid.image.kafka` | Kafka image | `kafka:5.3` | +| `druid.image.ingestion` | Ingestion image | `ingestion-server:5.3` | ## RabbitMQ The following table lists the configured parameters of the Bitnami RabbitMQ Subchart - https://github.com/bitnami/charts/tree/master/bitnami/rabbitmq @@ -999,6 +1012,7 @@ If the RabbitMQ cluster is stopped or removed out of order, there is a chance th $ helm upgrade --set-file --set -f layer7/portal ``` + ### Helm UPGRADE FAILED: cannot patch "db-upgrade" and "rbac-upgrade" If helm upgrade of the portal fails with error "Error: UPGRADE FAILED: cannot patch 'db-upgrade'", it is becasue of the limitation in kubernetes where a job can not be updated. @@ -1013,6 +1027,7 @@ kubectl delete job db-upgrade -n kubectl delete job rbac-upgrade -n ``` + ### MySQL container in unhealthy state #### The chart was uninstalled and re-installed diff --git a/charts/portal/charts/druid-1.0.14.tgz b/charts/portal/charts/druid-1.0.14.tgz index e4b01066ebe3a325d7b3d13db236ef8e438c8561..89e2614a35fc1a384a77463b033f2b491c35d371 100644 GIT binary patch literal 9453 zcmVDc zVQyr3R8em|NM&qo0PKD1bK5ww?|fF3{|8)oPSwnwh@zfOROJsETbuEj#P+eAnccg! z<$_5_;+P^i1n5LbeE;@a0QdmGw{U3n(9L&hc!vwlNs2hJvuG|Yr z&@p~TE;ejy1RlE$=s4lO-M5OWbQ(Isnrk?OJ^RJAp|06WFuuO{2(E3HKog8DXs(E% zVZg>wV_`4R2rLM3@TlFM8)V_#E1JD*pN(m;Hgt?-OQTtFV+jq5K*K^V9yMCPg0$#+ z`1LD1>8gVU|DO%g2DUv{Lo8c4+GORR5rB?k8XBbhHy(q!b!gT4jeWQN{u7t~M`(Ho zKbHb1kpGi@uOrLN@>LOLKexJN)oj%lxu4j={)Ouc)a(VhXaK(w@|K)^YAM5gT^*ViOR4VvY> zY2QN=@G*JRn6rOJM-2cRmg@#NHa3Xuu0}wERN&j}rDvK`q`8QUz`g&K7JW-!9@Fn* z%HIrnCZXIeSNJazU_^*v%`t%Y_9J=&v<0;02pBWk4i?hrOPU*60DU3IwV(-fNZ>uh zNTJ+fL_FslE$wsv=?D1n?VyJsgTPxDAbpRCBE`oiax^Ly>3%IeC?u{@nr;b^w@Iz4gtVKbEvH-vy>DT zKEvMx^}dX~J&x)FG5&13`UsquaD`mj$ury4&<*0FB`kB)FqUwR7*k(u`vD;bxg+7v zfuhoP_pbdwUohPjJk)I4)eQ?0TYj@NblpTtXu)}+)Y7mFd*uJ}pDhebY}e4BDP?|u zvj;fxfBDZ0YmP9V8^b?a7`cxDyGIR&PCA$%OXF3e)Priqzcx_c8~mxyS3i8-_R<0#2Zj}G}mzP z7mjJS>&PMoG{K+Pw!q9V5mnXxx9O+YD0)CEUSzJ(5C0FQqdoZeF?es=a})8(0>`!g zL>g()xq`m-|G&_K5|Flb5qB_>MUmn5)kHEL5fd3_0vbm%?7=HAH%QTioZl+^k**cmc6KPE0(2U0b z&Sr*XkQI}iqedj6Os)7DR8VM9y}F&Zos5dFTh+oklx&X@RgG)djCz=KlsqDH1pXM` zTyov1qc45|surP3_~iGt!+V(y4V^z44hFr!bM<`xePO?|EG3%4pPS0J!825+Q(T>H z$?Ax+YJ3n2Z_;bV2liWa>jOKl>Vr&a9HgBeD?2*RFjZa85HD&^$*b zTuqT?TRI+rPS+p5#8@KRBhd@~cm@sAbJ6X>MVQWPBhd5P0l9{)N7)CyYEgcgQgxi-_x09(tzK|_`qsacNo(v@W zPhahHYx~bGQe^#sE&_&y2{cV^zo9w{kOcx~;|y!fzL~Gn#z~g{y9F{GI;blTNRe|6QbS-`alzkH&HYFe1zXKvoVqUD9UJ7H9^R`+2~Se-X>@XFPU{l;a*3&0s_kK+yg zxBd$^C3^hR)karg|W`QJ^@ylYk#vY=XEiume4wia?3v0e7k_YhAB)E97!@^cnBE5Sk<uL1zJ8$REGq_akybhltsKoQ+Nsof>yy zMNCDEp`}As;Kx~vUO;mO4HGo4xq|j9D$_J9AUMjK3BD4{#_Gr9^Nz~rkF&6@f;_gk zJhl>4Ej`{O{{I(H)&LyZH+K+}3P|ZW-q}!%U%j3x(!Mox7T#8Q^*d(iXa{VI^?n zGl-9e+sJBbu!SswT*oyqYGHduK0_C^nQ!@|#XNA#5wS!TY14o8VBhLHwcCT1sw@cY z^z?c~d^0~}y}CNM)z!XtO|K`(`+x4g@_)6s4SQ2uSdsm2*p=~LC*8rI-v93+#qgh< zqsD__=_7E)`u!txjv7luAe{@CiJrUuVuOP@dFXy6FyceU39|49Y_~F^^L8-Iq5M zddms<3N-Z0D}kfa|8P|1`syaD44q!Uckq{Ilc3z$)#dH@;&O6x_u=aO-G|BVlMk`N zoGT^pl7XG8wtV?_^!qJQ7MxJ(vDHKP)KWbnHX)Ld_%o12z8rJv`8Ya9q1342Pr3qL@ zvG|HS=Zo;mCkx8oj6KZ!YFg3wcX8l_PrBK7ug> zDs_E~40PuxK%)6iB@vY>ixH+RI1bPQ;LJ3TMJ}%Q-Mhu9K>i6NXy%z1ZE`xS$p5Ey z`f>U1s=ZqNcauc@87K>y ze7Y6Nvx4C1X#|?|A6owDshPCfmHC>#8rZ_uLM2yq$q)j{FQu;Y(OWoe`642_d}cjI zhXhTD3kjMB_-%g9?#4Dv!iu8%( zvNM39iM0sl7g~ha|Ab33v)FfF8J3PL0y^EC`ec1xM8^r4CD2?Z8?oXWvO;VV@zZFc zw?TNC$B0;XLp~e^g!Np5tj=tUpf5xyg5z)USW2Oj$C-&yiYsPgX0qv&ZYJNVj9gKu zT8Y^qNE{W)G+cs-__;pt^dw|r<^0Br)S^K1T7Z}~lWL5Yk8r3mjr86QE0^8O75hDt zVn%}(jDRgNSVXai!Puw(?AXTR-(7n-5}&nvMD$1K+@RSg?pVt-Ee0tS>K=aXi=dQ) zq}j_Qr0bY};l&%!wjI*e4LG-KObo5PK+q(MJ8glq2L&(w9WR}Wp$}39mOe-s(D|@m z(joLgN;_(>+v5?0w%B4XWq0MuIG%8$a(5K^6q9e&d z)=*{fH&La-y=jVq6bUu6HL{ERQ&e0Tj?K?-g~J&Wxl6-hbK!dzYUn!NVZ#@*XQ|Wn zlDz*Hj&+HDZ{!Iq*#GysUCI8}?eqpG_5ObsX&wJxa$KYv0i+{>hvEqo)T_W@w#V=J zy@VexE-$X`KHYraQFBJ^Ha~bDoOb5#fBAIw+aykv<5Qv&=svyk@$LAR@pN)``_F4$ zVV8%A&_h(z%rH%0NEjj+6O{o8VtK_Hq=Ll~fiWcBqGpx4x0Rg##E==m7X^S;3eBAI z66etj8j=ZnFWSk+AykUgfnmu{)5#r+#gWYekK~a>;AZl_pDu0+i9}&PWI{KeF3#^l za^Z-N+aw~upInn7hqWj%g4ddvl01tp5f#U^9pn;&F0{V4xUj}7A*X!ONvH>&$uXh9 zwjFfMcN&}@20+Xsa=}(SZ0UM>ecMx~S^4<-G(Qi-SC7awZC6+PpaiEuz?FjRw*SX8 zR>k0{NWee!uDG6MAy;9?EnKv;2};Z52MgiZ0$rTN&x2u_if!fc%<=?n(K*k}ru$KV zZtWXH*Wstvx1C>eODy4+DVi^lMeu2N5bJxtB3xOW<}0y%&x-#!sqFf16C_BH|M#SS zBKv=a!#e)oPEvg8j_J#127yTGKe@Ebg@eePR>6dnD4PomNtCaM4k=ZBJ%~uGQOn>& z%E~{FG4w3^KXova<-gNcYx&a z3%5r>B)zg*q%i+?a6jxLOOuw_`|kEIm6!kZkzhsgKU5R)KN!^UA9j+eT3Z|*P^`54Z-4~Lm;a91Kj}*H-|Y{EwfyfQZGite zctrpX4ha@B9_;}RmQY6mCQN#l3JeqZKTLF3V$8iph*)eGRm6#0Cw!=5$u{$#IhQhurH`__F z{V$4mFZ{V-9GC+8f4AH1$@YI$t?{2bN$cQ069XgN{1;{0i}f!9{Tb)#C8Ioxpn6eF zH%02nJ(&U2>m4=t`(yCy?d>(-cNqY(pesx)lcxTqlz#AbflfecOky1vhoYIcKlV zpteAYY4dv}@#(+5HR(ju95vgI(DfG_eqP*s(_F$YQ{yXYjygRxOi%w#X%j!^sgO@- zmH+jSy8;^hx>#1|YW7a?Fk&nwpn!>-j_r6<7SpryJPdrO!PyKMR?2JI+!t2R;Bl5~ z@ZVvla`XRYai9wEf4v0$uh*&P|DB|`b41V%&kg^J&nbz8MK1VHVzUbNuefL~^iM8c z5&2i9_6hbkxko5g`D#QzOs|9_{e*709;(~i{%l_)L-iD7Fb#j^OHef3;b-1ugRzN zVgNt!3pM2LM4~st?_Jw-Mxdj1)a(Y&g$yN?0oWKZBwRjU1u!J^UPZi+Xsg>E5T^{) z8Z8v1?Lbss2VCfR@Iq_jVp1JZK{^0fOV;v9WK2mZnP^BEAX18OyikIsgeoaTGFB!* zF$qK|MN}@9pqsp%ycAuzm_&E~FrW-yoygY~M@O9QHU>wW;&#SHoaWYsMx1QH$S8}L z>Xnd; zGvD=nWW z_t%zW`@dn$5vFn&{k8Eea7FmPeqWCNs17>y`Tw1yb?|@D$l#czToj<3c`v?z3@l(8 zZ@-QI{@eKOmz%5KCO6X&c!0A9IC`hPV}XbHV;}by-63=J`{d@s)y;VlM3@s`GAxup z5hkJz$RYZ!Zq6?*$G2B0sKuNQish<)bKBU(>+#L)#qGt_<=xrUr_0;;WkpQLq?*O>s zqi|oigkPqfOWUy{Jc>aX*^5+oKvba=bU;~zLfT+i4-Ak#>|P@zKp06C5dkSB*Y$Qs zq}Ig)WKh_gq4m%J>E$=)W@FcTE~ys-1t{;x&k|&?u{%GcT*;dswSPrter!{-EjM`y zqO~hON(T`$<1jq=b>NR@4*U^3INAo#A;;nt(J6`ok|6R-p+KPHyrlRT+rR;AUgh21 zww5_Jt>>#wD_>cym-4#5Q~TYFMb=C7>-P3;Cn#h8+3fUZne(3s|BqVxe|D4N8)9L1 z@yy3R!!M;7lyVP$#(AuA_Oq~L?$J-Fbj6dOB}%V%@H4qVs&f3Zl>BdU_rnim&VQZ^ z68_&_ua^H^q{{a{mqu%24grPw+zq+EWB<)~$syl-zqqE>_`q92mjLY)RP!s&;#<;H_ z707=_?Mm?TW-|L-QPgZ~moN4oU09D5P@45U}c5Qlg90IqlHI}YIDPouzYXIGb( zlQV{m$qoni^fXF)O%(&@ms1^||3107y_iloJS?3dA=8J8>Fwl_fzPf#j4v*4C;zw| zwc8;EjTb1&FpWF5m>OOHg$+h`Jd{wdcYV&G^AG&1eptgOgB06v=z9b1`iyfm<>=&sbcjCmVqPY)-Jbhxiw3bsB{Qo zJ^)cJS!qDZz{3>K;k$11IwPb`OpT=ntdS$`XfU?jGVM8zH=Q3Yhc1mWbG`x;B#&;h zUL=={=B|Ud#Dcg4(_wP|C-484hOV1v$yV=f{J*vR!3F#Oo;sB8|LUqIwf%1=X&wJ> z+Nemk1H^Lf#U7C159W-0j2L^(7lFlkq5555bSC|RT*dV)3%QD~=UwR4p+cbbk0tKR>8~&J*SUw0 z%Yrt3wJmh|>Glk?&S!>+6l7_(ZdmivPq%+>y#=j*{A2XrlP?CjvaURGHT#H`w!50R zuI+->IsJ^{5rf?bH#e-g;y3ZB?amci8Fs4~e`VV9{-4U9o~eAW=P7LvRDm{^!p=`Y z{BUl#r%@t75fQpvv@4%imBMz)pO;4|BO2nPE~S@QmXue@#3{zWjGowJXp6z0Po0%l|IY2KbK`p$Ndi;X&dv{yuOa zDVj>aha}#n;zZ)LI83}q%IJHIxDjbURm6{ElwKD&5hu4Uo+O9Lb{Ja^Uy@B@J6vsy z@hBwsVsIzrBgCajIoKFM5+hqFM4V*1t`;UPUU-XP*h&(v!^K7EFz!q{jCgU+6EJS= zfM{7R$RHiS)8h}laDU{>;qu6MCQn_Pw!^91hpKCIjsV!eQESu`ps*H?o)0x$kv zts-?;`D(3wnMf8j_y0J?yf)x~)ARw}mX?t{mI2 zh=Lcqy@3B!fO|>(74hWD=fu)kaaN~)r&`97CX=Mxe)U|m-`X-3HmJf}!~3nkT*Jx! z61Z|)`%k2i3w^V$vhkklY2%c7#<=1m^3%xf@>#w-4V;&L@|*7vm4p)TT%owC%Zu?;g-f`4ih#v&cv{qw=T<125KgJGMp5bTAeJEl3ly9Bn z^E@vjRg>=#NmPV8F?_oc_baw3okTvSNz;@qT_V$l`1SVoI{q%z5h*zmB|oF|w!leQ z;DrQW1`X45QC5arH*{8uW!E>oHR(rI>}}aLO>MWHx=F(gH*UCI;d*RcUuV4ROZ0Kd z-pQgR6ITv$uz*lwlvOGsBl|W~*6CSNp8bE1@t?c>L2duvMUv0|QC0B#=l*x%xUs$s8dA{6|>z?Cd4YrH;&!YTqdhb_|3go}r>B|1U;mM%(|L-JK zzW*z_@*;KJ@btu1p-F$r0+~w%FWL*+ei#AAMJ>a^1e#`njyR0#!oGb=8ggmH`QG{N zA>1d*29&Igtxzz$7>qBuMDt`SH5Xd?*mM@~(p!R#nk?_@h%BCYXC-)!>?Qe|@p3#% z)M7mM^LVaeoDpp(DNGCH<{I7m{tvb-`O~fZZ)ccSDw`ak6)(j|y-#?NDS!Uo&HWFDKH2ouqZn{~sWtr`mb{UZC{g0Dj9HT2O#o`QOR?4;^*bljA?CYOj|6og{w^VcBE@3}A7jfCE$+;6DKb zSQT(5MFQ}jRzvw6#L52}0azmdcY**676luh+|MBMVovNo|4k88=RsX}5yn()I<8?6 z(Da+G8J`HS12qJi3VzfSe@&>Ewgydpyb}`G6h77ppLps)42F;d@eJMb`Y=V0!M6s2_u19lkv2ZFaY^YIn{t?>Ec8qkKBok#Mh<$Ad&x@qdsI?!NUGTMnJ}dE z2FivYRRJKSH{jtmQ^CzHT$D=P>>|#e2Ld75*99#ZtyW*q61$)!Sp0~-l%3drWc#1L z6Kz4h6-_)?#}HU#|36U^@xOpW*G>x49X5Qikj}RMFM-)5*>6lbejV zMe(P?I>n&t6VD=sDJ~z=KrQ}_-rv3fsOz*~2RuEUMw<(|STPbMv*OYu`ML8{X@M7D+2#d1U0oQ%fk4bo2p8K_Eo?xL1iq0J%X?k{2MPU*?eK(1=p($_I5Y zV1SeLzz{hdSpyB zhJ+y3!hqO-4*~Fbfh=(E8K!PnbKpSj0nQOtjvB|{c41(EJ%?LH@dBA9pjw0P`3-CS z2Dr$C#CSvuD=0jNmQE>HXwH;7_{nk6%=m(I@Yx^>@PB?*z?EgLfNim&lqo#G0+6_F?&^x%}Tu#^)a=%2I!pZxqUZw=2niXV^Qb<$o9H_!#`+ z+ECZ*B^X~{d<55Q7YfD}G*`sXFgRO4mmD>i;JeZ0)ZcnwKo%%08@~YPaVGS$Ow~W-r@kW6D(xfa%)OY> zIX(uTFq|XM0)&z@Fn|Di_btXOuxCC;{ulXE1G8hUm_SR1CbTW|1~|*`EqOU%DNdDEn z9RHy===N&)-$i1;W8Y&M9rzCKiF;|oxlVPeQ=RHmGX4Jm00960Vu#e)0CWKWR&u@W literal 9388 zcmV;dBvacTiwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMYObKADkH{RF!6!^=%X4+m6MM;*FXvQy8TPO9^#P(%5?K%H5 zXFMie_b1Aq?z_$=D8oLhL2$Rw~_JnRD4{b6DHfn|12SI{Tg2CnVz zo+0VFu8)q7+5ft(tN-hR@#wqW@wj(<+#BoT@ppQ!Kj`J@(6qOv+qLFaMxgZb^Z}txjun5m^#qj z5X-=Tjic7eU84zD5#r%Vx4X2+D!9`Ocilam(qdicS?i8Lv*OkoS`LAhgM2(`b$|nD z(f9DLzu>s94_o|iHb`684SWN!Y}II!jfW-xdY)|=kn-Ppi0am(RXc9IbnCx-;`09h z?EvBDQUE3LKkoHY@;@Bu2l?McIufK86KLE6!*v$cGVqzifDV{?&{!dG#$@ma+^non z&Vhx2iLkYFkO_zj?hr7MXS*9@0*Cj=EJ z-8*OlJ|0_3_Sd8ZfX8xNBhSSaasAB%7?6s3m%a;ZdyWhrkqNj9KhU8sTL2u<4`a&M z0tPmrY_2!>Pa9xFh~+FXfOqZ#dIO9Vbe0HM3tE2%8T2L14IO~K5ac`11|}r%4q~LW zj%fM7J40*tEPOZt#1Bvl#JO&m_F-QWp8n!ul731XU;+jMeIz{mgwcHdAw~BZ{TWz3 zf3<)%Msg9Kt4wIFEk}40Hc$%y9Nd{MRl8R{T3BBuz(fxn-o7mWY_x>NhH^>i;N%nh zMO51h@#Rrc4~X$+*Ec6%Y{L!mTdjrb8|WJGfe{sGS!=jNl$pO=_Z}e+`4i#iP}5t0 zcI7>N&NNi`%y3=bv>ZrW<;B`EO&hJD1D9%ay*T3ML5zGXmL&Uz0Q_iz&a z#~)eF5@9~~#Xmb3`41tVEsstqm>|bs6{3X0y2;-e>hCS~Fy!Yr`aAq+FZx?(685Zh z1m?(punYvIhT#Sd0SnjX@(3`0gInQ`FbDm-;Uh?*VR^)7)>eyuy#)Xa$cl4`+0eLP z!-l=?@F(o$5ts(V?JSXld`OTP=AfmSctOKJ7~kHb&4m5Ui}JszvOv55xC@MXL;zVq z0#>eVVxe)^@L`qOxPc$aIu){?H;Ldk~akOtj-z{-!gFP2pF~-nDek} zW0AmvB_!xG-0*fp4!pCGnY;&4_sksAb1jEVK)cPJ^UwZ@Ht`eQZpo9Sfy;;=(JnTT zLo8^6Kd|e7g=HhEY{Spe&#>`wk2b8t(xBh`A52Gc_}wG$-gTEY;#CBm@BV=d(y>hT zHvIG44D&g_Anwv5dLoG&h1a^)k89Kwji zi#?jtM}Gzg6FdQ5A49I!Xw9a9{&4h>%Z+WVt%58^z;R79M>aB;_W1hPIs$O9upEnQ zCaqR0kvpm(LIo(OrMM>j-rHVgMYpP33EP#bUsg9+J7)53(?Rfn>-@wu=#|x=U!ex#oF|P; z;YC(u_+WjjKjmO8sOzxTFB3$brL4Zfq)Dq~Js<~ReC4}$A-goA1?@9r!_6ESu4Cc} z==J%iB-R?a0ZE>-rweG=fsbxhKEibNnScSWIr1&nOfnDoXb+fr7IO0@gr-%6m3Pn2 z$<9Y||0zatvX*KvBKh_t%m#g8QG&{B!>4d{y;iBhh8NIvm%gq(yrUwiGCgfrp;h?$ z?^$IuuTtZo{ydd>>0Rw1RZZOfL(tl@Awjr%ad|VFYvc=g!f%w>fA#UPV*feTd*g%s zXBR24{y-lA%fSTNHaFlEPKcwbKmH*onvOVNujd)LH3NDfVQBNPM z@;~kk4)VW?^!01^C-7jcCjcYD3e>mPT{7K__{~tT`HYIMQ_*(0=322b%Np0r|dVBJejLe&85j zG+;li^*mTCtS_M5Nr)lGWWPCgr_9_1VEm0mVA~t;X8>($VNs3dd5mwZ^*iF!S$;yl zLF<6Q9Wr2m5y0*mfnS3=NRN=f7}Up~k;kXO!jr zmPVh@tyEM(cO&gm*0td{;kj&hhwR+$WqI1Ul@Z&T{|?=@;BU5%fCd8X|89f!ZM&W< z@#=s%;#0qBN#vs7`s`)s{+$zO+_ykZMP$SDMc#dlST*LL~rf!)#nl!rh*JzHciKh+P5$uK_V`aJq)*^R1L*N9si=3_jJIEo(_k0VZ z4t5vhGxSlHxr4_Y=2l~Vh&6IZm;Px++se=h-5qvxZAEAYXH+QRnfVnD%b@*O2EFt) z=8(2b>i(bm%fkOU+}Pd}7glEf8|kY3Z`>apANK#dND}_D*SfbHa{^9Tw||6QYmEq` zbIha#LTsiqGFpIdV?x&h^t>no`Dl zrSd-iSyRoLYa?LXf`vHT8{~VZ0L?oS& zuN@?9;+c0X>>-0@RMv0;OKZ!SK0wQccXlXi;*%^P%Pu9Y>kB>yzkG6_@g(62;4}1pvHXYDh=w|#O#X*GRsP4v2mJSLQs(?0POG`I z{~k^Ik=8Km02Ab&UroS;>!1(_!WfKBm9*dLZ~Gke7-OUQ9I6BTC5rHE{GlwNat$%U zw85qk+yR{07IMh>)k}Bg7O6!32_$F{*cdfA9abX$!_iom<-e~F4)gzRk|_Vs^Kde? z&%?f-D^vQODuT#N=CgAg-`}In8}R)Dv_aZZ2~Crs#-Pn7-K01x2Ob|MpiTdv#UCHr zs`anRr^3}h(@#a}t=57e#+_ftT@?b%aMrR#1fOvx1J8s6&4~{QT83zEexmN$wQb8; zeqtGzrZqptHoXX>b_IQC+sJN#xbs8ig|S4FE!87Eh*X=lbfP4&_d>^U2|KeS&?43v zVFK44tFq&MmbYpd{TekmNYML&KZ%i1d_h?bE={JNUSCE~If4IpHlZbm`!Be*b4&dV z9Lq70LqM;eTa~id04e3(k-+1)~bX|{hO$#m^ z7Zc0qt`M}z>eg5x<6gt7|44<4fca6%2IxmA8;~D&MkX*nN*RY1c3IEpEX4CyG~Qz+ zsgtOYD|wg2Q?`W07dcw3pF0Yx(HJay}% z@K_aBc2oN^+~8;$ME=@x*aY|9hX%TmJ8AS}`wMmdCmbpge>d_3mF)ipy`ggczuy~- z4*2h#q}u+U^q|Pv1j=XA_Q4Y*NU6YFuFL1Sy+j|+FU~J-KV5&|fl?;jErAG}Q4h&UWlrsEdNcibI-lL%{OgL>)#p(H%otO%uxuMx3KT^})a0N`SYCns zOpsA3B7)3W(x6JGcGCJ&43-dnF9G*tP%J1da~)HQ)I=?QZkwkk?=v;p~Kf8^o#baFFoF@1%t)7!o6cNEw*#f{19J-#+ zJm2+@Pb@k&|J`AdDeZ?(_{^dz0-ndSp~Y6Dbct{ho>2ur$RRSorb)KMIk~zS=<}Rx zd?8bq1>(yGe(TehvaP7%K>OVkRzv!YyP7~kc_y+(Agc5-#o`=zMB8h)9hNBzY>A)amnq0OUy_y{;^P z1E?IREdmClO4maNR4Kj%L_loGt#ATW<)6o=d6xa3J{%6z{ok=ZJjnkpQjY(h z#eXW^{KY|{_GbfH0IvWj zR9XHTAc2bIzo!pW{C~fHJUp!bcapZn|Ln0M0Q-dmk}OI)g#)R|NWcWiuQGu_BHw$4 z4pK+gw*?WB224GiP-fBX@G&B(EfGVxB${)y6?Q0(Ky!AQLU&4NeOpkXwDf|;cp`yj z9Z-?j?)8vGV#%k&?^L4t&0&mG00|!^+yy#4J)OwriHmePpZ|V&efEqMPz)(5 z1c#?Eh{T_TUg|art=}%FJj>AW!btV%7oG|OmkEs6bLwt~`S6R4@mA6z?FqmOiri)DFP(`Q$ZtR`Wt8ndQ)1|~qCCq$dr2jmVfK{X%Yp0-TI}r+_~qv23h)s7fUM~16f2}@a}wfd zPO!e=8BPXzRQ$?!>Dq|hx5Zzw*qL|1Vu5^-k{4&x_)862f1#f@1mTmOe*AVg9)(wv zr1A?N9!B2{;cU^3O%luO%_%fiNV8pjcOX9b_t!R^-`bOQ_W}Ch!X?a$+i%)y_+@VW zh1!$eK#$Yof6{FcW;_wH#jWwb0rEG%pq~~B3O&nSX#qxzJrxd^%ILXXKm{%{H_yV* zhX!0MkmaP`(l$PKqE;4}J>dVofmCh&Zx#or6#u8j|LE(3e(x~L6G44EBm7UA zUs9`z0`Q;0UJdMDX~`n!pIW#c@~=YaEr5SQ8#am$R89Vy#Q`eC{|tKS`oG^h#Q)hz zs)_%RM0cN-{WZ})10@a+zl2M{_zbc!K2j}T0mP>;Rh0imaezwjKfTdNjsMf{^$+sD zle8`VXKxh&*e~>tF#GQo{G(_o0sAAp$%Ot0Oz#=;M;Tb(7Vt+LEA?IsiY?eGBSWVmVvj_r4o=6VTIpdR{{p;e}E%4;sUT zguBOUpoN4!s|OYmt#VI>!>K~_02KmHgj9L;SfS?t3vG#w$#Nk@>7~Ifd8;6iD=nj> z+JGurq!L}ZkV;a4m{g)Dl~D<%Q7M&Zs>M{Y=_{@)kyVSyWM3Eyl;dR+nR>cWA(MTA zK_L@-k})BZe5xTKQ!O456;V@zO4IUIpsCFAyTeQgrkdSAra+tX9+tr*tITMD|2pr%q~fpTUAUjKtkG0FWsd+IDyX z{tepK2%5k97D1Pef!ZKZ;n_nf^irSN5Mx39#K#wT<4DXTt@ASkTDglqdKliwFUuPz zE2%;c`Pjk)IR=Uy>(XB3$*+J=?Z1|@M3{Dc@~iPJP-Xb9<6bKM`%pi`|JzBbjsHr9 z1xK?Kpup6uJGTXAW5F`m`gQt`U#GV}Utj(@yPi+LJzU(w$vgdBzXbq)8sfgEcFKvT<){p_=iaPnexNvN_Y{zMfruI6s}{5n&ys+N#^%Qk=qcfIsyH*t|f6 zTSqwDO)SYh390zfdibSMmHD5$Q|P+=S>iv9kNe|P{HMWT{@+Q;_y3;7yhClZ9Mm**W$>XCL1SMyD0jEpUO!I|Uh z+wuqtL#CcXIHTZpF3*I}mhRvj0!_Ku${CzpyeTV9eXoU-UWX^Rsw+1~WIc{di2uKnR4@L2{*rY6tiStu6TnONxSXoVf0NU{N1Y*z5H2;$n8npfdTE*|d(~GkSK*q`i-%|$Y_rc%5M-Sj{U<3qo zOwjJML1zJa`*|(VA?+v?>Hns7pD2~C|Bi>M{_hP32mQZ`B-?*Dj`A68Kama;=aK@O zPr^?PdrwiJB3qA8uAZHzxZoBx9^OjL3_BH5k^DE^_eH5p{*Tr8uf4H;e7OHnVDe3FOT@HS^LDo|5tNZ9#d%AyE&;s}$M} zsmh6L3E#~q+=Pp*V7uv}O;~6Okji@A`+blqy#tO7u>s9Hsp zDymYZ>|}xxiy?_>!5V{4fg)zW5a0FVx7qPkBt4ZGz(kF{VnAtYWV=f&wOANCg)VRM zGQMt1Bnx)3O^A=|HaCZptKx9J3m^Fr!RNzNt#>(7em4-th$t`{xK;1nWEG19t%k#P^u4g;GN!qV(DI z?~$(=(1V6WHYWp-&<(`*z=nZitbhl7xJE?2vP!A?AMgQQdIX<@_#n{v=Nk8x^uI6k zzq0@%p9TE;%XQGnr<+sIIa^pZ(vV}grsXV8KHdDI^A>de`OnFJ&%RjX(zy)C<>Dh+ zyZ&b8`>qc!+wS79inOFl#d2DV zF1TEuH5$HjuKDsSxrXZq`~pqa^#ChmImCNc)=VtpB#fgOvGy$147#-#gY1=YMvRWD~nQ5kDgiL|q+btt|_1A!$Bq;6thu zF2adql&^;usYYN6+=$$&mGC2V2daL;YO69Qx89qQ+PZ0giLHpJV^nOr{HQUd`Uiu zr(mfm%A=Ip>%g5<4H1_m&!91gM50KiGeEk+#79Bts+H?&DbQ&h0&U zcpu8kOE>Xery}`pdhbV+isir88}(D?e@CN(|7RyDwQiyN1H*O$bI!pds_VDLB_WY2 z*b^NA_RS{Dwqmd0DiA&2GED2R?KL3LFxblK8;ziE&DzTbMO`beRA^hHB_*=8RX0_* z2^U*han+*Ru@IdLFjmM6Y~;%p66taFfdZvq?$)T-3Yv^>@C4RR$8zggJ!xBJSv#fJ z_?exD2TMrMXSmUjL)C|3$4d+upxwQ*oGxCq-w5y99RtY^x&iiCPSZ8+k>5cM@i(4p zIYh%N-clg^B*25TdP*1yWpU=1tT?OBf3obNscm&yME?qW^nw*--`|@1rGa0N_oac; zy(F;Y`R*UcAm?V24s!8JR?)>7Rg_rbL-5n}hwMtK=I@3N^DJsxjt@mqbpkB;YJhxz zuH8k%=o&tvy4Zp?ZYz0x1kFpw-b_G@j4rHArb#ipP?``gWja-k2kN?P#yuy`G~AM7k26u z;|C*uMVq|ZPJf>ZWDsannXyV~6qb{YQW@BnHLy^*zEp32bZf>rmSD79r*+-;!kmQ%e z&ZlDc5&#Qm*@2I8-WNF(bJ{7lp4m-Ezp!C%t2Jb1YYp`6n`_jtxdvrxsV)6ia?#i2 zw^DpgB?}%d`^pLMSRYhW83GTxv;P&@e_t^EYyS}cZ8u3h|3k;-v!46mb`4RM3eWjO z{M0(%lV7O#Tu)rC?s=Y~f?J*Ap{?{H@n1#xZ+h=fluG2kuMfv5|L^F4|KCZfcmGck z`#y6Pdwirzpp>b7h3vJ4SKXEC-cNw%qmJcZ0&RPLd_x(R1%3URHu}-(@-5lzeY6Wv z_u_e5CZSw>D-fIY1&dZDEgw4O)b>{JB3Of-o+{0CL>{}mcT{$ht#|PbuL`>gEs5RZ ze0FPW^2N<~2ERhFr9t;p|ASpe`EIB1!`b`vdV6zux0}IcR>_R}p=vOz?1$5v%R(-a z(iOPa`NH&&c9M$c|J}rYAC6P;pL>V2G39OQXu*d;$lmjo+bIwJ#DO9~NArqjY3(cK}PswbSTx?1W zWJ+eM?PcQ>-`>E*rONFM!d$oq*pipHg(17G4!1Dy0LjtPMR0Yzv|(mPNwxold({r) zo7L2VZ47~>_@A*F|F1Xd4-fXgU8GQyp<~7ZBAY8BB+w6{i7=AdlwspX)l{hZ6vDij z*n%2%6DQgircHr-yU22-Y>pWwMn^Ws?9_Xa%qyMTMpy*4E%5l%3QCp#_!5icSK~Mk zW%57hjaB>quzxuJy^~Zs{)0L!vcxRTvvZMp>E?WOsfzqJ#Q~Se|5#V!|Lc1H5dVKC zN%ouwR~S7X23XV%s!l1u0?WMBzyp^REW!jUW$WRB%L{LT4Nh9`N$|l{fG>pvYfNI?6D?VO4D$?5&A)+u#xLR;W~vUrrd0WOUf?Zl$EBaph8LqjFPbWQ&kLTjFpKg)``lMbXdK6 z2$FJ77u~-C&2Q`efeaXig16}R-u4RLzkU0*=>0%`pBtDcxq^B=yZ&u2e5?<8%^(%m;Nz3)X$+A=!6*TUZ596iXu&6FoDqdx7U6NmBH8eK;I$iId3h zxdT>$V!o+EhtxE2`;WFl_S#xHu8*GK8)f$2;XsZ5(jOlDKf6gs;0h9gdY{pRWi2aAg!gH&2Q(# z^-=2xoVx3^>ww=*=fJdl+|rg7>9T)0`z`J6FTczFjUKF)UHVV-Cw_3c386b^+y@?5 zST@3~pEUg0YyG6%!TZ)v8d=ldu5T?{KmDK95%>-ImK$Jjem29cC{AfhvrGiLJiG7y z(b68U;hL!X8obe5{;y}#vyU@vZ9dC4O69+&p8xKR4)=fTCLJAtpM4jahPwvStMiZG zitS#()PeSfSOx~CE9jFJ6MR3}(}sH&49E(_WjtuC5ICblN+2*N(74xHoWy6#wgFv< z`QQ$LHS(9p1eQZwhDXMeZg**sRdA;n?z($Ar7U%!XRSNTKKgSqD%1Ue?Pq3fVGz+)z05JsYj3Q_VGE