From 460d877b366e4c27ed9849611cb4678a263f11b9 Mon Sep 17 00:00:00 2001 From: Smorci Date: Thu, 11 Apr 2024 20:49:16 +0100 Subject: [PATCH 01/13] PM-1438 Gpt survey summarizer helm chart --- gpt-survey-summarizer/.helmignore | 23 ++++++ gpt-survey-summarizer/Chart.yaml | 26 ++++++ gpt-survey-summarizer/README.md | 77 ++++++++++++++++++ gpt-survey-summarizer/docs/README.md.gotmpl | 51 ++++++++++++ gpt-survey-summarizer/templates/_helpers.tpl | 62 ++++++++++++++ .../templates/deployment.yaml | 64 +++++++++++++++ gpt-survey-summarizer/templates/hpa.yaml | 32 ++++++++ gpt-survey-summarizer/values.yaml | 81 +++++++++++++++++++ 8 files changed, 416 insertions(+) create mode 100644 gpt-survey-summarizer/.helmignore create mode 100644 gpt-survey-summarizer/Chart.yaml create mode 100644 gpt-survey-summarizer/README.md create mode 100644 gpt-survey-summarizer/docs/README.md.gotmpl create mode 100644 gpt-survey-summarizer/templates/_helpers.tpl create mode 100644 gpt-survey-summarizer/templates/deployment.yaml create mode 100644 gpt-survey-summarizer/templates/hpa.yaml create mode 100644 gpt-survey-summarizer/values.yaml diff --git a/gpt-survey-summarizer/.helmignore b/gpt-survey-summarizer/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/gpt-survey-summarizer/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/gpt-survey-summarizer/Chart.yaml b/gpt-survey-summarizer/Chart.yaml new file mode 100644 index 00000000..81a3ee60 --- /dev/null +++ b/gpt-survey-summarizer/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +name: gpt-survey-summarizer +description: A helm chart for the gptSuverySummarizer +home: "https://github.com/MinaFoundation/gpt-survey-summarizer" +sources: ["https://github.com/MinaFoundation/gpt-survey-summarizer"] +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application +maintainers: + - email: marton.szekely@minaprotocol.com + name: Marton Szekely +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/gpt-survey-summarizer/README.md b/gpt-survey-summarizer/README.md new file mode 100644 index 00000000..dbc1b524 --- /dev/null +++ b/gpt-survey-summarizer/README.md @@ -0,0 +1,77 @@ +# gpt-survey-summarizer + +![Version: 0.1.0](https://img.shields.io/badge/Version-0.1.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.16.0](https://img.shields.io/badge/AppVersion-1.16.0-informational?style=flat-square) + +A helm chart for the gptSuverySummarizer + +**Homepage:** + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| Marton Szekely | | | + +## Source Code + +* + +## Prerequisites + +Before using this Helm chart, you should have the following prerequisites: + +- Access to Kubernetes cluster (If needed contact your friendly neighbourhood DevOps engineer) +- Helm >= v3.14.3 +- (**Optional**) helmfile >= v0.162.0 to install this chart + +## Installation + +> Note: **examples** can be found in the repository + +To install this Helm chart, the easiest is to create a helmfile.yaml with needed values and run: + +``` +helmfile template +helmfile apply +``` + +Or use helmfile only to generate resources and apply them with kubectl like so: + +``` +helmfile template | kubectl -f - +``` + +Verify that the chart is deployed successfully: + +> Note: `kubectl` is a better suited tool for this + +``` +helmfile status +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | Affinity rules | +| autoscaling.enabled | bool | `false` | Toggle for autoscaling | +| autoscaling.maxReplicas | int | `100` | Maximum replicat to be present | +| autoscaling.minReplicas | int | `1` | Minimum replicas to be present | +| autoscaling.targetCPUUtilizationPercentage | int | `80` | CPU Utilization threshold | +| backend.envVars | object | `{}` | Environment variables for the application | +| fullnameOverride | string | `""` | The full release name override | +| image.pullPolicy | string | `"IfNotPresent"` | The pullPolicy used when pulling the image | +| image.repository | string | `"673156464838.dkr.ecr.us-west-2.amazonaws.com/gpt-survey-summarizer"` | The repository of the image | +| image.tag | string | `"0.1.0-b66ffbd"` | The tag of the iamge. Overrides the image tag whose default is the chart appVersion. | +| imagePullSecrets | list | `[]` | The secrets used to pull the image | +| nameOverride | string | `""` | The release name override | +| nodeSelector | object | `{}` | Node selector labels | +| podAnnotations | object | `{}` | Annotations to add to the pods | +| podSecurityContext | object | `{}` | SecurityContext used for the pod | +| replicaCount | int | `1` | The number of pods to be deployed | +| resources | object | `{}` | Resource limitations for the pods | +| securityContext | object | `{}` | | +| tolerations | list | `[]` | Tolerations | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/gpt-survey-summarizer/docs/README.md.gotmpl b/gpt-survey-summarizer/docs/README.md.gotmpl new file mode 100644 index 00000000..269daeba --- /dev/null +++ b/gpt-survey-summarizer/docs/README.md.gotmpl @@ -0,0 +1,51 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +## Prerequisites + +Before using this Helm chart, you should have the following prerequisites: + +- Access to Kubernetes cluster (If needed contact your friendly neighbourhood DevOps engineer) +- Helm >= v3.14.3 +- (**Optional**) helmfile >= v0.162.0 to install this chart + +## Installation + +> Note: **examples** can be found in the repository + +To install this Helm chart, the easiest is to create a helmfile.yaml with needed values and run: + +``` +helmfile template +helmfile apply +``` + +Or use helmfile only to generate resources and apply them with kubectl like so: + +``` +helmfile template | kubectl -f - +``` + +Verify that the chart is deployed successfully: + +> Note: `kubectl` is a better suited tool for this + +``` +helmfile status +``` + +{{ template "chart.valuesSection" . }} + +{{ template "helm-docs.versionFooter" . }} diff --git a/gpt-survey-summarizer/templates/_helpers.tpl b/gpt-survey-summarizer/templates/_helpers.tpl new file mode 100644 index 00000000..02260232 --- /dev/null +++ b/gpt-survey-summarizer/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "gpt-survey-summarizer.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "gpt-survey-summarizer.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gpt-survey-summarizer.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "gpt-survey-summarizer.labels" -}} +helm.sh/chart: {{ include "gpt-survey-summarizer.chart" . }} +{{ include "gpt-survey-summarizer.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "gpt-survey-summarizer.selectorLabels" -}} +app.kubernetes.io/name: {{ include "gpt-survey-summarizer.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "gpt-survey-summarizer.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "gpt-survey-summarizer.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/gpt-survey-summarizer/templates/deployment.yaml b/gpt-survey-summarizer/templates/deployment.yaml new file mode 100644 index 00000000..f597405d --- /dev/null +++ b/gpt-survey-summarizer/templates/deployment.yaml @@ -0,0 +1,64 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "gpt-survey-summarizer.fullname" . }} + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: backend + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- if .Values.envVars }} + {{- toYaml .Values.envVars | nindent 12 }} + {{- end }} + {{- with .Values.ports }} + ports: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/gpt-survey-summarizer/templates/hpa.yaml b/gpt-survey-summarizer/templates/hpa.yaml new file mode 100644 index 00000000..15828e21 --- /dev/null +++ b/gpt-survey-summarizer/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "gpt-survey-summarizer.fullname" . }} + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "gpt-survey-summarizer.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml new file mode 100644 index 00000000..18033d2a --- /dev/null +++ b/gpt-survey-summarizer/values.yaml @@ -0,0 +1,81 @@ +# Default values for gpt-survey-summarizer. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# -- The number of pods to be deployed +replicaCount: 1 + +image: + # image.repository -- The repository of the image + repository: 673156464838.dkr.ecr.us-west-2.amazonaws.com/gpt-survey-summarizer + # image.pullPolicy -- The pullPolicy used when pulling the image + pullPolicy: IfNotPresent + # image.tag -- The tag of the iamge. Overrides the image tag whose default is the chart appVersion. + tag: "0.1.0-b66ffbd" + +# -- The secrets used to pull the image +imagePullSecrets: [] +# -- The release name override +nameOverride: "" +# -- The full release name override +fullnameOverride: "" + +# -- Annotations to add to the pods +podAnnotations: {} + +# -- SecurityContext used for the pod +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +backend: + # -- Environment variables for the application + envVars: {} + # - name: FOO + # value: FOO + # - name: BAR + # valueFrom: + # secretKeyRef: + # name: mySecret + # key: bar offline: + +# -- Resource limitations for the pods +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + # -- Toggle for autoscaling + enabled: false + # -- Minimum replicas to be present + minReplicas: 1 + # -- Maximum replicat to be present + maxReplicas: 100 + # -- CPU Utilization threshold + targetCPUUtilizationPercentage: 80 + # -- Memory Utilization threshold + # targetMemoryUtilizationPercentage: 80 + +# -- Node selector labels +nodeSelector: {} + +# -- Tolerations +tolerations: [] + +# -- Affinity rules +affinity: {} From 358c471610771f12d5544f6121e0e85936e5d179 Mon Sep 17 00:00:00 2001 From: Smorci Date: Thu, 18 Apr 2024 13:07:50 +0100 Subject: [PATCH 02/13] PM-1438 Redis as chart dep and move doc template --- .../docs/README.md.gotmpl | 0 gpt-survey-summarizer/Chart.lock | 6 ++++++ gpt-survey-summarizer/Chart.yaml | 4 ++++ gpt-survey-summarizer/charts/redis-19.1.0.tgz | Bin 0 -> 88257 bytes 4 files changed, 10 insertions(+) rename {gpt-survey-summarizer => .github}/docs/README.md.gotmpl (100%) create mode 100644 gpt-survey-summarizer/Chart.lock create mode 100644 gpt-survey-summarizer/charts/redis-19.1.0.tgz diff --git a/gpt-survey-summarizer/docs/README.md.gotmpl b/.github/docs/README.md.gotmpl similarity index 100% rename from gpt-survey-summarizer/docs/README.md.gotmpl rename to .github/docs/README.md.gotmpl diff --git a/gpt-survey-summarizer/Chart.lock b/gpt-survey-summarizer/Chart.lock new file mode 100644 index 00000000..4b91b3a4 --- /dev/null +++ b/gpt-survey-summarizer/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: redis + repository: https://charts.bitnami.com/bitnami + version: 19.1.0 +digest: sha256:b2ddb067b6e67858251f669ac0bc8dc4d443bda71306779b5462bd3aaa5c917d +generated: "2024-04-17T11:00:40.052246745+01:00" diff --git a/gpt-survey-summarizer/Chart.yaml b/gpt-survey-summarizer/Chart.yaml index 81a3ee60..5b987159 100644 --- a/gpt-survey-summarizer/Chart.yaml +++ b/gpt-survey-summarizer/Chart.yaml @@ -15,6 +15,10 @@ type: application maintainers: - email: marton.szekely@minaprotocol.com name: Marton Szekely +dependencies: + - name: redis + version: "19.1.0" + repository: "https://charts.bitnami.com/bitnami" # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) diff --git a/gpt-survey-summarizer/charts/redis-19.1.0.tgz b/gpt-survey-summarizer/charts/redis-19.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..d58c52c17301fd08dd62b2e63040528c9d600e3c GIT binary patch literal 88257 zcmV)xK$E{8iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMZ{TiiI(KRQ42SLp3zH?UvaG~_nZyV>tyfJ}HMTn><#chBrR ziLlk(THKb`l7Ze#{`d3fYRQ%_eSusS-hC%v%T=XPsZ^3mA7v=QbZc({GuEHMY5d(C z{0s(z!HZ|l#J_{Vp#1O7_RHtrZ9jW4c=qzev*+8-zZ-1tJlz?52L^W`O!+6L3})XA zmgZHi+*k4glY}tHFiGfe4S*0bG$z?>2=*a^myn`00Pqx!5gmd*)&Kw?012F;A-Kvf zQOIKPOqCgeh=f-t>tnKYiCF@tcuN%7&? zZac)bUpUl+S+|iAg@!NtJN;)isUND80(6^_jG?R(NmF{b-GBale_#`T<{?f|!f=9G ztL~Pr3jT5pfEb4;p}e(rQy5NAu+tx`!4&_3GKxtu1lK!jFip*$g2-BgQj|m}2{EF> zH7#98rc;uv0g$1TP|So~kPr{IwlXxvlx4GEyI+wrIIVsP~O0ic+y{+5U#EXV<{bOX*KjiGF`(VuaW1?7Nq>!Ey`ec zMP<`&;ptd6GJhQG>EL_X9zug@hps9eE%YPiFTen-+uZ1%k9x1 zd>+1dIeHmBdp;P1JC|X&Hbx1`AVbj*^mYb2&w|0zVDSCL_VeNM7sF?R{@~fp_F!lG z`Ty5@@G;Flvj2-wgx=Kzpt1k&ynONO>9cbGfBtg&q5t2<&m*u$(piSb6Xr$}^3T&ej?Yn;Ax33n z$VdjqXfKA8S5K-)5K-j&4i&G0w3Ds*)@JE`u0I4+ycX`9iU>FXFw3BaqAjncc5Xi# zkqn%2hfW#S)-NQ^r)ZsSR7nYE(oZ3!JXF=hL_GiJ42}N^%&T?XuoQfNIh&Y|K5(*Y zlHO3yJ+-cepx0Xi;L#&+&>#2ZZ)JrHt6w@;;XCcZSnWm88OB`c112BTAnokSG{hVK-EI|xWkj9XWNH(QffYAO@l5eGV zlA?r8@QA76;vb?P4%HO0(lQRKzA4`qE38g{~Im8VC%ozdeFiqnb zz`7O;afvwJggcWk&MD)akrt9~Y;ygF2&|_l6P)>{Me_g{-@qB&*aQ)#+?hmRJtEwx z0sTQyc*C@l`o-4{QdY;q?uod}^`Ewbxymn*n%aXC?K&+JRB;*q$|@>sxgf%QhWYqh zOoe&trZ8g|#__Ch$}&vs3n$Yb<#Eh^FyKBH@exJ@0$`GmJPEnk zWGIbsC{)k~ha)h8F%MTbSN**VRxY_1l*HFE?0^Y4JmqT5kctfoNRo(xOT=yv zN-Bu!dojgLum$00%>A<>R(0*$HRqDtBok5p1Kzy z0{?cXR*h+lP};;3W@8F=`F|GS#=q9Aa5BOPW;18}u|m1SY9ud4q95f_fL&AsTKrvx zM#Z}0B)`-v2qBqnW$s$x7K3BDW!b7A(l_z#Z)%hug0q944$m*n{_*~J_vqmF3SVC= zt!e4C4Tsw4$@$^MiJ~Wk@lw?vO9frwRFP$HTrJKYuH)%6XTmsnYRC5%0v@#^mmZ2+H-Oz^p@+7OdRGXR#llHayDP zJ$ijg$MokZ3h`(LU@=LMYLKt@rL~Ao_GDMYeNVV%i?+rTJc%Jgls(x5D5gA=7BTXZ z!_hHerx~IsVNWDEr(0Z^akP)gRzyO&6_O-GDHFe_KD;IOUQ548Wx-S<^ zHv~3M$?`<(wTR)4>bj~KA|GzcQzJFk(oH(eDdX;O3X@#W2r~qE0If{Y1W)~L6=aZJ ziQ36YdytYSFm>JHHIbDI(hOfih63I8TarHNkJZqSE;12JD|0|=lq!r*l@?F5`>%11 zG8i+<5ORXxu6i`>q7=1uloWKl*JQ9a-I)O<(MHvp&?k4wFd~!;W8UCwl8;;U$G3APvJq28- ze$L$mOn`o?7oJ35Zuf``i4{Z`OAiH(Pc9CI;8z}NWA=o~QAy0~GjxqfURf9_EQxzp zJWhz*;gxOV2-l?or;6^+Xa@A};0n#S5=9`-GK_d6Kg!6oTs^xAN)nJKF``;(msd%4 zOXamP`Kypqq|3al5O2MyARpq%_80xg1h`me#7A3Idf$k@TZ`jvM_=+VAgrF~oJUvh`pTiP4A= zVN#O75lkyCNUm67vc*V>Lp=r+^J$0m5d0DFI_RFhd-A%LP^uS9L-YuyDN49=ie~}W z36HeJBmM-;j8jqhF~<)eu$v>L;uckhA6iZEW;pIo{eJml_zWnw*8{mHP~y? zloCxUtQrv2*r1WYvA~j7P{OE*teR<3wQf@J!TL2@a%-w*tFPa_ zJAbqPqy5+J+qeF9le2NNIH;G4P3U1(0oHShMtLk3grpBu9YcoN8|7KL2_9XRVp86~ zPrUEUOia>iI7ydqjPxx4BZ^T#CnS#}-p)Arms|-K zt}`Xk6WTatRQY+L7$sYpp@Ul#?oGLU+C8r@$}CSnnqiWOg-8Z7;h-u#$;2xK#ae~j zvJAeC;n?XDu)-e1I6+_}3VM5Qd7@De*7J-2^nzdtZ>MNVvRNQ!#^9R7kl`2wjKw{> zBoCm2OBi0oWE@cZ9|X1sJI|(2F|npp zGEe07$%%dhsDKaID5C&j6*mjPN+Rj=XL)ZDv)dB+A}VohP+R zsi>wRkb1r{X=;MjVxW><;GeP@Zn=+fo;so<(d>_SdcCMDu59Kou@rPz{ovYOTw3RfEWJsimo{GN~ zr^e*Uye3y(`k$NLNbXj&ZC}hqljdQFC@pB7%Li>V#a@2#Oxk*7`5pjIV-3O1KyLTj z+8%=E;-RZF{j@Bmj2i(ct3;NsR9RcK*Djrxa~h^gcs|Q?zHKMoYMXP?>tLO8QtW7- zb5iYSp;f9PVc&XKvQZUEeJLht{H@nU-M4cZX^HfFR_cD-fqbi-&P}m{rOr*Wqpi+O zx1+Us=!*Rn`{|w8>-H+_RnDKz?J<2%PN|%6UZflr`Dk)$RL;>zVk%xGCek5l*}ipL zw&Lsh@p%|KmFNE zn7}a#LNZNrvHzpaqgVl=-||&CvH8WoIkM;7<}H9>NU})f2$4i52Jsmt|7;zWHcJwc zpiPj#glvK-4l}X|=oH5BCYYiK=hICP!)%N;!L9mtNB*+W2Nx4etp#j=M-^e!8ZlV+ zy|8wSMK?_|66Io7MxUkeqqp17 z3!mUr4_u)XZ$PAj4u_8>aaX>=b`Xo7@maq5 z%vN2|tBT3jDT%nANJ&JW)KsgLyh;V#o4{m@RAvIVB(dc&qYO>KSmcU^qJ+**=ti8*Xvkt|npa$- zF;JV0RISK~oLEsxra+Bg=wIvd5YN*zMsf{W)Pa@-mve0)zBfjySBIeF)%2690qJyF zvx-(BTQ{nEls^PA{Xq`bQh#clhY#Q7Dw|h|6z>j$?Xuk$iyL3E@f(WscL96hq)SJr zWku0joaDDBYJKK6nIO5D>soDsqnW~;uRi?IkZPBVOsV>CtwG=#BSus@^#Gmz?Bc18e_FP#LBltk-v z1EiXO*NfEG8o}r!iDz8u*M(Pd#%Z5B;oph9O^|VY6%K7qOAdK(cbXASpwDJ0T153O znYkngVG70h2#jby%E&?%XA=?IY#B)_ORpW>t=qX(fB=e)WSl3k488nNnW06t&dBT~ zF~2Q1ve|mp$4+>w4Z&HS@ade&N)fMYwdlfJHAC=QZ};uno_Am13MY}s(neV9VC|cH z)lG2DAVZ@(=1sJ&CN3L1Al!#&N|JNbai}oU4HGAd6r_yAG0Md0e8Gkywxyeqi#4{j^-KUU^K-E=AQ;CpWYhxrg_Y88l%8)rKT2+ zfOT6Bc^W~6&RGT-8qZ{>tjcUD2~bs5n1UiHa%24zxt?({ekY!;yu}_#Zh;aC7rP*? z80P4eesCd$mthG^z@hRm=w!jkXsB$5Rx0HmvR|y1}@Qv&jPQoU?7t+(Jk8qQ7)3d@`B|W z03|jv>FV$ThDHy4g}y zkLNVeGJ6Hq>PKY8@7 zMj(~%i|lA~vIfSnK2hl&(^!6hsGS9I*#ad}U_>g$2VadEx(wITNS+u`Yi*|_0#H3t z3u%3DSgd+|&|O`X`Jk4)e5uJ~#AH(P1ZL5PIU8LKb-cOJH5SW4TaZ#bPJ~Vp5}~a} zVmdGW*75`}i2|4~Y@XOQ;ncOxiwWal*rynq?zg9%N~MQ@ODRP=CJ_Rq>M0f6h3x#l z6(RYI}u2iM}1Rwxt2L2BPof=cy^xh z=zotSe8z(lMuB_+>_@fLS-dvIRE%qd|0mEQ1yo4DBM&Ws+NmobJZiXz2I@UF+juNW29rlmUf%>&p zrSn>}XL=ANRG71RS5cl3XbAS?3czceQPX3s*EOl*36(4FqC#Er*zc`gQW#?dYW=#B zgqlP|?=IVEsLy)kf-(*d)D~ZmA(EoRQk3FX;~ru>Lg6fo(HlapWH;ggd&2_ZI^7WY zwtNx_87dumP*Zf00XS02C>blZWn6Z3LWw;iiO55JhdSk+Qj94R$3BX@=WF#%eKq82 zvKGf?)R@RC%ZMrZA`+<&yJ^=Wocz8{LW(04ifrj9vU#iL_Uua?9ct8zl_sqzSFCeJ z@=TpxP4r5L4f9&OFTFao4)B^yHdP?i$-ChbX?)g0_%imxeZ)Vi@f~ihNy3cwq_`feLSI)C!63&5c2<`a6&+D zg5sEf8t9tT0+*R z_o=P&3St=8iy@v;J20>Ac{GY6b8En9My>^_g-W&&&fb?@s_IFrs7?t2zHcGToyKV?(SP?-a6$IH@Oo;ay1*HQ~8f%|sD^%-;k> z_t4Db)Zty_bWxF7Q$}cT+K3A>1X~egu!HLI%TrwgnqNjZ6A|}JuWqTz@Ts6!vt6VL zH~|s5wvV?s@+uKJHnl8#aGPeFyf_ylBh@@q2xzKCtE-JIC1>1GQX7%4+PBne5DL^m zMeT3|A~eDYiZ&foJGt=wH~Z1wt#8y;M=$94KI`>1!OaAR6MYnqf@mhdUqQ+{CdDMd z$=IToCrS#iZlxKD-8#i8$>VqvB&5PlL=9?5U=xHBLQEQt&Q>%`6*#+Aa23U`MZ-|! znjQ%kR#mWkD}W%JhP1xY8=C<*LooU^!wj7yVF$k^Jc_4H@qbX+l?=i6Kj98_u@};< z!)`Ja6qc6OxjIjO*>kE@S@Uk;sOI@qX4V3Lhfi#83ACw6FDzJ0VuQRU)|NbMbbKJA zG`$2+tQd*!)XqflRGiQrg6S-PY3ekByNJ*tGWVM2G9y-{;hz4or?BY7W1DnQxEpbE z?wXIQVxt@uXVf?!*-bTAi^ga%pe2)1)&};q=er6;4Z#`WgRyz6q_v)V)7sSpssi@H`_l)n;zfs#b;ss8QhU@#a2Pj_Cvc=>m`>ZTH<>es~x zy7K5&Vjf;(a5TbU6&9_ea$O!U`9YD3+({`azej`@f#@z0N2tj25&k^TYy$2PgG(60 zBt)421{0Dfq@*y$d_E{godBn<=l0ah7+|YbGAPukk_?1pi3!tf${S@pA=y-nH#rZm z4PfU7weavkF4%391X4sz!f>qs8j7-Ovl!?~w^_it8T4$t-0l9(4i8kvLfM(hvB^c? zyRl094wN_wH(<+FhqsCy+b7gsq(LQ$5HPMr=IrS&+q(ugy&sk3HFA1OU<7o@g5Qcf zgw~VW6`XL>5p=$a$*EUkg~aSjLM#@ZoeyUp-dcn{fOVqQMK?hhlRN?%?qsDVrCcVj zLz^yIrb#|^$Vl}JCSz}slwU#Wu#4uhl>0M@EkcDsDp!TFV1zSt1LJt>k;WPi6qymp z9Bt^m2WzHaHk<3J>TEx65BlQjj&nqLdfKK#yr`_BH;;;}QvpnB?7%;lAsPUp$;tMe5pQy9YrmFJp zw{oW68UT&Fcr~PeZkDUN-&mTls4~qH7geaQl9?qcu9~)qlzdobSwKmtFlAM;5^^-p&d*|_in{x>rqaTm@ugI)pCJ=5j~vpQZU5| zgw=7fozkv5C~od$OqXGk_ktU+R+nz@~jFz zv0b1V07XkEG3Pu|X=-W@M~u;WBCUdM&iaxNMp*{aRPJN95)@~_4oZ~7Lq-Z}0tved zIkAj=>a40)7nLn8mPRZxwc8>56BD|oA|I?keyk4N3t~_D8|}XseNwA*LHJ3Zr)i?R zA_Ph=?ZqJ|z2ug`p!5=47KGAE^lnfnn-SBty@+Y*>9P=iJ3HP=FN{Ok!9wo_iqcPg z2`oxK!KJ_`{Un!0qx6&g*5N3NiR;36lpT!qt{^FE=r4mwSwnI;P|6yj%cD}(5dQXI zDNR&$&$yH>-+Kk7bXk86WJ=T1zZh)F!v4PoaLS6b2A$IT<|~D#tk&fLpYkilr!)&_ za{*KuSJ45YvVp@2Fe)3UuK=X7iTdIwmF*fS1FG5jegLYxyI!yeQl-5Q)(xw&mD_5; zDqGprqE&XPS`A)hH?Garz6fMxH@-EPm2+_Rp;or?u7$0fv%lBTnNt&YieuTq%3Faf zyR}CHlx3?Btyq@bM0h~6TmhP;SxuZ564D7r<{41#2ozFRqy-hyh}{VnvWDmbFk}rd zq}JD$fecw}R5w6Fmcr^Kz#**=^GHm(x%yOu?RzGU1@dQr`vqP*k}516Kt|wCe>&Pd zJbu4-a(uCSczkdsZv6k#pB4cY>~bWHM8VWZDEGN7%k#)zTmR35j;Yz#z+*b?{AB}V zT87jCA#(voylRY0OW=+mnRh4j0x+3o47_`s%!NnIJ4ed2+i*^(Ow;kdN;Jr3tW3wW z7X-`vy7kkJmigtvWNOVXiIcfh1A-Qy%mx`dBW2bJXtVc2Wj1i16DzYthC2nzEc32K z%XFiF&y1H@>vBJAx-V-HGwWM#S;$PAau>|Z6)ARQsF_;+j5Z$4u!KxBXuyGEjoGt;%x1^3xiLVRX_iv?*V^ub@-Dl zI{g{}D9z^eT_I3bbLhHbQ10f8=xkdr03|F6)J5`Ek?N^_IlHoom=^P{gZt11eSAcw zv#RzHPVh9J7Cl+3N9^<$A33Yx#rOI=cnd>#TQG#T^D`{IAA;>J92v~Ui0z%e1E(kp zQNrL@Oq2N&wKmHgx11@~a5Xd<#;GdLBY6zgWvd>}$N5MdQ`O5J%R`=)9K`)$p4Kq_ z>OfCx>hXYj+KPHwr@8xwJv~PW!wHHTVNchnD&+#7>ZcB{nvb^2l8-GaQ|0jJ^yKVf z_xNHccLqhkp+Pr!{S?}nME7!|D{&-Wl2LYV63H!Q#o9nBw>U0|n(Ik?HBQ;cDW-`g zBceQzJbDCvlpqA&N{Wp>aE&r*);}Gqo#dDOh=f-t6F>)J z&(IiCmd(I#%4mn+?BJ)v^NX{8h=VM@H;AXdZKlsvCAQ>j4yPyQhZiS`M@i^rmYSS> z{Hw&1!Epl#{&pQtr#X{`0mpI~*utFHXsS_!$B4292C4v->!deu2IvItJby8Su;1_Z z!D);jMcmgSX{e@uY|8m2+myDe;Y(!D1;^zqk(nk>cq^7JrNr2rHDgcq7fb*YxTR!N)L*r{2@A9(=&dQU zC8hVMl%bn5E&bJuv%EekGbqjQH58yY(loYw8-|wEI`Z<3Gn&Z)>b#(%I{m3N zrB^oVSZlEZ$e;QS=os@~c1`_Lpq$w~2)0w$r z%R}kkImz;AA{+LJEg0=<>+nt)NEG$zp#Hnk&vpGiWz5e*UlKEdWz$T*!3hY(p~RaB%B1g& zA!TOHh^YvZ^=t!00D>_gQ8B5sqktQdJYhQV6o;bYj3ACVFRlZuDkVXaU`z=}Gjxp- zff6(W3A!37%k2xIpchPg_yn84Phn{&6mZ4 z8;GrRSksP>Pv0b2u#OXxjOj_ev_oV`bi>rCRz4ft+Yn%QDqCBwigKsmueMjq2FFj} zPa(#G`D6^BEo(v|G2i0^{G_!8G%=fKin0;Orjn{KD3Q#rzA)+DKH-Mo#b6-Tv`P$y zVEcRZ#v={?GmcSwK1)Js-9cc2ePQovRg?F3HSmZbOn<(okH3$?5Y zwccl__kvpQt;&jE>phifhpqPtv?|>Cc8O|m>usr416*H6aZ%*@I(lCKbiM7lZR~pe zyc>MIzwLbR^=3^B?0oAG_C~b}V%YoqP9y0Rf!O(EXC&>{n#6FY2bb3j^ABvDv#qw69~Z z45WP>&E+ud>!>adYF|hBTST?5vEKWJwJ$NgS6urN?|TEbx6ievpXXd_F%e$mU@LX} zRLj9uuzqmMEm$HmZ*ddn%he{vh`kHG6&!4^(7q{*W6z+2W#K`B^{XG>6Ibv{JUPD(oGSau2Jb? z@vRq`bd#syB9nG0T5mGxCd0!`CM&qf#9E(k!*QgQR=Gph!MP2^LUChF#2T-ldDbsY-Wxn7l+y|XR0G8T zwb!74TACHfJUSPC6QuG`2WN)>Wc-&RXSlEa-4nC-{{yypOsC~ld&(BeGQb|2K-r z;?vAM1CCTg@FI>>8l(&2NGm6ybahfe?fXpixdrV+v9e5=O&#W$m~X3M>&Uaaqp{I0 zVW`jGCP-oq6t``aG0|*UbiC9ie?4YOMO|M!W=dn_2t6w@D4!kq4mqbns<^g)KK?F|3xr|d6D8QCq)cHr8MBFxtojf_T%TvfQ z;Z!xur7T*`{SdQPtDmUisxp@F zBnh&Qto=F>6Cn|m34Lw?u^=jL`7!ZrNHXpMU3$VjPWY@#38WK5l$$JI7#tvVDi%zT zIDkQtzLY=$omj;LaZWE~w$SnWLf8 z47!h;@yW#h8OZoJ%Ntirl==J-#<498^$Q|Nw~8a?5{HSBBZ|}t6jo2NT%8%>!a3&U zJtU+ES%-vtS81f~Eg9k|Z-q*+=-kRDvF_WDR~R{YCC*z}A|o*xa>5Bi8W3a-+6T9M zmPnoJaa;!Cb~nz&_Zq01Wl1&!hl#&LaV4AQCFkG>uNU&PlFKWNo`yXrw<}txSq~O% zRYo4#v{RcNbZJu6DUZ*O3O#|hr3@`|7GJNd2>(XJm~3DjXcsQ0B(fQulBkjnHU~3t zHA_`~72eb^Rd1(=PkU&2+1Zs_6w5HvOQkpZmX7xnVzIo1O(iyH6yrya*3vR7H`1%T)(c)1 zI-0?>s)*eOzwVwLA0GcS^i)aYaitjwHO@;3*?F5!Zeu8ri}D0sLmW$#pG3TVZeE*B zQiWqz1!<_(q7<`Mqa$Kr}t0pQJWy)={mR-WoRinLBScU78oJ@j`53H}H zf`YyrLsimgA-y=@t+NS>aa6psMo^eyu?t)tMSH#C?`pn~8R+c0`A~LQE-}^u=m$JN zHd#PI6h73np(PfxB?~FBGLu^kKBA*?&sqB=5E1Vj4^hZ&VIkJayEXxDT^^cW?*n7>kEQ4Q=4oVF-5S2 zx9_aMChBi?$IM~@%Fsxy_lIuD4AGH%YzaBP=y{fBTtzC%-KXP z_)>7@M3z)_-U&(=Hv?q#2K|Z0yD6gNC*ypSZ2V#2kwTO)JQ8%N-ObErbpmU^3WZlu zcAN&!Lan{YCXr4;o=OwS^>B9ySG*tRZGWct?;o6=9qjF19PIZMa)l!vPAEe#GRqoO z3bl-0;~0sW?G@jMBs?24%`R9=>1Qwmie#ZOVco&Z`tFem!`&5LYmQb3 zs^_aW0bTXcvO!mu#ZJ|2FEi@kcnG%p&%f^vZ17aMt6Kt3eSjNXA>3%yC`!0PyjsSI zzPY$KwN9p}MW9-2A^zFLailWg*Girp+D>N+WSHmQtUL!kXLOBVhXtzCAU*v z5u}ip_Tq>_UUJI-3V8`GiznnIdN*)FMaujA;|V?YR(fGHp$-;$H()}3>Puh=`3Wus zCFCc$G?I{??B@Xz`V6+Z1ddP#YrQKNp&I(jpa|8FTn=tqH4VEg6$CWViLlblkEAI zG5A;uYxNyqeC#|Gmy>c zOyt)6jAl;qfcUDeL05(mY|Sq393A+pIh9_S;>~d=-K=aUb21{0al7i#dI&yTe&-S6)aigpit~0i$gzQ2Kji>vW`b$~S4!VZ38`jts zZ2$!ozTYT7fk!d-j89OOp#IQ(rA@y0L-$Q}lV|Q*>h#T>xo^@)-I4ni9X%YmZ|zeH zpSUlpzWa&$vIt((kxI*UK^+lXis8@NoVgDC z{LzYfyLiyz4L*DT{WW5l%pjArD*wWX0?fBEzqPO>TqIirL!jMNX$i!za1CQ2fcXP5 z#otW7OF=jpfFSn3PeC*r#p7K_s_GI{wSaJoJkp`daa zBvnxwRU#jsEu|RDy*GChC7AdU@rfmEOjtKxK|@JQT!UBJmm zUrzeW=Iw#EHfBo?%*17)og*tUht(_&m)NByyZNZIfkilJ7t2gnn-G$)dd zi)498)F5RkK{w^)-i#E5BYA`&$8=)Q01bW-Ow`7owP@y8i|CzIA0uX4@)WUHH-l;V zO5zBL)3Z2{+t%F7f~o38#e^9I*1*$yI-tt^bGw9WG6X%fR$@JuOCw4)yL<+xI&K9; zn-0Nm#Xk8^09y8bH>Iks%_0zJv*0g>pa;{mXT27A&M^!Hl;IHcbQ4tL!BY}_xv^kM zqNydDT)=9H1d9?y6v!RWToGV%@Mp0o1%Ac4(LDxzmN=aPK1;|YgFTD$eFb_J%XlwCVp=BZYW+y0FucLziNjYa|L?9W zsxf5N!+SndzrUO@M3-utzkuz*pu}gZiSHENF3+~a;P2oER|b!T_)VnAMjDJ{DJ#L+ zsWC#pG#9gwsXVrAvv5r3kJ3x96k}aZZ1SqNe-dYY8MOdHq*(o0cHey}v>;`koO6<7Euux98K}H^AS4#|*aVmuUtQNP$uU;7Yjj=C>L8 zEI>%14{yhiGVmNsagwvrJ){oOl);ZUOfa+Z`l~>}Ph`&HDaxi;f;B$ThfT~mY5OCv zH<6pjTpV)4-@_yVW04}RFiwg~D^*6Nf>#o8A&-rU{MeC7E|)2TYeJV2Duc)x|HT40 zQ^~knf2m8;bwypPRLupiPN~Y(-*T#c`b)X4A1amo(1fgUat_WXD2~DZ z0q+=&F`LZ~s6l8zISmh#MzzjeK{e_G^J8k%^XY)Dq2+I6>Vws&`8n-)j=z-46Jr9ozJuZ>%=-Jsqr^gRy(W z5|`av+nGvvb(Y8sFDR+*tIt%!Sh^6#&;fvF#^H~xe+6XHjxN22u381 z3gFTpLh`~80iuesKZ|H|Q=bZ#=fCL?e83S1@()At?@!29Y6(#XA$2U(de*M} zWZgi_Uw+OnQOIJ^Crn4+FT|$D<*Y~yUBcSZ3A<7JW^LU8p-mAo(PcIoqY z+Wo3aguThzN{O>+;{mHn>l__>>!reLm-YR`+^!&2r0oh*7hYFC*P*5UeuXi#VrGTV z{hc5BP8j{v7e(`cS4YQ1OnmB`)KKS1#g@^N-S`I1=o7BS!VEA4Pek0no@@dXQ*)=_ z6FV}0(lt=F<3@GjcS~Ymh+`cA*BgptuuRK=?Zcd4@Cg*3nFe%59b%=;ATh~e1f(b%k!%W7ahbuw-IBOkBjVxH z&s_i3HKpqbLXpTzn<8!#GV|}6;0WBnEa7D~#HA>LWa%;#@vLpTrjGSz+v`V zeX83&c1ll9k-n*N|MA8aBYR8n*<5On(Wk`}qMHV~2mezl$`a(uY_k4EGv zaTG^*M7^8%8Ja(%nFz0oC*TUrID?0M#drS&KO*UJOAa1=8cxs@_WwmmvPvF&>*)#F)U@$2CyS=@$ zz4P7nvloMBFJC-+zWw~W!S=Jk_OtK6V3k7D{p6Iv?7P9zyvmjPN`5}B0nmFa8@@LL zJpr<{wZ%;!Q073g@s|AcQE!tMXR{RXvU0svK1(w`$1Zl129YhFnVX!KdQeo-SM`Mya8FjcrJD61CLe_O2fU z8B8KF1>1vwN02aNCUfCi^igUO zS0AUv_wtT;x0$+WsHT-beU}Gq-M)#RTLTrK+lr_ZE;V8G6Ma6fNW_=$#9%LmcuIQ? z!B3^$MDc&h$_Fh5Sm_ZHsv#I{Gx`*#Uu zoX1bNO25Vtffi>3Y=@-aDy)|AxhLSbsPbQJ&P&<$T;5B1{W+bNM>I<1E>aw=*O&$oVi3pl zZkot2*4R%~{u;5hu~`gi1H};vLYTRYqmZPl)N2jKI|#VoaPy13=qpl>Nlp?LrhpqAd|L<6B{qla~`fst7c6@SiaNcLPY=u0U z*ME0jzIgt;vi|$@Vg2`Be)it%o?U?B-J^pc`1ld@_a-o7{bM*q;M1oy`SzECv-87~ zW4pjF@-PH1vwM2#E3uoVR-v`O{6(k2Tq2M{hIwdsGr_S;coBQO08?;@xTlN63J!|E zU;eVT_VHr?@CfvOk((3|hU0`#hQlKg6<|W2KCN9CLKDa-p`;*$6Ht5zru<8=8^`Jf zbTEO}NPVF%*nn!kN~b&+n&cW~HyLIOC1MwAxMt@$2x*fr&Z7dOf~B$AVNo$HSdVbX zw9~Dtn&#Y7ncO|_cmwv1KL z=8WXv21+c12wmo5M^sx<{%}Dl83upjy$GDV1{ZG*!0E~U-$4+7OGqbcYljxftlm#h zhHqjgeJ8&Wx1Src$GLC0}=3|j{DbfqLfb<5laKd|6&)i7V z0}8LFcT6I5N;1~#gI#K0C%h>>4#geAl-N`pO*mIeUE@gJxpWO<92NUyB(e6viY(9m z>RYQq$M%RPZq63zK9~w6+-*0}9RmHkFm`J{z}@4w#)Za#(DHc-zgAuv zgd%W_<<(ju94^yvuSAoO?w>yCMXM3vLj|{<{o`|)7A3%5xevt&Z_rHNn4`wsuApfB zuE9*7UWa{4a>Z_+2n_m9pTweih9LKO@vJy%L1l2j-)!;t7+J42!3bxRDHWB+40A$W zvD#FJ`>~BWhm)>4H30sfK3V6uDc5BrDFUd7GJSU!LXw}*lq8*wj&2Yj-p!X-L zPLB5fM1`XNM0;S}-!4}BZPb-<+HRx0%_=Pe*2`Kg1q-g7Zg?uBw^lw=m4cEPR%@i) zR9%&7qsuw_c%$a-zK3heT2)71EBR2{C6>eFwF@F9dP00N-eq~B>L8bv!P&w7;raX1 z-ShKbPtNvVJzlpbiE>z5Yy#%!NT|F|&6x;2Nh9E2lq4x+lUKcu{RlGHcZbkVJ@AJ> z|9kNa1d(ePyoMo35)_J=q^M{q?iDSz-3MoR0-*g;fQst@nOjm$k&FQ3U5`>pS{GTK zET#lm8A%cZL59Sf^3{`Lbd9nnps@u(5TN9`(m?LtoP<;d2;>ATT56`z#WcHqDqfjt2NI)!&H*1QrBd^Oe_AR4V8P`fy%4n12Ybqg z6p@MLDE8hS4(AV73*|LMta2o&_W+`+@4Y>Izx(du&8uFi>-UPjZ<-DSlg@(^2+}#i zVOLPsF>o7-DfcYgcFUa-1Oe|urEbGZ!=k)0@4}ls0%yK}_G?g?746=?){0B7L|mjT zQ3p_WroT!!-7Vt0cNN`>225(xm#hPCfc<&N_yxA$uoOmQi78qV0*Mc|gvCZ#f?#IivbKyqcLt`l*6dIcLqhLaO}+8oatg~68rOzfhn8;2Coo+V1#ZoQoliGu_=SYQ+0^d zEVK1Zmd>w`>Fel(QOUh-@Wh$1UoW~}dehkio;W?}{NU`D!#z)DT3D3s(O6KFQ}-lf zFc~90>PF}m=+0+f<=)51n0G!fPy=sY{v%tT2k*VRGx0)K^9A2uOfRtZ^18WOZ4kUZ z!H8rxFpCzm3VI!Gb+(M|svXYJ3V*&U!`R+=*&p-={q3*AEUIB+hhf>b|Nk&3w+_k+ z&#N8=YI~rrx4wsAdhua;VdMOUhVJGqrZ1&ecn0n!hrIG(dvQzYs_J3qHo5m<{EIXZ z|I&v)jmfl>TsR0PD7-o&;;!clIHt0x*L)eT8n>~Znc{^7*4!bq5G@-=uSRT<9|jqc zUnrqhxMO2S#$?15(T5smx9TSisiNKjldYhsb z%QPYWk^HO3ucnB}^&NHLnjP0Y`XA^2z~K=e>vxYYKeaZyb|L7#EM_-y60Y z2wG(}+h6U%8;`o0TDatvu1+C8Sl3e!efUtk+o-FTzD0U9)pDraNv%r9iKW{O?Bm1D z^{t5_machSbh3~RuIyW1>T2R#`m(hA4zUtk7j`906ymzP8rR|PdTnOuQ(-A!3EC6~Q?9xU zi!;zE*2e{TPgVPy62ZD(Ra|NR(|l~HZUiWrUZZS}OjF3C>c79*?mr6#o8WKT{g=U@ z2l{*VT?#+vmq=0R|Ad*AM$;2hO3*{M3?)JlTi4r{h{5fGr3hn7<&~f~8TYTg7iZV5 z?JtyS=24TpSA;9+w78h~v`$fJrHm%grmF2{i|RzBE$?`)O0Q@QQA-=8&1Y5L@DP@)~SVQg~)_i&F^uMMGJ> zmsdB+=GX@t-a2{C0dWcF7S~cwDBEUL(Tzb&>FpJbBIFkVQUR!}zg)^vamZcIoZy3F=cO-X_(`bUB-hNqKQHm@K~N9-&4QzIuV&y zg9=G>J`Ku`&b#T+-8tx>&c*gwHd+`qsCtfOubiB!H>tiIdN~|h8@Ra!z)F2xxaU|P zne()~`mAHqmyXEI*Y;**d#=W>Vfi(+eoGbRYkq57aFD^(UsISiE-;!>wQa29^gTnb zG3c)UtZNAF;G3^F7&lYFLOYAi1WmOZow*1GRTa!XSJR+5=5VB()6@?1)H55aY$3Zd zuktWoX-eNmzQ(K&SxM7XG{A#;nb?vcmSJ>_BDpu{oU81hB@NF|j{YkM7&TK>&pV6c zLVC5oZ&R^*2(=}Kw7Y>kNnf0impA*5NG4);h~@P$H~}yLT0Ff{u#QInGx?ZqY_1VD zLD>zah(8^x1rA!^=?mJPb{Hcjv{1le^z7d8I7SH=z5?soi*COF{kJF?v&jbd1K@-? z?&C4J{Ff*m6LOWOpm)9913fcwI5sIE;@1svh_^gK2pWzH4}i?`5pVjuN&WzrFP=px zbiVaC|3FlKH%=$;IG@Ve1P!je?5FHQz^Z-gOu5?rcmzo1Pa1I-srxPk;OZkGtPIKG z{cNMGv}Pt1&G}ggu?rSu^?Hl7w~BE{KJ!zH;m1XCPzR`i4f#Q@GJSQ0S4Sw#aY)610A9|JS&|17Sp?XGxR~NN zWD!k~MCb_o{T1NiOK>`zL||IF#u7l*>Ecjx%xY$-A z)**ve=Oh|-YjxLalp8uhHA#%teH)-9 zRtW}Z^E1~oQ^folS`Py8&U*H$cYAw#+uNwLPHDbTP1lscQKzI&5sK9*;+;T_kQu!u z8cXV8`XZZ*O0Xvg*AR80%kec*2AR!f;9+eI7Jky3_TK;BiO$Dn+A(1K;ypqA#q!8F8`^)-#caLDcR&yhxHn*lT!|ksm zMyTB;*(D5Bky2~vv7Ku}fMU8U)feOnC8bZiOTLb;Y?Q9j&tEL2t!m$TNF%}NTMp4>$%ZAP*$8`-*S*Ie5>BAI)!a*bu6 z%1yu~*{)aw>kRa#+s}W+u(uBObk4qWd8wLMglg@(=GN+(*Y4HLQb8SyP6%aOLqq3u zQ@#4lp%-~_?eP_wZGy+wFy^z6I-cH}tfiQbJIcw6UWwm?q=Mrg;NLl6s2+mY`t@^X zxIg?f{glstnBA2A3{F>c0;Ku;$Kd(P!OPP5kLNo(59dGb<%f6F)tmrnNd2+4*u*Kz zwIX462(Gu+u5c0!fh=_d)3qsLFoFyY*8ngsa=DE~vGi(|dxsrQlv;icNOYu{t2X4j zzMO$&Q4g#Gxdt8Pl#%IM@w!;glwZlGcG5KP-0xA^_miKN+_`=6efP^ifcG|#DuWIJ zDqpV~t=N$sfp{e`C3Nx^!D=>eN+M z>L7`D5bmqZ8c-pmtB43^p3}P4^?-em6=pcNYEwaJyV@+)tJRyA@Vtui3#;zl*;9C4 zc3~OxbSs~UR5b%UtB&r2Uaw9PUyJ$_y;j8MO--uHbZt{rzC)wh+*jMGe#%QWt0vmH zU0Xg_NyB=zUG=km1Xc62(*C_IHciznA$2hI=GfV38M#w@Xa1h5djNejbV47S2fHdr zNQ8nxzjOHsf>DepUEQStbKwkCi~c(&Sw5|3Dk3*Y07ndE!4$_arYI!bV7h3oQh*cN z<+P4$Qe~DSh+}e%vVh?!BDue%TX|_J7m7%kOA0d>$0!cyED0B^kEU@hNYrJ~H7uBz zJ$G7M(120Gf(*&t6UbYe+Qsu;^(4^A1N~Q;(}~I=m59xKI`Ma8*LxPSwYpEI_pa7| z){tH}pzzmft%{_&y@%hu|gNOOwef+F){^yS6 z!jksoPSdAPYw}8-`R^#KfM7f=0>%GTGU@_7}rf z4c>o>GJ(}#M_1e)fCFT(tY|huK_6@^75O=JYrdk_KTq!3a*Zo)G({nANH$B+5E$IO zHJ~xm4^M~Sm?Ws{3^&a$V@xN@Cq#n1Px=gvMEj1}m{5=x6q#d2h{2Y=s zy00l@;Y9nYRe7+_Jy<>bto+9l|HW()taKZ&IsV&z`fO*r6#u<=_Wb2T{C6KecN+h7 z-_et1_g@nKeN|g|DNe@kGXx`?AWGlIB!qFFPKtfK|Jl04$(Fp{j6eA8HxP_K3B&gN z>%+GP;P>CbpZ{EQ6=d)6`rknB@kh^hpL!cTLplLfeB3JCdN5tJkw8AKygo+K%0YVQGLK*m{4}qZ+Gl-8;t(1$m=Mu!+q9|~8?Y|YK zuICK11-c=&KmO?+j2e{_Dkpnl(U#i60FCimL*GXoDE#00PvlXjs!aZypGsO$8YxA} zBCNv6So|UJw($u326~VGZx00M-=Md>^Q;Gc|0`ehAWU03&yZeV-3LfpAUmTq6 zpZt2fP(SWAPv%{{nBUcO@{gWF`{mi+m+k~gR`z-Q!TG`Q#o_V6TjLnsAHO^L@!+hB zf9UyW?ClDb^_FuDe$oeL7Zu{#GkCxF`QRU3X*xLtL+P6sNnu8j>0h)DZ>~%a+rsG< z`1tzd-SPhW!_!yWvVL3Kn9Xx>iH?4g zrN$MOigxmdTaq?yFR zy|uI?_8umYr{l`xw)YXvcyEhvCZOSZj|aMAaoX?Y?PIS7;z{pu@zGYz>RXTZj6eQx zzJC0FTR%7QHGD5B``CKnU)H$G`c@WD=BjShjm}lu&%Gdj&p+k;AE~r0n3}`<%kKa+ z@Bh4b`QrJr(*DoO!OMsIzkB&v@%gW@z}RIko>h;F07FhBC<|qIIn-l4Y|^tQyv}#fu{RoXf0go9A5haI1k-BF^z@vJflnSUuC0rx9f6 zoMn)q@ysb%Z&o5}dWw=lZ1uft1xEe>r*R7>zm1#KL$~zObW2LG5fv1fDNaO2*||Db zQ-%l=C|f&EgMml?j^Dm2K*J=kqF`Ji@9ThN3H;KVKXg!}x`O5K`OgYGZig=My*(rA z)+wC%rqd1zM6nEMp`RDh)M0JTeN?nUxl=tWlhI1js#U{|C(iX(0u7Vq(*o!~x&a(s zfpt^Ubv4=SUnm>s{|G5Mg=_+PC5VLHh8T-S8JUXCvjKYCOnTrC-JSjbbOLvtzo5nW zHE%5~;bc0@+>&{dw-y%ANTW_@%`J}lZuRmA(53mskx0@@H(J%lrzG+uKri2Yywn%# zLW_EYJE@nS{2~?8!CFP8x|{X-{&>URt`kDpZj2#CR^_dSoukyI=CzsBq>+E`3hFd$ ztwm};xIIa-y0l5%0{+VI5e70W2H%;gP>HgA39@jbD4zNROBlxD8ca4z{eDzYJI#;)ur%>g&$_X@OOR$)YJ1=;n{%he@QUTO zDBhv$35if=!Fk~p$!&U4Y;`TYxH_%9u*j3pbKLggvSeNLI`$Aw_gqbai?a69mGl&c z&C1+9BQeU#qqX&LC8FC*Rw#KL!n0M6nj$NzRhJ})Q;zabvpE4MtQo;=&28puq&06-#Q9UaFmhD5XXU!g8y%gDlCvOdQeH zyePRYbCmyGMub_YZ!2_mfisNN9337-R{|W}qkF|3PmAV~TnLB;57(5xUIB zEmpMQ9|#JWWTw~I!Rgz>J#m@J`=gWn1HW*k)pDE6?%TH~zrH^>I=%RZ$yRHxVM2PK zH?!v{&UIZiqWg{qcsq^1Xiky7W$HDK5pC9tliBC5k?&$)xok?eN|)4CgsU2Dod7=G zuQM_omRzBnU|KV-S;Mj55F`FwtuT=7^5E zXFbi(HCLj#&zcpjE!{qmv8{HZxU(JFV7X6NqY zXZpB_r7u|)FA z=!(^oTkVoB)EPVW&RZquw*2L7_69DX`2+L!a` zxf)r#MNxoQdFw%vMAMYbf(U1GQAI4=s%r+ArXqc~LUbOMY?{{5XVbLu@%+oD>TJ4o zkLz3t;2)O1;Df?R63-0mt}EYsix$6Fer&;IsKyNCDwDcg-cGAg<(ibTl&zAw0aOu- zaFLNvN(t7~=1)v;zMMNjL4EusZtJ&*_OP#CQq!Gn?3Xy)*Ur9oGx?8_L&75kI`X7u zNAL;w-9=N-KYsYK$Lk?vpoZ2)iG%`u3 z-L|jP)wa3B6<;vS{yOp>I`8t!Cfj{`xZAWr*Wo^~2I>d@dwOzqad7tj*MlG5zdby^ zI5>X4yT5;Sa9+<-AKD!L>AJy<$u;W~FHy?j12}$X2Ys)jNi+2|ShyM+s41D@DTx3I}M(|p&pW6N)HhRVG_#JI1 z*YjKD{&>f%2v>~V1x0AuN&0;Ec^_+ejd(uvF%qiq)sc2j<)Y<=dXe13YvKCy}uPUa_m;-%WUO)+xltZx`KvY zVDo2%O`VnMvp`#Or~Q+srR56LvhCm1C>GmosC+#Cc0-xO-S0Q}Io`pB!;^4 z-(Vdua?UcGjKO+?oV5m=<;gC6M^OegHb4*NjP$Cj0^x+*Bp^5gA8-VM{KHWE`xE#B zggFC21bUzcg3->0g|~oxIpP-IhQ*!w3V9cWJbivdf67RnmTu;sPyCuF>pmLDyYJ)# ztKGSQo?++UE6ul^;gx6sVY&*?65>`lE)?uGk(oQ}Z6J2%0dOntFE14Kg~1P*DW5Ad zr9IfJi(ZOWG)9qUwqZQz5De;_ zk`m_bHmFMsR+tx{C@21^ej;UhG%TznzU4npV2OGP~P)fwiITzR*_mxqZxs)RrFa zc~qOt*=9Ip*j$a#>QUBwZl|R+=q7 z_@s^^eSJQu<5U{mV#;tb-islgcD5Tsfl1pJU%Sm5@<*NKZ zyWdH1mz61~1&ds! zXsXFJWV?!oZs`3mLv|}b(wqUBA4O+&PLc&-tEx1(EXR_eE8YBF`}gR{mTcK&R~ed4 zs558M*wVdM(!E#r$&wd9njLsL-v0>Wi4V7YVXPyEB~+JER^A1gu>k4v_5t zpvo)c1|25>+66C963Wh#a6n(mr`&)@x9}dAV&}Ckm9-n`wlIYs7wJ49lpUSzXLR!i zr-<`I{l zxmwjS^JcIv5Q>g*n0&Oz796b51e=+`zvD`(XMFVpz_OZ`MfDbqi7 zq#}Lb^#5MYF(AtJ|6A|T_W#!#Z}ay*Z@+&1_Idw*jNe1-|E1SC%MC6dA?j8|Tg^z* zYOTQSya=xu_7b~!Rp25Q>8P|LmW)#^XHtlON${j%C2ib_8a(9H({%zOt%X7=OdLDz zv1r7@73;9P+FX1iAK6$qrqMK-@x|g86?YUj2wi;9phf8r9y?C4^$78Z=ilT0O6)&% z(`Gw1;2isJXXnl9oc*`6wfW}R{(FqyL)d?&HAZ=#5Cw*@HfG#FVmoh&u2K@RHL$Uk zkNDi`D37`U?K!ryhzV3IMbJ`iS}$`VMZ)GZ+qY+UHlxOAel8!!vc^_>L)K;;n?>$B z6V=ef?Wg(jl%gMGHSZo1=zk9b7TNj0(259i23DfZ1yWIs!-iBlJCswK_f%_5 zJ=bijBJfhyFEDx>o$0~YPpd{@w``aEIyl7@(?z1iA94+>3&V2{t1vtJ zFOJ{5!qxez700X^`O+?CUcnxnQCmeHowak}pbJq0>Wx#Sba@x^qMmvGM^tiSjK&Wg@0xsIwy)J6uCWvR2kOR3H`2DarbI)mY2=nss&c#Tz(qhe;50oJ9+B z87+o_G^>4U%%y=>^Oi$4jGO6Oj9jKL>jx~W15*tOyPQ|;FK)FzR+y#Q|A(IN$(9TQ z%<=y>-)`*W{QtMxJJ0_Aqx>Gg|97j4fnp_9)3K@x^UJeEF^U5030I6O?&`3@+?avF z-+>7u;?pJj`31Q_&LnV-{HpGp1ZQL-|1p^aZ9}j=F8M0M5%ab7G zl`W#6|K-;=J=$Ucz#RSm=JobQKL5YHx%sUBALI9s`agGXL;iVcM`qtxEEn{ZaR2O4 z-}D?uhd$2D{Fm0m3z74rbZ~j#H#fFIFk<_^%+R}q!mkiQ6VqFu)qMm&o zZW`|L2n-PQiigeGfiH1tdR3Dw$`i$e5sw7B;9~#G5hybWDftfjfxO{j+6u8W z-z=YNRp$Qk_J1g=)8#i7EqMUd_W$O_n~i+^@6P7V#idYkO56Wy{F+C6B%^kKj{Hy}RrQa$CG6-8pL5g2EXqE% zI10xxqE!8LsQ;+sY4MTLp)y`&7i9vAe{0a6?hD5em<@`ic6kg`Z>}%Efa3;!NJV{b zknqxN!T?>LLYb}43Q_7oDo3S1jX93;44b2(KWv~ zDL2>o_^#R1fh297L!+PPFzGGY%P$FAA;Jzs`xH{Dj%9QKrV3>j>>3SYRnCWYhsHL0h+%Gp*J!&Ym)Z{#UklyHAUoRB8d;$GXNp=f*qB;DpOJ6it z!^hDZjR;y|#@o~%jSNxcU_F#2s=+rgMW17X;+K#AMgDbrAO5S~{Q9rAx%l6kjjgTc z_}^pv9w`3D*~oo*k0aP-pAS?L>`RaNIlwedBJLM{pZH_Mp2L7&MHtY*AX6L;ZXpi1 z)hYX#Pb}ln-Mp&gUi5$;KZG!c!g^Lj;^^YeW_|fsW*b{rLH`qfN}(d# ze|fY0tp6Y7_XX>}BI2JYRx2q1Q=Evyao-~`B0@OUZ;dnG6o5AO0Da3(Nfnv785HXr zj4`DRpTw3?>hv2FL*K_-y~DuvJK88Bs6x~D>yfW*@8g4)^KcmY5y4?raZ(y4F(%Be z7n#3~;!D_DGc2N?%)?adSr)*q03w4#7kG+DV$f|po<~Rtj0LEfkdVZAKiYUWj}m8p zCmnZ~O@K#24;D)t4S+EcVvfTxt}BGb-=SCw^Hl`!j2 z`>A*+Qk61EMN9WLh085M^8}@VIN107Md?j__Vd#2^|lvW-u zYXwyA|8KW8H@EWVf4qMF{^N0e53v8&Jkev`IiU^n#*{&ZMoB;sD@z_5fj&ivJaNA4 zQxfCbaxE5r@{h~aG<>C7?x)-twI-ul3}IgQn&VU54knCH4+h*WHCYzuIigN}Q~%v3 zNytj#3+*0_r4cW6HdfnFgBpir8R5HT99h1oL!}{%dwf;M%5j%!Z-Ss7AlgLYt87wD zN)q{yp&^SQLu2)wyZy`=6D#T7`20x?XNtpf1pV0%c_j3y<4 zlTdpKBjTUH5RS!lKjwJ>ju%eME&%1H+iKfLNkQ&D(>5-=m@f_1HP%*z++ zPTTP^nhmrNls31M{0LWbx3z-~Q6#({bz-l_uRiO~T zN?%`x+y5R?bOzZ3bhDnqKJKoGEqoM{sgT??(B*v61)sGne+F~{x3+hveF3*48lMt3 zK`>C6q$ZTfZoQTWOsSz>j3Y)HlcV~zPmjFHzcD$Y+wzO%R!s#Ps0H~c0l(yJ{tb1) zLkz40{2~K0?-jOalIj3Y;TWAIK`<1nPrFrVO2^7h2xWr+LyD{fZTfJzV|!g#N+MwY zRX@9LuucB*xx$x@)NbG&4&P@W!(#KFsUhVcrz51uOCQZAXpzy8LaNYeqRIta3QMPf|E=mSV8r^Uz==U=%^m;!)8rnfG4K{*oa{$$*$D1HO2~ceBQPyKOeyiicdy^kh)4}Jz^pO*O!YZ`@IpVlzWPP&~z<5X~QB=%F(dV_}Jv#%L;gWPsC8x~(t3 zWgOkS=Yju(A?`HP#2d>fOWSk9-LdN8T|Y`+mY2KbzA5)H9EXH5?41xFxz7D4Ws?Ap zkT>%J^p235+^4zeyLR{`hpKF=-kMw8SMMWfjkfg0YUeaPs^d^b+R}4lOhX;s;KPD4 zrL_1m=MX8FjfSEw7b#AY1l2yxc??a7by8$J;(BBK8i(uGkWL<8;b1&o(j3TP;Q-rM zG6AP$QZ3j^t(2f8w@f`RziuRA>(`itaEf)zZ=Et2v!4A|W~9tpVHDox(aK%r`=g7~ z!O79(!QuBGezaNuAZ9`BFmVXunL5V^bVo3ts4MQCu(uE&T_@u?jI>sEu7alN{P5st zczJ$!c6_uyxHx)$dU^8x;LuH6K1^SPb21oS9G+jkdq2FeT9qhmeT?#nJORte{PyI` zfiNMIm5tbBWS#M^ywY>C;<|T7TCQw0>zrLBVfQxrwR`AHU%y_O{{FsCZ@s=TgX&zo z12Tm;ES;;CM)rVI7EfYvvgFzO^NY*V4=3Lro_`U}6yNg9m6{HxmZFQ;9G@g{%~|$qS3mR`j=&8GSfokU%g1->(*eghr?IKA?^XYaQ|SPF{OVJ_dn3= z9F2-^D=q_)9SZ?z^LK-06WT0lW_TqMSxcW?91kxKPY2&0AJ&jkA)rE5 zwH&d4HWX5`$6U&|nysxOnE-K}cR*6>qYNcK-EU&~B) z!J#VZ_ZsuHe^OjxS>3>i*Knl5{0_E zR$oalFB%f>2C+O3M}@nTE19!&b&v5a3K6A_PUnl1z4!Qc{x z{-wS!bTWSoRrB0jD9;h}afwvM*1I;vGKaMVxwL6@3ubOS3rS`UPb;FCgV~B~=3urU zoH>ZCNM{b_(-6;;sJimmV6K-=oW_WXd*^7LwbkRwFFUf%^@J=$dx)2IwS zn?{As%>$p3S3MLnJi;DisIIij@$-)P9$fdo4};k*U~z($4Kw^?=&A+7N7Y|<6tR@v zdQ&Hg^r_Y*ALbI+SDpf^SS$BAMS5dF2VpP?+n9K8n1zou1rVS@j?TC9u|VAV#>L zAbm_PC1ezTntN+WszbP@8pw(z(CcOA6Ygb~klf!dY)^k3gLKs z!!TDll2WD4+;X9@PGN8w-G$F)ZvV_O&R;3J)Lhe3-mIlPtg=BL-_(dk+?aEyuES47NHfo0bS+A9*=Lxs9BD3U~e| z$0eUiuY?HsRL;p6il>-T@ooR^o^^uIZN5R_EFo9!rL;}?ku{5du3BDIi9^ix(~p=- zhpfBN8TD9DL|}s{98oq0Ys)L2gTB!Er=*w7h$D+28KDLj{amP0w(9e(&oVO#C>ze`6H=@b zLWOizKz1~#qbdpyTn|^n`ynP%*N1HC2xW`#EPLHNxs4f`7Q|qgT(^$4R*c4$C8kL-MLtfZ z)m97sUEQpU9_kO(@m5mG6mb3=)9!#eC~71<{1MHrRiDkhoTWxP~st z2?z_+*R>_u#8RPK+dB)yRgHjd`{%J+z?VFYy&@9b{(0+55}xS>=iNAt0Poto8+WWz zpw`NHFXu!)YpEtgeT7=8u9J;EV#;th-VY$2)@Gj+0+YfZdfRL5@kfpeg1TUpMa9p! z%4xE02}50MWC}9}PViEDKh` zFeXd$!fn=1-|LZHplMzece|-pP+bx0Lfp{;Xk;?qB<9Ind2+Xd~VocyvTh-Rbm6(7mXC|k}LU;vJ6z&0167ryh#KAC_bg-CW!O; z{z~jwS9`|FFXwk?&n!A(g-m`+5Y0y%C?l~B%*|8cW!UF!A%)}bjeFu+$y++H)w-sj zzEx=A;6gqWGi-Lup0+*HfgPu>% zw*Y_Lzta1EClPGt_W!x}|G$2_v6;L7cY9~+_4EC|kMaBTaQFYG$4?ipN^SY>U(T!M zoxiDZV;V5&HNfvkjDIH~gTWc`2Z}fpKi>iTXSf4cthM|;DgCOe39I=i3dn4VLdPxB znag2BGdiFowXgs?i7QiOuhKiow4@nrRcH9Ie&?*M>MR3Ca=uE8DiZ(`GrWKHLC;GM zuvvt5!MU<#JGOC~_rJU-$=h(b8*2Z)(EYTg4JBzD+#+r@ePB4izYDgSJ3EEJfszo1 zY-rl(auN(=rXSTNC7HSC__NmHouDa+XA7?1RCIpoOK1=A3$J1cG0uf-&+IO>|J3b@ zZP3xJ;D7tG6ZNS@2WxlDq zt)9)b1XOD7n^Lne^^vjgyG-9*Tj)BqT=uD5tep)#YyJ^cKsD)MB zFNz^AF)91Ht(Nh$ zbLHY>C`u_T>q?O*N*`DkN9P_^;&uX9f&%m2PUow3V))hAYwr=(aT7W{&Ag~*9^)OA zo&K(gh+HS9NKfLda45JbWwkaMW8Y{hmTRT0Lj_ckol>ozSB|%=vsoa}KvsYQdzb`4 zr_}YTU`J6-BZ#v)w8U-(^lBb+$dGZCC*wx9j~$M`)${zq}rKyi{6BgoJrMF|wr4onyk#ntxn z3vz?p@wpt)RsA^)&R|5o-d(}AL0F})Uu6JdZd@Uq#3vPAXhzkOiZZmgWfk;430jHy zn!h>vf9v&jKL7t_Yjf*a|3AjBW&NMZ+BNjFrf-lP1^yMxG3*_kc410IJVxFY(C#`1?m* z|Er@Idg-_8E$jl7`hRod^~T2QeErYP+h_g%D8IJ!zcUE8ug^=ETddRk1dwM9{=gbs zF4qEeU8Vks%mazzVnX7hKAr5UqZ42JH9KrkJm|Y`^b7Dcp?!5CV|kl^jORDHg#q^E ztn@Y7F=Ch84_#dYpVBhS38B0*+Uu@tb~|Pb=w5eatJ_H*@t&8rFy32PMc#yf?#d_K z_y7Ly{&IMD{?pO^p|}qJaz!3q^chg(gDzd~tzWK>yK5G#y_HXY)iCcfG)+r0 zRzxlCsi=upeI8rywh$*uL}7MVCkm*21em}lW-)!N?nt`N_<^gQOTCU2j8XQ@VM5WN zs-ZeK9lB1}urTZyTyx*Iq+c2<$N)x@(FlK(#!9zX#B8U;3t@p=s(%rZ%GIrtpn4cq zKD|2}92_4GhgxRxu%w2nnDKo5Q*wr$(!*y-4|ZQHzK8y(xW(XnlGY-8nl zzyJHU)>t*Jo!Y7zwNX{qoab>&cbN2HN-Zk-MdvX9a8#LX2%mkKVv#@Yw2AR#m8Gh@FwQ>-G`n?EQ&FoygD?tmIxS3V|_G7Z;*v*_=5 zha*$HF>N<@EFd;PstO>I+Tkf!RUw0+K`sjBQ-U1e(|6`VG=L=B-5<>7On@ZH+ZG8J zKXlge!RC@lW#!1r_r1Uhi|bwzQVRMQZ7dQ_80}hjifZ+&ko(cr``+-s-NU-9e?)V< zGuGZ)9exu3E8uLzKzh7kyQP+dq*Q#04@(h6ml2aIdgXO@cYHp!;1~a z_%rMIRUyhtzeQF;aj8{VV@v0xLwR<83>`P(`|NXkowfRiZrFNZh5o|TYC|Hemz+$l zBvp8nG~nM6J27z3-VxlK3phh;cv^UA@O2y_Vg~|pQXPXM7fIR~nFN1$XneJ+MCRk{ zsucLh=fR)J{_tpb?=5|`i}%S69RT@Cr_et(U)<28d0I=}kOX~Pr_voe|&331pm=^u<-j!2p*`C}41#Be&qBIs) zJ)X{TuEWYNE<*vvx`D`RS&vOxl32!P=kZiy&et=;NGj%k6Kd&rhV#47S*w#f?aVF+ z6s$vuV~ej3W0j-0sc@ujWDBnHl(Viwuy+P1+y>sJh>(C1ZFu%M2IT#L01i9T!Xepr zJ1Zqk=CyDqPbgf)XD@+d1&D=MTSkcrwoJ7?G+6=fTMs!|>)ru_ zW^ATpucyDTgKIh@yXRnNDz&C&GcN~99J7-R1sO#R{JP zE9dXg+p1L{z2XF8xFg)C4RW1ya65zByWQ*5yY}(8JAk2J5jA zf4tIZu)FIyJe7W%lPb%UQuVeN@+8ats3KV+`$Y;{x>R0qr{seHf~~ZJo=Y0%oz7Z^ zLsU26J}Hctw;39YEOHBt03wqhA)HqeSRE4+GXRfbcGZuNCVjw-Inku`QiSA|hDyN# z%!Str;*P}1Z%c|2>}=RpL2eL&dk;mX$n3_53Z3D6)o&o{>Vu2gmJdP~LE#`~5vaT0$esTn{^jLV zu5RdPPtuD<;Q3g~a+MH83QAsefKN~6yq7OF+nW5HL0j!8DuX?tgr#XRJVQA2z88OH zs2sDTt&P5}jNds3OWn(ZmR>U=X0%$|n&a3p6T*2UCxlf@cVj4)Z>=j!`u&&T<*IWX zG)Z^yfB;S;F@)d@TDL9HY;qkal9b8+$AdWH^4k0(?~`Zd`gUws}EO;^*qYZRJdP;m_s}S7>pYZRBP5W6AwP ztwBe8JF~;>`^n4^4uI+;q`XZQZEvr8Kf%uD&sa7XWS=kI*7_F6s1^+luca_RM`#_? z$?N;Rv54zgpvBtPVH?&&{}s-?J#?%h8G<*%kY5xm<1-Gzf{=1enl(FFG8F}!r%tqN zc}K<;Rj{LJTSjx!VEV~v zqPV#|iNi~I-{|}bvn5J?72?S){Rn=N8DGmcH_NUo@+cqXBDO|;MdUCF&C9b>#@l=_(Co+S-* zETx}kD~dtkv}>q!3q&lfcMQ}G&jkSfw< zmrqylj}IVlh7s6bIri|1Mw_NtPe|Vy`rk)skNSSEN0^{aJ;VN0-*=P#DqY`4y(|8& zN4+r+1L%r`_7{%NddEhpz50ut`W+D6n`XfT9YcFZl11|;ff#m-fXcR1L77#}@Sb#UO1r}NnA&S_<2<2$T&U!cXP{IcYt@2N+YGWaJLkrX& zsLCcYOwt3R2H&~)b`8DOv|THzO4l@><~0==z}*0}6J!4-;EsPPr|YGeU~XK%enKa% zoFK1E+Nu_bE64V8r+sF#RktxneGbw;YB%LZ_b?m#(ObkF4W%JF#PsO`utoN3_k9BC zrj5}ZphyK_x_}}+;G~&AjVj!P93^WPxvz_jnV(!pe-$k$5i@{vtV#XuEQ7f2Jn69V z(?v3cS4w3G=<)YNP3)}d>JYyJl4xHHtXDoI(6w8SrsP8T=FtCiorzN5KJW|O4P~|t z+D~Ra`6Wuegh0*rV{Xqeb-^KKFpyGOZrrurIw?_I!;qe~`W5aBQCPA}oeVowPx1|1 zsv$;+kGeK)L*fDJ*r(b6qn@N-TXPXR#OZT_et7034D&^bp9P2H)cAWR`C6{|v`FlTSKyYdSXT$=F*+OjrrmHT)5KXJ#AGqJR3_TN2LY@`2X4`DdSVxh zq`^o*b2q#?9EEr?SSvlC80d5^+-RwgzMHHeU$&IH=dWNJzpfKjH0B&V6GvLgmRd>< zdY@}D-&Ab}Ei}~%eXp}bX4c{!xAAO@)tObwrKW|>qxYryu_o1d+G)ymWRg=xV@-L- zT3410Q2I8*$ko(`Ep=*WM~NA~cQKPDyV3}e5F_~7UMyxIKva5JioGJ396tZ@2=FO3pIi!Yf9nHe9U%Wt$H}xgiD*;b$s2FF}IfaV=+!? zlgQ7o@hxM7V=Jz?Rzpegu-;#C(aA#SRa^(;Y{8e|w?S$YYK+pi3%B1~R!) z>iqnD+9=)Otz(5`K*0DxuebuX&CK-Ecg(s^7B^mPl`UHjY8Tl`^6*p5!;jVsJ>4`g zTr>cYO_v=rf>7qXpj!;5g*O-viP`nbMY%?Jxa1Y1{Os_Vms@GQ*!8$2T;y^h_tU2FEv>9Eg-^ zJ}L8K7Mt-EwveN)lPH}KYRLr(7iHoe}8vSv9gkT`UXg(^dojkJ!&xFG5X zNk?bTG$s|%Y?}1)s3>Iymb&nHEDN`7{MBFDz9smbHk>mM|IwU`a%NhAb#+2K^_K%g z4~OzU$t>T%E>p_-=kD5Pv+AKGBN?^%{f;8ox6#?0CQl69l7klWz^_K{lpc7ABCmXT zh)uh%g8J9v0tjb>dz;yez6NqvV_6Ws@YL?L-Bt=GZQ1iB(K)Hgax$*6k$>hsqEI*s zxlaz!w3>Zoj2YpG|bUChmtwgKJvL`~jPGt3BCeO_=&=0H9k1}{#@nR*5_ z`}oJxGV~FC38UOR%$(bb@83Ii&x}6$;a|NFezxh&eqnd`uQxhlB7$>GZ}|$FpQyzv z<0Dx3IoW|%F#0*zF>^3}ubn^sg1<*)8W6a(%?s(=b!&7E7V*a%gJqL5Sj-@SI4b@I za@eY$gshkWdI@{7OSC?$&o7-g=`e7$3scXaDlecCTxOzRW%vi=sRg|S&afiWbFK^_ zLO9}wSp`Dq4d>Dw!otFbQQOFPXTtcJJcv}HidhxVOcH)bq3(tsLTuR3rqB|!2Fe*q z2V=)x8^RyOin8SBe*|TPRF*EpsQq7trURQQ!_C++sA?wu=pe6OU#w$2K@&wNV-uY8 zOb@A*l5{E#Y3tu63rq-s4>|P6o(97mjqdq#3|PZHm#dzvsL$+q3=_-;0XmW-9NWTE z%AYA)cg%6?t%sMaZU#ap%m=SSjA0VWoM`@-Y)ck%stRxvcAqS9$HT%b$-x{zDLL)o z$n5X55rf=b-tVt20ZaJP2q4|kv1sJ;Iqhqla6f;D(*Aiaj-SJAy9@byYjt((+uhpS z_=GXb-i>3sYs<5-yZtjQW-4bYr_~=Aw;JFu%~$|8;=iVWqweRRKOT1;_-N1bPL?_B z!E3l%n#6%oz$rAu&I2@e|B?b&K6!WCeD4O+QiB zH$~D^DSy(L+K`e8TP$vXmZW{*Ouh8Pb4qhk3(FsTp2JD?aM7L?(0B}DplR%xuDY%f zmEBp+yG3J7gVj@1zOP!@Zuax+n_V@uA9(ujM?ag;qdOhF2#SOpx8$aJ3@4x;FhCYAK-y^6`ZE5$sMo_zd z9zrxhsQtF#l%)El?DPhTFpJ2XG0}ox(B9%=E9*nO;W1j7g7ZGn`pY=CxG5`3G1#{* zshFDHm=cjiwv(aR9%FAByP9-F-Mv*mb9E%kM|D=-Zu*+^MLTF-R&NBcTDEcE#raYU zN939t?1u6S{n_8OZjLO-RukCyCt=RRQ|tUw#+-gS{@=|(ZhpJkf&HH#ndUg5|AkY` zlH3LIW-}*;wDQLGPG!zFe&p@-k2H>p^h+=ybiX|V(Xr>4kar6h z2vGPX>lCw(#7xF7ay!OGLJYH3!~gw2>zr;G!rN13l*4GiEB=$-a9eUXZ_J1*4ES3@ zWrETA__#5f+w@Vv`IB*Z}csvv8965i1{fwMLiLZ z9hix^lhQ(JKO;9a7ltmIR4S3{^Nn83|Ek0ij$2uIj$8j(^8WS!$3be4XWCmeHX`20f?@4B}V9Fs)}yt*{QbXkDOn)lsdf>2-Xt1x8n5oy(X{%6jL-Tdf* z?bW$lAG8txrwJHj*66oh3*X&hS0K6*LZ0lBNQG3%3M%lCCW*T1DH;}z`jPE_`4o8& z6B-q}5*i%=XG8Hz(jv4g*&Ws+Gn2d#1)h8*X(3N{?$7Xij)A_t$+ASld_S36>W;2ebGA6cV^B&sOlOLQyUK2 zXgtLMs9Y~hW*Boh|Hf($oXW>cIlZY%@WFwqSMqNH9)(amY2!c0V#Enf*jYY*r}Z2w zU1I8Px{5+dwE9g16y)C4MYjs;;yk7O&&Us{&)#hAb^xTt<+rV!P0#r7PrIargCqB| zcl6~G_(Q;4*PytS5)%IK1Q|$bG7i}xSOH7}t{YcSd|n*H9m)e$m}(y$B`N@mQJsD} zL;-C=ZQ$R50*n36MA#crBNPs7U@Wk%PDYjbi)7*b8C?gN(qtaK+BR;I5!DBl6vTOS z2~xL}xAcN?Lqb?4UpvGJuK^!Hg_)$BSPrTU&`PGLwskgwlC9-zo<{AHinV_ZpE1JX zz*&M6^7TMJk=#C5$L(ykkYU-V{RsBNIx53Ew|VT}hf8y{K;-+3h+#y6$uI~-5%)PS zPFb?EP4}pPa)>{5K|FY1yX%4?C}u+U6l0xxx(;w5$Ox-o$_|j`pRxSy)F_}oBt}q-4V-S2p#3~fkR?pn z*t`U$E6|{M4wfCk1xOs!zO_Jarv(xJhC%j?9k&kbg1Vvm(E4@}rl}0v$^P)jl&nxu zkP>g3Qyu>@OphE*{f!+SYp0lp z!ttF0iv^AAsfs7ZCE%yR4q&fqZb^-te{0Pc}1Sz9%XL0JfK>GpGRxF`5-bF?!kweZ;WmH8AL^MZz`RT*#X zhI$@gK6nb?BC>?n$mG~10f)JHXIjM)i`5&%Z$C3kGVx`EwTX1HENEz)(;Vm4ChZrV zQmfAzniG?WUI6Jt?G@-*GwITGSjtP=w*wbhoRwGC+)h_L^mmt5-Oh4OvC}JBy>nf3 zqzm2pS4m44tdyT(ER>(z8K~|IqF#s{z7>?BVywQymw4rf)CXz;c+N@38?LVIarFyM zIC_ETmb!PcE25x78LhNuXyI2iAIdE$qw+^n)}-2obM7&RpX~EvID6^VWV~W>nN5ER zsw1;`Gh0HMbcPyYK!lCz&JMJ}`&)FHCK79#6qU~DNRX$0qY7JLBuCC&a=CFv8aFZ{ zWV~m@8MsP)*u=xaiI0{HB`h6_!enLv*d?UynP-TLoun#qx=ye*R&HryzW)J9!Ls)) z-S$>bRda5JHjCoSy}u5KCs=!q8GAC9jTdSB(hrQ9G-K+?_{`|Vzb%)H+NKFx*o>~CyK%S^ zj6puH4S_@uhqs!;G|>X(2z$Jd2j`%?&B^+{YVLK zq+Xo~R@;LzAD2s;Um}KvhAb-gnn`t(%dj(fEkw9#^)7Us zmzu^Y)KX1N_j0w2t)}XzmiF(4uL8bw1?pI-o0y5-(=2eRqEDIz(zhMurdvvh zc%i|Y7cL{_dv z!#k$-J%Q}1a^T!_$-VxBXX_o?!Y8qj`^R=>uI0pHLm6tC_kXAUeHI&OHyRK4n4N-p zLyAfqPdY+RSiN^|j0et}j5shKep9Dgq~FZz3K~O@d>ADt8|oM+k(JXSYyxsV^TcZXGGV57P#AyZ%tV*= zjEbA(@C$3M)$E9_@-`_sCvbPd=)&M)Qrs;Cl2DVJ@1#38pHA8F9G|Ej%ta0pW=jp& z-474ky$uRP2&aq{Sa0N}r;?af<~UYwz``5=KYwd9MJ0GE1F)24m;ra`*)7dzkhobO z-_4FrD?V~xwSc7aTc`fY1?T+ONcuzMhkF3VPmYE#2c38Y$F#rKRmU{mwpTL-UQuVKhIgk_ zEw)xYr)`<~qL1VNeVGW1C1^zEI+UAeIGHRd@XVrLeac+o=D(4~Dox6oYIMzn2O`?U z^-Luob4R~Bh&anWLUtPvLQl1N?n4wfpqPrr(p3)joB|CoQ&BeVduaxuj{fqC>Y+?R zv4&^#c4y(LsDVB^yljJGV?Yecz*9qV;}eVNy;<-JMFUc`COx!1PDNQ%>N6bMd|tDM z)1lr#B>$B=Ztwtws@n|~1NE_JXI2q5-Qfm3$2^SP>7)(RwnM4;YD-DcTJr=ifgD#3OhE%bzrQ+tRd1K+{lIw4=m)ynvn@Q z`Ymt}w1{*?7R#=aqQu|YU=2gPy^|Hug>jiIOG;%nvDdJ`tm789UBA;&5G20o41EE% z#va$(S^om7WD(d0eUJ&(ck^h*ZM{^-!d^@HNy>)je$PwDb;TmUJ7ko5hE~QT`yda3 z;E`5So2n5U+>{j66|YXmBcaJVQkmTU|7uz3zeDq7U}_qqA-Ja~aCu zeOC}h4;4~um$k(@?w!}TU#x2N4;(&m<|FTI zXPn(hkhRrYanD!#I=G}8O24CwM6ngYDSctP2J@;tPBkWz?N5F&?$+a{v&`c-_Gep` zk%D_or5T;#k$^Wci}0u`1X<-B^M(}{%}{gOWmsDO4;^?I|9?RTxQ|q&ZO41tsP#q6 z3vM{#lL4=9u3dytr`T z-#-3+O#b}B^Wa+<|H!mjwbFL~LT4=%i!XebE-&4eK{~$<&fOMxi|R&inT*H5=`6Uu zlkC~WfO~WK*agzy*1|ZgeVI$uOEmHNqEWYu=`%l~Ot~DY?GkSlJlhcZoTS5{B zMR}qxra@<`iuute6P^FBi2l5ng01N;j!&D1d%M4ni-#Apjtfnj)*50R7f~1g@#o-u zGz_)7132s{f0QP8CGPIG<4bL5zWQY1@9%u>4GbEYum30D`3VNNOPUmotB z99)FiaJZ;$H*zG_RA%=n|3n;}=&1<_a`o_X2nYlW9a|-BjH>>A2DIf8X}$CU80sWF z1d9#!JQXet;!b~;Lq|82mNF{cSy9J|ndYb7abfAeF(AgCb;2V@QJ27l5}ZlI%O2C^ zUX=)RB&*P;o;bdSJ@y;&PcF+_Yhh$Xk%6H@%`!KbDAgj;)M$CD`yB3IipllMh^j`o_jL74*?aG zI<MJ#aVwkpgMJw+6GNsF=_H#GP=kb4e2Ggej_3aA-U)Rzq@T-mz-e4_R={VQtLh zDP&n+(BHDMvGu3J(GDVQ2)aL(Ef)5F#X^F-2dSKM*raeM*rae>A~$)bjN+o zM1cQr0OS8~fYIbKDNh@werd{gW6|MTO17DaGsmMeHO&(*VN)L#ZJ+{Jb`g|9J91`E z^n{)(36PQOUz2zvBS#>uWRfMPA!LRb#CAu#&UC~udox5?7t3R5zY3)NDuB){6u6RR z!{L^TWGGta?N5>KD}2hu$N72emqT*d9+%06Naj=#eFKrCJ?T5=5-3*8r+dzZb^aCu zRk+bZ1`Nh2>PUh6Yo?)a=5tFE`F@Dg(r=UWrkV4?E8&qY-8*hVSrKH`BQZq{rD=et z%Q7`s{#3GM{|KKPC-{v2C5XZ%FhpcgQC}GQ9~R)V<4Fk7sOwmJ*btbU2gmp70L%hA zsifG@70b4srfy!+zk6(&>9!(Ku_BYeFWhg2T_fN=Y~}_eNh_8$Y%{b_zMlQVP_3Ey zVM#{REmID2f0e>Vy&FtEYh!NGt2_`jMmy)) zVbrQt4y#gZkNtyHLa|An+7gqP0}-%Mxi-E7RpNg%%=2gu333@8OHdnB3S){}vvII; z!=)&&M?x^T<9w&zSq$3#=$8$WD^+Ccur`=_lbo+v;gAn@To?)p>oA!;5Qq{XjgFAq z=Ytap8b=gvI7+QwDdsLcA5Hh-5;f zoli10*Xj6M0eK{N1uUh&C!jDNk_yM8<5AqSOVtVZ5A5Ynfr}U8VW?bJwOJ^_^E_7E zxv*&_Md4@ZYm%#sc$$(c`U7Z4cp&Z#OhwTxQloZ{#FGTL))gI#GO+?CVPo0ajvvL< zW;%|EKk2;xpp2VkCxag-!^`J?P{zGxgdvx>!4bsN&z6aK)WE%#DoY0x&IBLw^pW2e zg|F}Pli<7b!p*<8&hpcBv30R#CtjL^iyueD)XI7@Mi=<=#(!ozPydG>`?|k*pFH@p zH@x@nXm@w_!$Bifc}J}Aeabe}Ek5uL+IS9yoQR{IFwFF~GhvJY3KM3gDr?Pt6Z%T7 zHJ6nJZ1W^O*L$1#Zv`p$l@DIG43bw1EEsBWMCnya5@X==Q9TQQ9aO@tkuj&X(sM?%ci zqUwKfHNhYtPu?PP_#BO}(OTXP2IrWpr^8>VLU2_p@ze>Nna7j&{7`n)B>J*^%*Oq0 zD)iv?Eh7F`rqe8ni<<1}HN+9>I6g~u}*WeT+;ykG>m#}^65|te@JG~CiEPI7EzlD?(T3cm5d}B*q z^O^vR%4T*rJfoI8Jz$kzhbo@aROV42Ah3;MlA;$J~^zTn(9|*kx!5K*1S@7<;<)wXBkQ#X>xFJ=;4==4T!m(hh z14hP}vk7E1n5W3u(I3C&pEL9VCcRLDe8rq@onlP}8Z)BDdU#C!FbEd7XFblI&(1OW05=q(KH-Jv z>O2{Y*kh~$NA?_Lkp^W5%)hFD3kxL)RWyPz$6qxP^p#R_z1+>_29ioL`lkheED$g7a``` zFG;uJkI>c8V3F2@f3Q?G(oHp2D z7lmlaTVhNPY;CXGAoo|5E1g7(2QxeKI`WTIN?5lWLPn|tx%CazTdOkRD7C1ia2)IAlF`D%d66ReAx5 zzfi^o{MQpyrr(E0_|$bc{-H`(#)-_MZPui*DFRlgs3LX7-9M>KwhuKvcsB4<5-Pna zO2yogBIBYTk70F=Ge|i_9@99_;DqW8D_6OvVf z`}d2c*iW7lIN)Q(Lonax=FNk%OArO9x|%8-UesGpiJ2umn1WIZ8a06}i4?Q=kcT)B znxwC-3oaE042M6$u=0z}Eq6s?(kD>zrcQ5kYbLQCLDCI{GV6 z+WqBNuLkj#U8`~KFYw2C9Sy|F^v%<}ATydrZ|gD&_nq(s*`=3MB{^q^VN+kKlC_Hr zKHGo0l_<&jl9wH0R#on{*1BJNUnlyx{{Gu}Rl6(y5ISm{3}){oQ5t@v@4>~6Hb2Kj zmnZ30XMKIb_x179(|NB=&)S;Dz1zvu)A5r&2Zwvhw%r%FO%uxicW(#_*0-s#rOs== zFS$Ss6(_BEV1qIr2P|?A&Cv=i}haJR%c%&8ID|$)D0OH zsK$}!>8+r#f4rbZcdL|r1jbW+8IJvtcG- z%sWXv(gtJx8W9EPZ1D2TABP7=IH&<{l}G|=SW+&}Uy44`0!Vy`gjGRfvSc8H(IzwH zHI89(pt@jZi0~^qKL5Mhb|D*>{F{oqzd`K|=gPJcz$Y|0BJ==FtY4@St$kCd`Sry;vqd&U}z2Qn1!TP@4#5!TkIgUG{I<#Ho4(u4J zYXwh}aIHfJF)Ivf*Bhjtf9dB^nmd_a8KR~nhO0L#;^GO|^8_tWF-3C$Af1NOfTqd1 zu^kSCsBadx@y@^kG=LKz|F2%_Pk6M_@ZFpFT_XtQ%jnWx_(dQ#1k;Ej(PNIS-|oR& z`Dq&c_ge(P5HRo=D7<-ZfZ4UZCYLotB^Y10u!y{~Re7>j$`usCf<_omJyhVy)bJ_H zx#H4Mm_L0JoQYEKE|2S;O>_zwF<$`R_mwEsWWmv>e2c8Yt@7G~ErS&yh6!whe5tzx z)O+bK^7?&Rz49IAcKJ%hP|!_bjh&5`yibJFM>D&~z_v0#&p$t$@5lha}uTo=3=wu5H+Eoq{` z0plFDr9n7g{sG=X-@jl50s2m#0p%;u3;~9BbstaC0O4bn4;ay~U+TS9K&T%rP6Xx8 zGLd;N_tVbE(|OltYjbz=r_DFt$Tc`uFra{|C;*vAQ*aRwd=3W5k1$FUv<;6(x_;dS zgo!ExEKB0(z>$xN24;X4Z~YH^-{C`Q$QG+djAYl4H@slS6IhrHBQw(8&>}>DMBl65 zU-vxt*^mj842_TbH<2(iltaW@&R749)0iaS7h_*fJm<~A7t#w?NzNBmqwDQ=;)mS# z+p~x6N3S0fcJ2N5g8%%610Sdhe0LTZ2q_-X`fH2)b>VdDr?tnzYs*ZD;>pIh{|WdD z^hi1x8Xi90yqrMPcyGe!FW(E&HinJiAGIzfko>5DCh$I?)K9@lz9F8tnJoA?4vp>KL_Iy_>cgM_=9$DyXQ>9-gNW6 zC{_ahn2Y8r7MQ&ZU<{xnLxhQ}jrD;~cLruf_}hdUa{tU#>Df{4IlElRY&bIo5{=}{RNtb?C+ zSOHX#q{7JHA+%EbOnF2!Jv)O1jQq4Pat;qsxNu}87E!`aF!5M@b5M{P zXS>!zS4c4MQonLA8T*EBcMzs|aw;on<3M2)!m}WO!jt=nfEG06+tC6%G-R;yVm+2O zF5ZVag_t?}dfJ#90@pK~xle`;PlxxH?0uH;r%-0kBwK zxdB3CJrYPw*CG(0EUA^^?knuViUa||Vf$1gXw}{O_lOOUK;uP-`iy)l2yIRjvBIe+ zi~k~~VrZ*yL`QS{AWU+vPTWKhc)~uCm|oGLrJW* z62S;qPXqVE663!3_`M_1dTt#g4PU{nEp_9BMA~Nw{Eotpz}~F#_Xf63fH=gtXFMtq zzrhcr?AA;lp38df-$yi=61Aj<4#JqE3`8d>c%4-n_NC8p{+dj}+O-SE`!NizWF@9H zi{C%tojoFjHefK8vRP%qO^d_YL!1b7a%A%Xa)q8cM)8YrQh`K`I$wDc0Fr(hJHLG) zR`^WhA+_;~h;HlJTEj_k89wj8dILS|SSY{eMr!QT*+Lxgwd(II`9O_Ot zBq~tIzR)E79G$Pe-HX!f5S6V;yM8JRn8id=f2?FgBm zI{4_)C%_Rg$8_S%Z}k0WtfD+Q1Y?W*s~7g&Uo&#@Fw5s({*Rn5`sM<+Q+F83GQxH^ zs^wUa%lLjB}2OFOU|3p8(*$+y-AY`M2xdE@75hp&O$ktE~(itk*`~mW^ zAn~Dxsi7NFHyUi4=C8)9`uZ6d z^8H@3;?rN(*U%0e4SGXDYtdvi^{#9}ERvf6l(QyKk;_=PJlp z27C9TAU(K3_gIPvQNopc)n%thT1>Pv(Wo`R)#c4h7DJmZb%JCHo{A8=Yor_h-# z;E}lzbluRQoMpDZ+RU{6sx^rDM!V&920h%XlNcvR5%PqK)2AlE=8j7ioen~%97o2CN1E5!n*KAP6S~(n`Gy;XR#k`6 z@z|U2BcT1aESPkRByY;5`~ZNG6@!D$p8QGR2U_&b_Jmv7MP=NJ$+uNr@AuF1NPedy zh)REvpa7hs$TQ}Y=I(7&QBQuIIFmf5=Y{QB{E`KW289?6W9)Z)ke!Jk2Ml3Bxais# zl29*1ljjp$TN`MdyO8N~;Gk zC>>yBT&rkN{6@r2Fa_pi(KeUKviBQCZL#N`c6gT+*6T-_6a^RlBsGm4d_XH=IWVh# z^0pR`bh$dby~YC?fphu1UJ&O&*=|D2^)aS^Hz2s-ss~N+DC|SY9COx zpnZ@C*&lFZ0QQbhhyk@RU!3f3j1q&OAd6(MF7{zM#otoD;oR}t^t!|iqDGn7%#6{J zERp#Tu$jyJ$Xg^#3vV@v1r;cS;{o?c1`IO#(8C7pek5mDXVWb)Wbm8V*%0_gdC_ma z!#H>88k#Vr{D#a3ow-O8ZVN4Z|DbHf_IHsW@GoOpAr;eSI^CHN+9k5&y3&Sp_=7Uo zY>NCA3$S|doUWI*eK8z?9Z{?flq_1~UruX@hG+j}QxBsn3_Ox1!qFDmY56=b^|KWK z7#)cCt<&y^rKYh0puH5ns-kuniFQcAmK-G@Fw-g=d^ikyXi*phUqb z9hEY3EJ)LJ8f{!zzf#<`feNY(*rV}D&Kc6Jf@k3>5p6qPCNsn;aAyD7`&&UT@e<&L zIfACsPuu>cv+p7@)=citBkprxGLXLkuC4%0f*HFluK&3mS7n+q`Z!l3%xT(E>62vc<|8x zE0OF$0Z~Hz<5gDjYJkndf>#ND2(?mK4?6NioQ{K>-Yu19bd6rs+E21J86bt~nH-X< zbJ|nx9R_t&rIU0i{a0s@bBu1AVA#0B4uwc$13UbvL;=ENfvE*QW=Qg_n6WR=rPDo7 z<-FUOTfb@Hl`;*@Cfo>+KZy?LhBlK7v3*)(b52&TZG%+A!Az-VU^0m>P(*=CfXmai zMPsvSNvz7~LB0tM3-)95&BVzh;Xq)xf>L1j(nNe3vl3bI!OR{f!Y73o zQkUWYSHhkoMUG0z$QS-;h_#0a_rUAR+h9ZRg{haf6XQXgW>K{rFg!5a^*_pt%Dm-F zD^dmXVORG>t9B%yA73IEK_tfS^(JF) zz()Q?4=5C9Pg%qs7=j-{Vr}PhdLI!=RI#ifHoedHU5I!IyKtIfS{{ez`q5k-6vVHVyAwYVSlv383gm=y+o8z{GFhn%j?@ock zSfV5EEBc|pCs|Wn;D>UAC98>&zN zG)Ng3J z8H-*8SnFMtc5xj24OM$)sVU(k;iz)=fkv#|D$G1Qyc}J;Jm5wm%7woO9zNUL`A|9d zUpia7#HcPrm%1DI1wU^Y(x*-Gu8Tse7o*9<+6Cw$izWK|?~rMcTfz(3qm`bWoZ=aC z{8(3ihKWo~adFZwm*}9m7YhzU+O$0FOV#ZB)1f{_hn&_4tcNOcXb&cCTSuFp)Kw%@ zRQzU0kBW|R@Rs60G$qMBY)CLb_XQ{bLPK$?%5!KXfZW-g*vf!#I3?TL3w5m^?BkJG zU1t+l(HEgRbq>fBdl#^OD&;IvsK9v9>C)TE|4ha-si1wSyzeE#67s_Z_jUe(po?XN zQIi4)+9ziuNy<}*)rc=kMZ;PapqJ07GK8*L#@vO_JA{eRWk$&vQ_X^r^eeJKX+x_# zkVXSGL&4*7o{2%+6&7QEzAtmOXOxB$@a#Ek^OHr_aPzlm(O6FMqPbaJ?lQbsI*~aE zGPRGfr62=1VAn`S9On{4gduQP+k}AE9d|5YvMW|-0n6c3Ni36_k3^WYK z;^6i7n-r*zn~k9Eo2WX$XbTI`NQJe-hm~Jq^C$6_;Y1^Q?jW03LHSN zT*nvdJ8etM|B-A7C=L9h8E&$jS@<(;g{JNKOfY!E8tZk0dk8_^Xp*O$Cig%D-zzB> z;({yUH(1GnQNi!aD&iLfctK9Ny+q;PwaLH5J_c{<=G!?5N(RxSPmYtqofGxd-Y1>6 zNG7T4{2yy4M#eXT8HyJQ0y9)OrPlJN4CGR4*qD#!vSSqRCY)L0NLi&8n@0H*his#H zC~I8%^3N@tPtOd3ulsAn8S{>*FDxcM7wI|KjEpT~T-Hd&A+k8M?%SEwG3YL=+PWb0 zji(6JI}HTRh_G@6=&zoUSZPkYg3Q=nuaG7#gSc0C#QzT4mfnHIQh600j*;&k{Tzvd zcEt@ZS?x^o@wS06_tW)G_?cgR#*`beVLY;K*$5v}<1H~1$leTzbm7we(}hRua^);F zo(?xlhCa*Dv%zhsqGFlDA{8)&VN**JHa98yBI+~AFm4!ZGA5Wk((ed@@x8UmdfqU* z#U|XSy3OAwHbwtYP%Bo5g$%_0<_`M1$~oy*;R*eFsso)- zSG{dwiLX%9fE{5e_^J{p{Zl2ezs_Z84(qAXyVuIz^`Gk2u%=ePguTC?dPMw$?%a5v z9ByHmf|Yg6xwV)Lwb-FQT$VUlrL$qin8e*yV#XY$YHZl6U>f$DsO5n61OnIH?;;`I z5_Qc16t(hvP=W72?f}If!wnev?yyF3U3oJ5YSvnneN@!uM3 zoWMJG?t`DQuSq<7&>rN|vH-}`aX^8hhtlC@u`d{clSbe~$@1W<|77K;4(8nUGBtjg z#AqR*<8?H=>{HX7YN29-w!thy0aVDX0KQC#~z=gLvM8m83n!lvfmXFsU+%ZqCE%ohlbJtb5Dt zoXy8q`-v>e^l=G(le?}43{p$jC(AvK9XM;is{<-vQj;6WAz^y?tmapXlWSxqVTC}? z({r?`2O=5xP=`m1iHJIgB4{jy@>IaoA>FX!xDKbRq7D)u-aHWxXC>MzrL}T? zd&~wvUS`+pUUPM-Rzk%J!1vmJy&s>0p7#iFf?pv{Bk6-I5I*T+KdFV+ZIq@}oL@S^ z+93l>(47B6I8QcBWY7;t%VM} z`h$jOOHJd^M&C|)gV5^vDe(B&-D!h+h8qI3^MR!;zFU~G8I7G!E5D-gi9IW-R!18i zmR`%4?<@_JloXZ&!TZrvUH-Z`-47`k_>(-K;ar2jSobV*fkbF04B;H}9Mdr=ur}DC z@t^Q4qbW!7*C+eD9`<&2dR4c7 z&8}o*cGI1vUS+wg=gL0vDflhtS;{_L1jFa!{W5@H(X)U|P$C+L8u(HL?Pd^SQJ+Uk zI_bs0O!fI{pi+;_u}c}r59L+YGqgMFL$@E(@~D%gJf_F|K|ndcNUezfULcDOW}LlZv#6n*XF zlolWJXvMnEp>fOLFXFx@aWl_BWakAwnKmBE=L{1E52^$ zwkw^7Z^T2pl-=&BZ19bM;23o7^V3`^?eyH4a7pL`-e0rqgubbziQ5;d|E|QrY0!W8 zeJNjbqUxi3N5eVt?3V9ZI9d1 z(8reXrUp+ALAY+~;Gf1Zu~Nc_>Z*4 zgeJ4kC6uTAefAA7BoJB)J)6`sJsi>SNh%nPj_$WlCsFFPZTF>p2lni58PsC;jKV;H zJo70m_xDe)gQL^_jVE;ZKV(k;Ba!KenO)R{V}+JNBkAy)f~V!jjZXIu{M(MzpsN?L z=#6aJ`Qr}ydw#(SS0V3L!tDZ}Il0@MFH;mhvpNoJ3m5L8FS*VP3SD;dL}KqnJYecs zhx01f#IlCXIyf{1uk22(g@a76fN?*7qIpDjzhm89jDiZYt*yCvd!)KI@{JXq>|H0x zh(TcHo6Nrg^_q5@Fc+f2ic7HCPYG8r59jR=)1~9FY;fVI>IM|O z;?}L9(KUB@p5$tp*PWe9pWu7T;lXNUCPkKJ*2Q4f@NI2`{=Nup35zUDU%|r%1CGV@ z`D|>o4{vrP;Zxv=fGikwSC7@#a*351<8!vVlQS<#d35K=pFA|kltIpNZj$v#C_JkW_bu2X1bHoeJo+qznThAsK3$5B)UF4 zZ69q}h>(Tm6!M7wN}f%JKjN95O_#lkSmbp%)C9FGMUX$_?z&Vs%X>(os{KJbw_)t} zu|)l4-d@^b=A%LB1XlINJx}6t=;gWsC$7U1{j%F)Me{VJDE8^D$I5kuMg7P1)+Z4T zhRw;APO$g=dKp+YACTh1)>^Z;iCG*nvpf5Of(5z3km7b8yOcG{dqK#HS%i!bb;f9d zHF7uKc(qN)=ZBbD1%bDkae5Q)FF`3uFScSLOSbrh@XPE8Ew@pNf`?SvYCN=8aIL{D zc;ek(>ABcZqB{-gTKzmHxR7;JJP*?#q|A(5e70-_D6qbMyXX7X8j_a@iY=lluQW3gDoEBco0!qHfh zq!vKs{Zze)%`ABIStTB_@9T}xYjGHOJHV9kC$Mx70byDtlPWkYFN-82;Gcm}&JRD1 zt+9WUxG*G#npe6BzdG$8ZEY2M-E+;`CRm76LszoGXs=$fhl{7sTZN!JjaOe=k~4Y| z+Md%d;HQat;Q0IrbTLce zW{u&3;MV|Gc$rSUxgluXZv=R)CAdIx18;z+Tmm^tvPf+o!i-caixJFWkpNBm+UNSn zuXmt;QyS4UPB$1PPjh~+doPPBwy3XR+i00SEjfNb9e4o!+w{gVclsdy#LtVio^x02 zYU6kX2SYUKD%*?+Rd2Lq-R^Eyb)!sLT|cj*o_G0l7SQ+cTTN{Nb-Fv;*lR1U5idY8 z>ya*pw)8=brtWsm@plD|p5)=FsPWK%D|7*OdcBu8o%HPoYifbl7K|jCB84)o>Z@BK z2mw99fB2Gesw%4z;?mICZrar?3b3lf(zI`#h->^SsIT_gru37Oq{waN2fi}PH{a<_ z+P3ey$frDT3fm1y;>}<~ZiY&n8`IKM=pv`w>|y_gTwsgjjKKtsU9d6$l}*? z)kRGKeaPdb3?0?x=upCU=CL^bT6~%Q6%TnpWj9uRS8|M>bVVdWBp`TVVrSf}#j=03 z&^9?^Wn}AmFZI4~Su%-yAkL2c9XRX|vgCbL&i03EtWLp4xu6R!b2ntO|6|e0rWI(l za>9-->f6QJ9Mgn-+PdzObywA-0Mtyx;t*)}uC9PfVMqX?&{k)l!Ug0m+5Tl0`Ox>P zq)$el{*6kjPK$brSpft|M<)&6CR_d08%PUotMZ}-qCNpxCh%AOI=l~kPga{{R>ZMjq-}^oYb!{7YS0<+q zlFYS9(GI$g0|mA^?E+zxW+W5ZoLs^^fBlkRpN2-o=1CQ|jn8?IHco;#X)96aC1#m%BPcGJ(|g!N|njLs;a+6MZI7 z$?_)6bng@pRdh$ls=dREi|iG#SSx!B;B)fUu9I1G`31dJttnhrOAf=4cw1Xm8VoRj zFlTC8bb%tTaH;Ez0_o@mLY^SakTJIp^wD7(*m_jQGCKQ*oIKh>9;>TX(ALv67jgF2 z%S5Yyhu-!Pk}1hJ{p29n$@Qbd$xAaW6P&4Sbw(=GVH6~F;lRp6pXb=dAU;;dKTFH0 z9o53k^7O=A{mBOAylfp2F%tsvy49Bgj1%(P70I$2pex;*g7To3zqNs~2>#q-@bu3h z6Ie4*S(Lj~#E7UMbDSL+T?pP<`zK4mB$#spZe5EEp&{k0dhnURTfa!nC{haaAo`ln z>sEy<+wPuWFzxt4G8Q^W|5cBX-aX7Z+Dkg|iSiSfL&5Hx#P2H=+E-KaUnWSV@EQ>u ziMpzGVmR)Xka7YMy0_rLkVL0}Khq%TP;tR54?)si2ijydlKKsJ=5=}=zBOtCeAiFe zcJ~xu@f{iqd^pd6aX$t%5(_4AhqHf+G1gARNBABDTE_Taos@`WJI|yhQ(?)q7O!Gk ze=N|L_|3r~#dCgfAf#kQ`(yyqlupB`4ghTU`bWZ}UdXD45c^lLULHVQ(e-8+9;D5r zHV06zQoLJ(5ZTzSjZO&2)M0vRfcR z$$1B3rUYfNSFR%}iA&EoEARnej(_@B%)mexkR@5Toqf-X8^DfX;b6hldD7=R+U*&) z;rJbBjv$ps(~CgbQ^xdVdf5_wp=WZH^9)ZqW-z|;nsFf2AmC2CGavG^&dh>;XVa32 zf^K_eovFJjR3~sJze$de&mxpf$!M=KYc(_*?{#nbO&O({@Zck4xq3uuDN|zhD8&_} z-FV13P7&0uQttt&q0U^u7@d-ccj=+oi+Qm4X_A(~GGd_qr3}*~Cb5~ABcJ-0SPygz z!3xZ68^g+qe5Q(T3@02^2Lm?iEL(PW&nw?3IfCcFx>69lbLPoT;L+FnL)UBi{p|T- z{n73NwwP;PD=6m9n~VFz4kjDvEclN z4VBSu9`<6Dxnnw@_}q~#nB{&vT~Kn&n@m^_B@cQ#?;L5L|3|+bY(8uN^EIILr88#l z7gCc-JO>9E_jitI^AezO?io5%#t4=)#36}%w~CaaOpNV zK}Q&bUS9T5kecz2iYpJqrY)VlLpo7fye1tDPN48;4M0|N)+tAKYyn9D? zbIGg>DP-f+_f`;$BCQx0h%~}HZ(nY1mHx2p10GHXz|@4#EcZ?9qJYVHjGh**26bG_DiAP)jz4%KPV-STS!cQNQ2AcSo5n9c;QnA1INI5t_s@y?IsLDWxsUcOK&Xu~xTJ+_B? z@qbGNr3?3=-^+;uYeK%Hf{y*e@|fW?ecKrq-~;J64QoMs?u7kRwbN!p7w@Ge2xpkv zyx}xH+dy|MTj`I{&wthqEEKc>u+RnnSICc+2g?6#f;ACAVYR(ndUUw<;`c?g(=+@z zjz_JNwA@(~35CC2pFJ|hkIFp~^g4^us7w;lm>COPH5RN!vA`_;+x%)Y=&!aK7x$xC za0Z;|5Wh%<5NpmU?wOy#0~1;T1+yLjX<2YJ4?e5W0ZLsM0?XV4iD}}QAQ3H_%*#U9 zC{ylHA#gDKJRkS1C+vu@vqq_1)cGIL6+M2zsmg8UiHpGVqD@!{mZr6|!nrF-us3tJ zR$DWEXeZ)i(BoCKq-mronX_;Tim(xPaFxec5LvcT-da z>|eW_-2x1Sg3>ZV$#f}pn#IywY}7RjPYePQH4+DN<<>HA4>*}nlO?uX0iIyrbyK$+ zOIX9n)1}2IEWk7LtbGD`A{;wwzjY2{Nf>2J* z&PW{bOM3*`d0?{m7Mhl5-uvJdzt!&WR46B(ZGHf3;)DuYs*y4`b7&~5A9>$&rgF{c z73bMmt5NXq7N{Yb5gB*S4X{ZmL2p|V@xhq`L-M3};DTkYz!yC)Ct(!Swuk+MD7i(zz%wehMOJbTj3l-e z^Y+d+NYbWBg)b80$loJY#tRii*_seq!OHL%@>B_%8rOk@RS=om_`xSIpFcD~MR!;0 zI#1;ZEYg}Zp$YEa6;ah~zg%);Es-96s+pvdRYIS9f=com}W1{LW!Gso{>*&N)AW~;sP_%CBmL49;+lt3b0U>B^1Eb8`0n=I`kf{DJ6bPpKBo0pA|Ahy^Xs%N=9^B1ur%ApY6q_ zfs2W8aS-hpxH6O9>vXqBq;3hp;;cp;{)dn4-fBHoi>P?f-&HC#4ZkrjW2~D!i%6vp zA@IEBs57C3-@@zzb6*W~lJ{N19&VB?S-wnY8u8HdHnhCa>ka(iX$@2iQSJ|4V!Y(d z%Xo(vA7*lk%I|gl4NxIvUgClP6Dys)s5An63*vRKXEtgeVS3Dl@BZyTL8I(7uqhl2i;JS?h)&Q)F!rGf#MuMFlkB zz~$!BMR#FV08Zkp9`_+!s5=x|61w(5|K@wel%)>w4hSk_g9`= z(40XUm^CFDwVLiDr;b2Td(d9uc_Yxv%K!9@M%QzZ*iqJE=S1qA^rvVPl7-NaD7n1- zw^!O0VEd+^ZSI9Lv$atqQ!Tn<32|aYIe^#8=7zz)Vi+6+5b;cAkWRWOUycj5nT(uYoV}_l+Syk@Z%kmgcw<9NpX!=a_!&T^> zkkb6C?QF9MMo~%G*gof#88HX#Pj);;1X4YR*-vprUl*NrjDRTpfR2kBt72@y8 zM^S}o7_~kzirvo_3TYBuONm+H8%H&VL@u4+Fx>1J5QlMq9?=-iOE&gB{SdQSqmkAy z`FQ|#@CAKDoT90|KbZ<7aNslsTw31lbjYmQjg*w9Bv9F_i+Eex%f{=gx3Sx}l#4JfQ$^L0zSYKwr4`2cZSB5~RmqHBA} zLem=9amq=TpyU(t@rL7{>rQ`;3!pN41ua1=lOss|@ewetvXW&2U9m9H;>Vb!jFi=+ z8w0ulduO;vy%P4ghk`*9f~}>j%W^4muD8Nv0;XUjSc;+rm6)3YBL5(80%&QiX|*6# z=>=d~5UA+1dRZ;K^x!i;$hi4>Dm^y;Sh<&w;|*``f;U=_JB|x_jXOl^2&_YG(g|uC zUggk9jA?Y8)X{b-M!ebq?Cxg~TM3B0D5c#ov|EvJe6;jqU4&RtW8o&mn_aK$rJbY@ zT1(hWz<;Z8^7W+HzYRs;l>)VcRkv^gF)U8S1CA~S>-di`a6-(5l0>D)RviR2`rscX z1`gdpvzs?7s|~}c5LXq{J_^$=XyW}< z)aazn-Erq(+Y~Z{g3Oc;&%T5NDskZLA{2A+~jUfN1MEs)RE??XQOMPw1jB-F-m$L z3J~^NpGjp7Txv9*_SPKJ3mTD*7LA0+K^68)3^P(Ni3OnzQP@Hh68S~rgRLr=P& zO+gJR!h4)wT3EWRHKn)GQl$=5J41(3RBPk(rR}%sqVHO3lQ(g07{NZCpz&wy?EJJI z7Tzgum$?2BWlbn(U!whQHFX#IGI_h_W99AU!R>puLD-IQl|o_z9?;5WeS6C$ zc4@axxHekEPdcFsi14mwM*O>j;!#H|QYkBo$U!SES1>n2z2WSq4W|XR5$%+a@@HEK z1KC;I0y7z*Jw06+5lOa~?^x2)lh)KPUXrFEnaUQ92-#H(fN4tMAm}>cghe!xdq-)|aoa$`H^_HIT`EepM%W+tRbOta` zzK{GG$5n(gHrVu3cMX@a?Y-eih6)06VQJ4|XUk_XX&;0OaAO}ARKWf-BfqJd#};R0 z0+~%y4*pviVN$b-@U7)Bv5qUPPpi(9 z?dE^CyV1}xwmmn07E?rcY?I-&h5PWMiymEqm%Iv<=GA_>&Xn#aM~{Y`fl(+ggGl+z zmGO`2fNq6;x}x9wT3S>+;D_w&Wo^6=uSnEN@Sia# z0zR~D5I4#~_Oe+_3)#7;+dg>kY{|K5_Hc$}OSO^GZSsNI z5Ut3eTGR4`F!okCcEtY`@^hqG>VKQx@@BJc+)g~GJ$m`_CPP$|4v3ARTM;=>dCUJU zBbcuT?Ny{_GTYku%vwDFq6e#K>-Z3NGIw1S*NiH!OyO-)VqPfy;RfZ9aUF5Bd=ORP zh6=mj!VyrIf?XVXsrQm#%xi2{5NlMxjI$H?{xR-*N&dD^JYUtB^P=oC5`CPB`Pde@ zi`%4sWh_BG`J%BDo}3(93|=e$5JTpp?Kd)-I#jvljQV+K-CF4|zYi1dWfQkM6?E73 z!9%JfWs;phv2gSjcVaIIZa5~w{yz{%R3{H6!=6cuM^w6BFqVEARM*KN!ya$DG}n+4 zP)u}~3OiIg*PNY$zFeVNVtcK#`fT&3&-Ys<{BpOMnQUVOl z$*>~$w4G*RX8X6syMKTqe|FwXW1pmqT~4kkh+vy0%D5-?h{K^59vt)}$DB&+du+I$ zf^qt#7N(tA0+WGUVh@_E9$+846+Mliu=$9^kI|&PWA=0c>#1$u;zJLdW?$dc{q1Iq zaQPR>QZ>}GC)572E}P*e*K%tjPw;I>NZWt0(2xoN^@WOv9f0GShdII`FVT@W)7lPh z2@_+Ng4vZ;V5|dA74GRoNo$;^EAFIr(-t6anAr@qX=Cqo4Yg@z&$E9X=%hLTbu#YTL@cEttlOc^^q(BDysK{fm96fk{AjVeyy0sVUq;l%A{|`0$k`^Wwob2C94j zKFo6$-H+o>B~qbgcJOLm<+mbS&r|Lt-Rs!%SqU^>Wxh3S?E37ZteKVhB`}HoI%uvB zK!*<9#n}CcWFd@B-hd0IR~N?SaK{roqt{1B6z1Qii(97sQGW1+5hImNE}9KN*6g55 z_-n_$7J5uy9}DG9aGspbGXDnd|Du`sJlXX|E$^bqK%xlYIoH+@?A8bVLn-0aV^X61 z0LA|Q1u{=JnKl0dWE@oE^5Ypv|A7}EMk9&pneHa`OZIB@kHoAwnLMX18yHbT2)AcEZUMzZgepml&zhoC^?6k>$V?Dg#nYe~N7dIU2H7`3NSC$t4LiqC{ zi-sm|Bj))p?D)#h&&}KO@on_25ox&8+>YK?fXDag==-((us)?N@kz%~M`%GG{p?R} zdehSa>$gZhFFKV=e5dkQv`EwE$%#E5OOn;P6We)~j@+eQ+ZXmK&eY{*sjExXAy077 za2tfn#@K=R`L&ujO!J~m$CW^bBxBl<_8kL8o%@-)J-bYt6}{LgL=H(+um-TyMpbf>v z>)F{gGx7%A1DS^CDPR&>35DouU;LG%BB!rB>(;fygmF_oAUF3F-|8%^zDDOIO3YSL za#WMg7k$4@F=3Hqr~}pdv(lj###~zbBy1Opr7X`XlgvU;mYfWgvfkZ|}CnlVso`fY_fVNdG&c=UWkeqaU59XY?MBa*d zLUog=-nOmia=)BIfP{${gkBO1-wTRz9LosvU7+0N0Jf`13#T<@rGAyQSZS$N-#uVfZWj=B6@s|#&{nQ>n8?b6@;-0;naJyj%m zH`;#{V%9G&J7YX8GXLMf048rjI3n@OV7k85HCcaPUOJhmv6=4BL&;>!jln!^ioUl6 z-AWt{cRb^@+gb$dhqQgjc3=BUik3F^%7Jmk0}<=|wszPj;s9ok<>njarB3fRVH4@^ zW%?yWfsRrNMCY}1kO><1sp>_b_W!;QYMu-ojCm;nij}JL<+P}o8`&UM)tVH1Pwk!9 zT==1R@#ZWtt_B=E$D{5j=jT(&KdBy1A~~g_a7_+Z!EI{_scm@z-+2lHCGVBli2_l? z$T~b{`FOuCRTOCN{_pT?1?R^k9WS;)gv%JiLdfG%ic7Fq(Ke$tsdh4pFb5_ODvl&F z_Cqi>j*IoT#cqcw?~zvj@0*Rzb{3REY5jrOv#~Pd_w<#4n%j0}jvdVKjT>hltrpCd zXHCQ}%Nx;Nr zBUq+Aw8xVUq2W5@uaBi-zHfGzj@NmWu3423($In@=)tPh+?U$B{hpUcJCDZn6NC5-2}m91^v2q<&GmzyW*bW*{})pKpeCHMrxpqkmE!n+2a*>Yazrk z75)AYC^H#$kC2(w*8o5Un`KauVpOfIc&eH0gpTZD8vetmd}0ViQ(utu0Y?`$?fZ;Y z{63>A+91lx^FJlgsW)O*!VMxAmxs$ZzU{>Lm>N+U*{c;8IsFcE=MUc<$c$7h2a_%Yh}OUy&_ok`P9= zE=gcOXxcDj#;$G3UJ#L_@BSPHw}&s+x_+$60h0d46E!OqU?7^(Q%3SzI?CI!=v zq8M6YU423n>&-g~Xey654OSwfmo^YxxVi-E$$EJI+d#a%8UiHW%kXTo9EX4C(M;Cb z?gQ zm;O0kB8u4SDb`uZ0v4EF4(f&Hd{HhGQh!00OF`|e|CKH6bd&3mIbVJuC5L|CjSY(o zcVm?*gQrST_?aGdTP>OZU9(s(;8qfXM~$-6r2750>f__#(XNl1LgW7lCJaG`RwfD6 zk%bRMeuv^3!5g&E|DLxfKic6s`1~csq+l`tRTL=s05 zx|bCE;g55UbH1qRC5H?4ZYjY~LfCT|`n5X=Y2;Mv^?YRdNzXJweQTb9L) zrI~}*tqet-+55ntmCu>q6r+qX6D|!>t|sW%3UGw>1!Y6r%ov3f?V~f)&@O)3(c9d} zI0HR^6fYS~LGB^pvf0~)^z@5psLZ~VERhr4QRPRdh@aV!k?Yg}!Mcilau|y=w3Hfj z1d>*?3q^rl?ZmUAWL0};nJg^nF>td4B*rD)37<$K^5rMBm+9Uk)m-RXlmXjymAL~+ z2vall$nKUThO$OO+!dfI4)7WNEfMP*u>DDH0n75{O9EtZ4IH$u_`f&H%f8YJD;0IE z!MrRK*pEi|gNJPK?J=f=EVjJCpQ~Yr!5^`mV^$x8Dfo%XQWoA@s%-$S~MpYAmMUehodMp_Yz`KVkte&}yk!1m6|6+i0x z5=ylUvXVIZ;HXvN4mrA-`SJfaF7;GZug*~`)>re$e3KgMzzsXN{YPIalnDgb&#gQ0 zgU8a9)D1M!bqL8rSr)z;5&(7JyU6ooXa@rt$XrLGfg%o}-5k@zhXmfTM3$}%dl=3z z!OTG$1vJFx89)NM;K`~b7ywDM6Ive0lehRYGVpD48}nlw#ubF75Jk%Zkc0sgj{g7jbn8J7=!<>&{Zjje&p2u5!%WJ_ucPXilm_RL;?+R zXx)Jr-ph^P%1k4ix2|VS2+!}~AC{lD?I+n2mwR^S@(SxnJNSVaK z0pzsnCfTSo`uFK7N)0nia*al6JnYO#CTtZj_>AT$MP$c?)@1 z^vIn$nFxjTvfFVpfnAjxK}bY9VsD*P%pX~)f2TY<4FL&`p<=wcrU&)}n9;Jy*yUvk zJ_qe+YF(VOBMXPQMfcIIhZ6ICL-{+{+-`*6mI0pOT?`v1^L!#s-|58ioSP?BVn=H9 zjC&y0EwBNSK5!q=eDo&_!V06`7eT&8s|})X{O%M4pa2FtfrGg}Vv?kR0-gT!nqU^j zG6ubi9FHsVnT!upXFguv)m;vH9DfU!BqnR=H}iJ_!Y+38Hny!JLu7HzL9k2(v551b zKujG|Ip`0>=Es7!E<1N&9327t9v>dJlLJ1b8^>nxWI`^a5k#ZzUD--> zO-9Wl>6ZZO9RABha!p`jOklm96)mPP=nrFdXnDJvt)&pzk`}Uq1qxKjGVn%tdRxe< z`Z~nNuna~Mz&!?JzZO8WA+n`@P{gd6)j zkCm13Zu$-0n-1Xr`j?o{pk_u}re+|?5g;50A9B^i9rz)*6oJ3Ei9-mXKtobkLSj(uMQ1p2 zAX(Dei3h4IW@B@Q8kxR2%W|32wi3su%O%Y0b?H$tiW^~&W|L7;D6Ja14j6*T06~W; zmDN}xjOZP#8Mewi5F;i^j+W7A=hyLDg~>Ho(>fl?vfy48lr{M=;T|-v@YQCYFT6*# z-~rX($%kyW*$^0sp-wxd@bclZH-GH{!YRFy>q7*yi}evKhdEOg~1se z1ZoyKSwsKcm?0&hg#_Cu0XDc_b+*$MH8=l}73jJ715rILtksDgW8=-A(q2TA5hRoN zH;xHNzu@lVX#2s z;^;@C%#}prG+R35Xtf^3#FUbuYp?G?P-3#nhs_O3rKJ+aRB0dF3O zRQX{U3lRM~^zM&tV&`HZ&08^d8ahVVOf*``Vn=6t^0N%Dg?%*L3ImYWSFU)Zx8Oz> zBW~owI+NNj0%{Y+bU2o@y6fCq0^7*rL!MDls0>J!1S=($BpTPVV?Si5T8rLZFl#o+ zAtu~vME`tb+^4U;!QDN;(d<+o>XNIteaO0@^A4y@Ole8GT~EF8b6+1Xu9aV+W-S2* zvaqqYq6z5*b~iCxc(7B*D$*Hj&eLvKNWTwGg?tHOp=dyqPAp$VZ}3o(2+tDB9`Vz4 zv7PNnH$yDAX8}_@{&HA-uw)HCgJ+#PX5w9$HL$%6e$7O_Ow62d05R=;#|m_LY&MH6 zdlMm>Dxu(QBkk)mrd|CJR)b*_Z=t0?Oi-!HckxNG>C^EgnU6n72Hv7&_|Co1rjL(0 z%#2OUjNS}rW@fhkGj2;x0BOu1{)pEfxp|0FSoR{x#}L4*Pv9|44J3Yih_mo7=0COI zrZ8&U1^Lw3i9Gqs_G{xZvHU$E%z3wIS8YR|&bR1gQ0=36j?@|?i6v_yV-^S6aS&B# z%}_E5{C6cKx_3cJm~3EfrGnXjX0G~l<^42^?&j zfO(`Vy1=)gi+-CbUwmIC{Dj2^^E-Lkp=syfGN}mX|Cb_q%uB3+`mc?I;yY4sWi7{H zN5$({i)M{Jsqu!k?@0}la{;$8T0fI~v>`lv>=(v0PDMNn5@2W#h=#9^(>$Gs+-e>@`l;G^9)CEAQfE7q+cDyR{SfyZM<<^&EijD}U%2 z1c$=)ep#V*)xx|p1FrM%%!htzGbWHzai6+=aqUGtyPoXFy9lIfUEh6D$!?|k0yK_w zX^;75-ENmQbR8}^fAKFK(6yGlKYcs++Ba|C-)d`zctk$ZT6?d0x_{a!zj{>+XxrxR zo|(SqL|%8a5ctZYyX#s-6Xwb?S{;AgZt2?ccxUU&IAE4SNSW|R@MMq;&@wfL%F^lK za{g$|$z>O^X=elUfCGb(zU>sR31RI-6EjTi7?e4sZ-el=;KH=%0BR5Tn0A%iIrFAJ zS^2*Gq}kD!L5hz(9g3iYQHq5H!W6AU7=_ltIs_(2EI{f8D1mrfUMV!krgp9^Q>zX? zIZDpXSL~?k?9KmpP^G#pjQ_2oqi6qNokhn`sT>|^6$s7y#IfgK*^Fsz{y?(TOrQ!g z9j9StYbNAPF{W-kdVhLsPVcv{VbR+>c3u(eHD`XsLheqNLhz`v9rG^W_(?b-IK{LPE*@k&bw8@@?BT-plZ5QlKOfU zWedt)>9Z>>dei_Z9@8Xr7TU`{Q*YZS z%r_(DvEEYTW}AE6AL^7R=&h}G-0*V#ZTJ>s{&>0RUB>F^Vwd>_tL#iwlQT(n)A;RH zcpjty%095%TL!X^K#%0Jw`Az5yf)sXeGwvqXqVHF&(4D;)-Cho_+n0!@^cC*_% zo65<<`$x%&$&jVY%DptmFuUqryYZkloMF4o2Hr(HUv0e{>LyNA1Yh~)@}>A(J8e{p z*w2K`^)XCOA9Jrv(WN5OWNLI0)A9yfIu3&dTh&83vwWx5HDu&Gqc zBW|v3C^o_x?T1vDYl+iY4`Z z0tG9)9{nK(dDCuI!%Ue}XnB&cnTK?7V*#t`f%`QIIlvv>QkG@wMo%&oNzEx-+RxmX z=k{MHY8c%ciP@!NY+jyl3N$zizqO`>({|0xtoP9{hLK`n8WIrMy=;X1AMuLf{rx)Y zL|RJ)gnFr^S5d=yNxsHIJl1|@vwT|q$;6tLwtr2s5De9cf2Z}nHl1Bc{=)M;n#Pn- z)PWMHFm<3K;CKFE7qOkrLa&B(uRC{5b(=$v8gOWvG-%eH6#2_--geY4Dr$I;DD@sm zz4YJo1)WqhnLfqVPuHVxeH0-h)^yLnNnOyUg6eX=pSMod*`sMQ26|PHCMI%bdSYnW zAy$I%sOh7`C^-1)z%^+mBu<1wx~E#Mmj5uAQVno?CA`Cj-f`p@vyO&0yUsz0l4wXu z6x4zFt=gCRrs1_rzDEGMw2v8z=^l>9iQ1^#$0>nfoT5^&tN2UGTI|od$w{Z`lTW!j znLeU*kg*G>*E}zi7BG`*Z6j{RINDx@dsxm^LU+uDxPDjvrIj86U*Z<9rZL|g!w#44 zM(F3!E~XKWp!{P{$aBaF;!M(q0r7vj+?xn!gzJZ2{NP(f!r1%&cToU)>jS+x+Fe7O z@%&7ZvxYhz^{q?)g8Y96Lvwy%tp7(`UZDPW-98g3i_ac3b*VMao@5>&%v5dbLW+&_ z&#~vt*Uv7{!=;nnn1?uK-?J^hw%#gO@AYMzaR$?O;W1a>OBQeb1;0$`_8&Ozue`b~ zszTU68M&WJ%07T*ZNW*vq7N_nq16IAlc7^$`j2HN5(*XRG0mV%Uk?g{tm=si@ukAtMvA14Mbgb#U8n4sDDPkalw zNn}D_a6T%m`IfI56<>=j{)zsTZyJcNW2XT!Lff~A0nODVu|#S37t@yGIA6p*g4L<-E8ohX_&D7T3a79%m-!)%7lV@^ z?;FfivaD=qZlxi=Ly2n3bWmo(AU~LK<0Z+@7RA3tyWY##NNR0lxhev;%JMwX?}y7! zJgUXH8m`$!j98I82dK|YX9!Eh51M1BBur;;Q*9Z7J~{tqNG23O2;c_wy1x)|v^JDX z3iYZbMtwf+fdVUeFI*sNv){aS3K_xk^nU<}Kz6@*s`dv|F+8FB<_<@?qrKz)J4<7% zNN0kjBBBEqkX<=$|JJX9ev8cb1^8Q?4S!V&$TqgRk08+hOVjDswT&r9D?wkCgFlGM zABTPvkXL?nAK{=cN!%X}`h!o_zpC9c=u5KwhlBp$GyJb=_jjhRDiII_`gW8BSk*Rm zF}<47|2yjn)V2GRUX~Xl2%_}uC_u2P1r#V)-A54Ut11`-fxaD83s$v&ss^k3@IlWn zb-L!xC&>2lVN6Q5LHT8o8k3sUSbL-oq-|VIFF<#ku>elL`7WCkYqbIkzwfgWtU*qDauDrRHV>+fwPn_Ap z>gKg=)1X6G#E)F6-ZZ!>(hNa`GB|F>Tq@Mxm-_7?PhulE_V@MQJ2Je_2i-O;GOkev z?cq6)R_Bs?jn@6J)KzpL=$mmMt&XQbk53My>-1ql9y3Ya*zz{7&wA^HJU*c4#;~}< z@W{dk6hs&{6tkJitGdYIkQ)`Qu%JAXNKTo;Hzro^8nQ;1H}eWeotS~iQg4JVLT983V79z85S_-hhgOX;;%=xe_ z1!7kIQWq!b7+Wqh2CBGNeU zA^OfZZSCpa^6_SpRL1qnb>4Z=jd^rQM3?gV!M?J7U@$1z@3va75eNK=fP_u zrc5-$)U>>ZVv-Q050WWLiI7w(P2#Tf^v?Oua@V948%)ir!CcMyc1%Zzsy#h6y=L=M z8)P(59m)`nCzRNICui3zVH>M39y$|>o|d9LqCvA_Yg+^I)3*SE}PAXVat5k z*mNU<7a2ryp~z)AO9j88F&s)1jPkG#-FAnmtg&}HL;L0K6i`~yv& zKR2N0wR5E8%n-kNfd95LRw|W8`}-rR#@V17@k#FaX*%6kf{^_QrY!#fR$$-jW>*W= z=!4+dAR%(hx#qU5*7uafXkrpK4!M|^J%k55Q;@SuaTF7r7{IM=NQB@*3s(tb`cd4W z_PO-%2hYS`4LdJ?6^$|)lVV;mk7U;l9A-Bnj0l|UkNI^+@qPdGj;7KMe4s<6%!u6W z!puIVBY|U>(=nRhKe(`DaHY4oJ{Qb^u>-2r)r;<7_a*9li>?m42i=2RL|LpiF|ip2 z)tCs#t%@0&8$f?yCNZGW0ZAZZk48BP$6jC5kun2XonA@?rW^jfV`^|^FF zDvrkZiojzA{5%&0js%y|KdtR{lv?5tL<ycDa5$$bpFT62DtjV zdjLeJRY*Nu7_`meG?=2Rueyh54|;?I87XWe;?8>|GSY4RqNN}W+~+diPJ2d(;pPM~ zzR2*Q2y1#51ddG*_7s_-`aZI$MzNxC|czIBT}u-n#-r*qhckC>-oG^9c*liSaI2M|#lko(`oi`9-^ z^wBkEpDTSbW6Kex0(N3#Jv~XYvAnSih=C`ctyEe9c5{Yr>(4}3cP+Ejq(&c?sHikt zy}m%x<|Ag|t_?r!wybeRX2fxk2~~9DR$rzGb%MDDMQ<`l>CBP3hWU($JOay+=1ZD& zv6h4n**OAFjnCNjp=A?^0zSb z%{RM8EhD130R}TEE0x+|nMLnuo=ry6uBDid@YimNg#w-K)i>Yt^YI^|9n7X`tRW(a zw2a$sjx2=(6f4JQwDbg=h9wS*^~c^fhs+0#UVNhuv6fj(bNCIiNm|NmGvrCauk|pc zbN#XGMjq+q==<)tM#^I&m)5d>0IIQZQiX>XIM-P_o_-cQ&djqFi{)JJj5E@Axkt6w zG|47N(*F=oZAY5DDEd zUZ~x!p1>&K0}OWz-YLpc!sM6^RTo~a_+-^g($z{gNa9R!BdY5M!K#sRWdzq`YS;|y z7<0ow|6?r{!uVR)5Dz1(Qf5Y72)bQ#IyB@){R7z($epNRg-VNkD##VsTsR|+iD~-! z#~gjR)5UC=Io-ktMfM6Se^%yTeBHGa^>z2KZ#V@b*ZMpG%a3`XtF>-H;24CXz;bn< zX(za8CT|w>niQsD6pcxA>CUZRy^($0J#@Sju7_nIhzNY$HA0qFLL$AAOo2pV#3}Rt zzwRFH9~^Wp-n@Nt+9$&iJYQ#U@M9}BIYM?LNCnrb(4L#JbSIl; zU;ow;1sriNzV5#Gvik+XiQafnw;Cog$TzXKSYK~?vA*gay2U!U@5MT}?P47SEtbRX zt2yl4=LIoZsU%lgICUE*Kh|?a5y!Da5QWc1Xh^Wi1d(w5b78Nz2AYK?l##;vBlO9} zhX_kh)h%FFuyzu)r^U2d$HO6sRB<;0hqz^AezE?(9eS)eYuy8~YuHJ*rUS-fa=xk) z_fV-L%hi_*rS6HPUDOX|(Nm?aT$0=+!>N5_c_;1<^MhK@nfr4I>->snA<(5KY9U(E zN9`l^^IFnN{WA+@BvXA%op2_Vz$U$M&8!qpdBR82-rUor#b4f+du&N(`R4x8ZEjLd z!f&q=K*H7Xf!>Ebg%yoXUrTh2^~Rgl^_^WAOArj1uw=V6+~;h zc1D7XvIN%`1J^PHi;^sMA0owQWJDMilpDKUhLh4n0PGIx*#pzFS6ypH;Z_l@KqXF7 zf`$3U5MObj7eR9wEr}p*XINrqM=gXprbG%66ZBjr_=-G7V=U2t5C)0}jtX0zdCC&Z zbIY$ZC)o4HmI^YYHzc;28FbpWTMC6=pF`K=}4m zR|rkAW093ugXjHaWBBJk|JhA>JSPl8@A}6@F$~4$>@nlg20!oni=&}j^zEWho9*Ix z--@vvbVjcIZfxNV>%3!ay)D=IjHTaPO&s77DzAxUErVF5hccXO6|h^VM*s2RsG ziS?&WKoGFmp6yS$a$%G(Bj)&~GP4pQw(k|Eht>?catt;yb8h@TAX5FF3LGgK5xH;P z*nj4_Fmc`zG#B4)J0S|kSYbE->W5^l2iB-yHqNgX1jiGCegK=C;zpI%V_$m233#hB za&L8pT!8IPpLP0lCjZU|i$HAo&f2hK#fW9~xKV}$W{SXJ#d9?o)KNHO`g^(A8pDy{ zL^gYm=ACL*0M+C;p(Cy48)Zo20X$J@O9kduWezn`8Znmo;7v4n<)`hh-wEEbiDp?rOyz zD(|#9=z=%~aQ^d&k>wRfW1g71M{8Aqd2_aC)*tNb_HqNYW8L}PNkqEjhDt@*=p?~( z;vZ&kG#6$EYmL(qE?l-aJ8L1};|Z7*`$jZ5T6{ZUOgBx9Jmss$U(b(wySHHgb=V|Z5>DdpzpZ|RF+tc;Ng3HI5g=88833^_J^?9KZ`FG(t6)&Pzv%8)b ztLk->-*A?!C3Ey%$SyB8uR&XL$5)#$cfeH54TUMA;;hVUTD_lu7pVeK8Ps?x(Ev*t zft3j(sd=V83S_1UpMVYu!!?9dy&Bp>sZ)oCMtJts^{;MgTluQSw&JbJVfSUeE)Hd! zNRB8|VB;ea^>Zm3E?N3}2%}#UIuKY)4SWl@tKun*qnEG8_P zcF{WxOw1$jk??QLKu*<*n^`yR$Q8O7@{GmkSG{iQUFw+`J+uGWG5^`I12&gpyDs!$ z4^8kTK{6B8Bt3O3%-w7hF z2ZslH=A61Z% z5>+_RfcsZm+^VH%LW?R_FiIn@8KaE5rlBn2BISjAkh^F)dybL!^yV^CeTi)5p#jkX zqH`?Bk05x;sbEw|k_`0;j;-&ld*bR4y?OuE!2AsT;%BD^Q8K6VLg_2v@c-9x$hkY% za+@Nz#$a#4aOmTd{%mzAboHW-cAR${+;mRSfUB{2$y_?Ubl`g(>7~s{idXtPobMA} zeF--pyIm~>`@5lTL%NNqX#l6xPO3AcB#C!{tRu`cQ7yd4HmX)Wu0DcywV3pwytw+$ z()d2JJhj)%ae{vCIMhWxMbgV(v(wXEg>7(px`S* z92w4HuG_;uSvc&Vt3yjSxxv87_Jyhew|?H+F(=Z$;dI*rv#DO?Vi?6NN*5TeA8%@g zhV`)JvT>KesIohd$oX(cBZ?FAScwZPr{$}|->+W&Zd4D-+5WTqpPfvSjuzA8uBBT0 z6C0Vub8}D}UA?r_^3lYjB$QoBO$`6D(4|6UiVKPp&1fZ0t_Ub&hw%Sjc2X`?rx=P^ z>HTm09z$kR`@$gMqkXGvb@WV(3&+)AM{)blm;2uqjOB%4EWZ>nHcp}6v+A8@3wqvK zT8Yfk_dAToqz{KtaYowE15=s`F4T&xRNWBy>VsGXR<7bR#_(XjWpyX;s!Q+{>7pNv zjBdqL_#9k7Vr6S(=~3&Y0B#x=ZUI7TX>qr@qb>$osG3$F z1UCn(VCH(QV-$K2PSUjaItM;O^M#So*q!#wH8no>3^`d*zz3IDHwnE#4nx@4{MM)O>B_!d>7|e&CCrKeONn$-CV=Tu5jzzsLv~aBk z2_NiRDu-i-4)#X^4>7~P7j^c2H*e+N=>8!&+tm}wxtq zIarw(BF&+%xwu4H*0KuYfZue{F*tpCX5KxJmhB_nVd?bxm@@*0=0y>xc;uBHO}y9V zXP`xfouO~DGsl=!7Huq`As5c-mxIKTOeZ`O`{`BGarK;cA@-6ml;Dg-V}#LA5IOcd z8eA+09KT%eyYrtcV*?&Koir08(g(c?nI0zms*qZ-lyt-j+sM+bW;O{JI_y2p-rVMZ zjhBZe=si+Wx(d7hJh_#}jQ+=(1HUa3WB%u-kc3-P*aDN0GZ2F92^?C@(Nyf^+$BKE zTGF1oR94Pf9LHKDHKaA^qGRh7OedOcXs+nad3!Cy+$}W-`;?7|pvnmuRsqwi249_r z54^anMj#;(BxOX(bHN9sn-W3cikh=n_8}b%nWS3jxXw$GTNhS)CA72yD-+-}6&y!n zl;G%6uaQ24Q>;m0YV8gZOieTbnS zS7=9K_Z8svU^=X-%5t~lVpiuQU_LtcTmAQ|k9mWTOGnZAE_a;VD|xo(%Dd+(Yuzz& zO`?lVnc1BsGngzLn!Vg;p&x>^BR6S6BdU@q5Llr`=6)Wzl2=Ga)*&%ugIe{6nJgxy zY;4|a(xOC=>%)e>IdciNq(tp3jdopKk(de+0YkD!fFhGrt1i%ihLA8&&W&h|RYl4% z5k({&f8W~$M5{)M(hRNr&{II9Q)y$*3l{B|0_Dbh38TQ^CW$6o=3-u%nTd=cfy za2s{u;>V3sf64n}FE27sa^LS4JJ810E-YL7s=*( z?^H<26cMQ)*4C{x3?cATlcZDv%v^5Fd}uFb*+~Bz=9JqKoV%~@Zt2U`DOTe?e6eIY z+K;iq9<6;*qjVXN%|%)tc3t22BN?`9j)9a!T}cuWDK5HT;k5PdTW05J^>{ML%*D2( zT14pkN*Yd6xqtOyKomagchRXTtS6M=_=*Tcm`bKCxM14@P0-y!Y9S5eP30T!hnOZ^ z)FY&@J=fnS?pwR|*Iyrg^=-G+I#tFDH>5X2HhS6Gy0CB9fgAt~Hn^SNi#|xddixA= z4g=|L$}r}etjr*~5S@vWWD4=s%|`i;gO}gxa}m}QEE0A}tYaEwb`U?q=>(eC2YY~b zovT>aJlr=@ojw6U&M-5vAgii)l7yPobk4x2R`|&ODT}?o!(}}Q* za7s_n=vai=<-x0>Xx4+B+xBvR>^Ckmu z^V;+f0M}>F&|4Z2rd7BTo=ycFjTQR;MLeDUZ*+KY_yzh-a2!W`(k;An+wN~|qbkAi zS#MmMRlsc7Yt5YSNLb~M zGITAdqHLrUuA#cdg0y0-{Lw+CO7OTb8F49pfHTd3+Q&U~+H0flj(exQz1A<(F>Xf-yido!(1X=bLd~Q13*597mr*6h$%kmxL zi?m<3N^IsE2L}fSUw!cf{O`fRLG^!M92~y<+lw#0I{4!2ufF*5#g~6Oc=6@IS1v6i@zP*`dih>ZAtTzF&(uKim)OhE~ZE5lnn)zN@Ng<&_c+adPnxO)~8;p z>?hR1X`27%VfV#1-Gf$Kq;ESy$LOu~;q!ct^uYqR%Fg7-8A|wwMrc6PwU#Ldr2x8a z3mF|ZPhq1uf#IOeKgl>}bz5UTAxFrGTb?gPi$;1tHNWh~{F*@~zWs!cxOBgDCRki{ zQ#NW{k}0IKIcjz6cv~GbCP_*}tCMTctqvMy3@#&E9XEwmemf@Mb%yo$etxG9|2<%w zErc?W6eC;cTG%r0+5y-gXx-=PH?#DM1pPD3}+C8?q^WSr{*vL0loc{-h zUwu_Q|6jg*@pS&*M|*|}p}%wtJwv_o*Z=HTS*>#lA#p=W#1T3^KR)>pq+U=T%8t$Y zFQ>|PztHFL$?5*dYnwhxt7)ErG|KIMMGyc&}N7Tkz z-TrqROz!`Vhvqh($gWD)Jq?!c{}+c}etA&d|Az-JzWCy4|KCUZ^UwX~tp!Iw$N}(t z|F6GVE!_*cqLU-I6VbXjSSltO+-OXWQ1Mvnf~ZVrty?R-;0$*wr1h(N0Vwh1!>7+D7f~-@k98wqamxw3AS&Q2V>%i?;s%|4(~&7j^#n z%MAL@KRf1wE5D#$Nx{w`Nc=hzl#P1Pn8aB^+33{d!#00@W8y7bRCAi&BOkR)Mo%!r zyfNCgletanpi446LVx~=x|d{%{`#v`LmiwVIzm8)p;#;kw?%;0M(R@L_;+RtSGU^_B z){yprh=~QfvrTKcWc6;baQT|)&E7_Bvs>ly;{7NVDIjte9yxBU0Kg;Kfj$RcD(?;FmhvHce z3IB0`ZWnb+zvpkwfl%}2+%x63=VtGBp-%$W#oUAIv)Xb`?jVJ`FL!zur>l1#as-=o zr%H6@(#*dbZKEAzX|6?^Yj0 zsh~^^Q5&aeB@uf5(h>SQ3@RswxzBn0y~<}kyCl;+^qFx0I(k(@4Al{RW*8hWJNsTO zJDU5jx3l2o+njj*6T9=WOKFDnbO-M|L@N61F_6*xd9i(Dq}ihRx5p7*G~@RmDQ}Ju zmgMF~&j-hVsUu6yE-^QYqNuIt5pU}4Yx8DhV(nJ)w}3R@CM z@KjI;fX)4UOfG&N$5e_8+Rt$k@L&@V z+T0+`>2Kk?n}hL3P1>9(oS<_aqvK3*8R3M8Kvc&mZXme7Yzn8fMemk4EQBx5VP!{7 z*=Yaj5FS|p?%WHDU|sq0=9c4UA|Q|LdW&)Ov=~hmLqa+_J&W_AYKqa_p_HOaj~i$q zk!d%7Wfk^cu6M2&8xxGW`6Q2H8{>K6r>$ILrnt7Fu*rY>Y8}d3d-f~2Nc~i9g~J{0 zz&h??@?UgKVxodYKvwJ^5p`W+3>rolms{}i=FZjgQdy+NE1fQS{XW+^<#ER)0xD?l z(=L4An1U?0K|QT=x|`B+B(_<+i=qWDyD$G&w{;8|;vr9yOXWKMv`eex)d0wtqDlV1 z%kInWfk|3Ww(;w3EP{K;q-n7Uf=nWsBC}2V&%gd^Ba{d4+WOFDSbpYHlf(uIG9ou{ z+wEts`SVZU%ZtW<{`xB~QI}W#bU6YpiHY!a&r*i|=VkY$t?VF8Zv8f7(}B$N8WAY0 z(KZEEyRGNXKX8*=+f>K9HnqtKim<{7AAK%uiD6c^8qc2x+OG_&k=|HK`_DtB{pZfr zuLqrPe%pQi>;L=LZ_oew>$5i6DZztgNb#OY`QzQnuVgfz^8Rnt{covS@|qXGE8;(2 zzC4_}|NZLgr}+PSY4?8ri*iouovJZWrV6g6J4lL8C3^2_bGJT9JR(PCQ&yQwi9o5$ zUve%P3(tYYFZyap>G(T7KeeZX?EZ))YUhlms3TtCF2PbJWJkey2K|JfO0qs%;0N-F zF_+&I!0MtR5u(lRlzAH`fMzN4sJ=qLKp=$+Uv;TpAwHpM?$7O^{6T-RjoKn( z$MT~j!u{L+&?)t69Unci=}PjJvh3!4YBDBOrg}QGn;SEe>lX3BA0$$H-nONxNb_fe zEt6EmjM2$!RJq*jS2&@u)8D0rYR%b~hhCklJM8BFd(p9||6Ttjo7$}n($>H5BzaKs z)V8%1@*ha!w~77#TY&s`_{Gw~TK1C&)Qjb^fhn#0W% z-I1k39CFgyWSsC^x8;i!pA`q%8~uTU1I?PNoThk4+Q{mz{%}IN&}A-Yz;7nvCBjb`B2Og~4NPgfH%DgfAM5@I^ktxuMu2z!i_o zmt}q={;!BW4U79eL>eo;QS;f19+?!qWmYQ_Y9+z`z zdX=>uG3Uxu&4cRF@HcyZ<$o;%R9Q@R5^3k>x@*gBvzhn9D>#u9%zk{dzPxsR9UH~FQDb7BMr~uBXjcP5K)_hUo6FzJr8ZZW zM@vv(?a4>b&FcYq54)m3wU4_Wix+HN04{*l9(mtYL`*0%+@ai$!Xy8}!8bY82fqA& z?0tWC+cvW3|N0bow7aoVi?aN)*L&T4Zjx^O+9bZQo1A^keJw;n5^9QI0aA|ID57=G<;EK$Cv*tyDKma>6nPr zM#mcP3G)7TX|J)zd{P6bX4Iw5-H}wcB=0NH|4PXJd8M}Hxw9~J@Twd^R(nw3SBJRF z5w%`A&!I#VIs%E|(CXCuv$<88)Bjv|IK9uxV8BYI)IY98M5U5;?QZQ(p?evfIpNu2o>wxZhg6Z_cH1O;d-n^_%3&rbD|MvS5rY z`)0ZYxC`u9=8EGIr5sc~qAaF=m|OWObu%PyE1~0Hvpy+6W;n`J9dc8WP2`!X#e$_? zkq>KM@Fl~)Ws%q5)4tU8+rT=kG5>bvd$aaKHAB%_>XvbIYv9N%^AXr?M7I1ko0a$BYx9A9FIJ@_9eu#FTEM@ra?n zp%IRvAr7vDF3!iHFqV!GSfoGAOsLUn=8US`gM3vsVHs&TE5|f#!i!5hUdEW{KUD!x zi8@oPsVkt0%1&tXE+M>cZYkUqrHRRXm7A{ zG(6hb>1zc2G28fQf6)7Be;?&Ta^tUl`+r*ye)V;C>%Fi4^$+`>J$QfG`@gvN=lkA& zf34pY54umg@{6yRYPb2DMJvZTF?@1-qC+7Y8s>&T=)?cL{8RrW{#|PS`JXhl|2&8B zE;cZb56s}7=KQwUerUA++x$QJYT>OMKrQ~C{ez>5|L0)mG5^QC{O&*h$3MYuof0HP zr({ql->6H|2|EBv6=RMfJ3+|l`B`2))js;GidxONx)&>W2<~p_lQ8{O|E1rZGbv`x zJN;MreCpgfjj~|o2T?v~-cSZIMy6J}X=%o8e=YmTzwV#KsgK|hs0v$*qd1!m3GbRv z75y1hUxb3UL!#;xM^IogWl*S?z*)>3Pa`XSEI;llDpYb+ayBJnQaS2+E(vF!b6rkI z{@R56=7nR8sj(<1zA`yQTvZWoe|*vsQ(kwuy7qFBj)}5?*ImQyR$DdSnN=NFGq3a! zn-z-paw47gFtcR|uirt^@g{%>B@&kH*po|5>aS`ly-FXlX$7AB@-Hj8Uy{lIq;cv( z>lW`u5yR=>e)+xW4p_C?;YZ10H7eU;zt_2n>`%E=RCUCtlmk*lx|}Bj!FjfO0jXUu znAq=g4aHN+WE;y?KeHHZtLEzGH!EL`sN9Z#@|cUSJt*Sb>`sFo+Or4?0n+AH^gJs; zTam8S&llc@xdD0aoVq!21H#kZ6vucBC(=5g!78~1()04C3nb_`CSgZ@Ku0u?$`_PO zmfNYW%&iGyf8KdRMn$DCyEiGRLKcXACg-iMiQM1FC$wjSX`fsP`=tUcw*ey3!g#SD zHJC3(PFn+CY`rY#)kLW%Q8mHhM>0naXs=8NUHV-eg>xz9m-?)wxtoMCjYJOzQ{r`P z@%Esve!#Cq|JQjy@AUk4f3RP!|9G@}_;~(%FTeZO|1D)+q&N;S4|P53Isv2^(6lVl zUDqbJRv%S!(Jqesuk>NZJ zuF-lE5>0(E(IuRlJ~M8j;=5|U5F8Z;7Wh0K3^dJ}Pn2W~d&7CnM>-=$K6Z6~(X@Kj z<>@=UyzoMwS+aN7dCiB^-hVEKg@~Ug6{|Hr;n?GFo>lihBJ#)@Jo} zW>Nxj=5WC$W)@Lxe`fxaitS8YZTn*K+%L?$In!2|u3C_J+0b$gqD6rLuDYa&54U7l zjOf(Vw+97Os-M9GVWBg)`A)rkJ2$md1;i|H8!V6}Zd&U_0>#RfUzR4FcLaqHC3=nH zRNC7SV+mq2!jS@I%JeG-y$*ex%9hH0*LVsV2L#dd38X)r!=0>Xp4aMEwmm2K%B~W> zZR~%sjYt~!ogdgWnGwFN0MV&b^E6%(rE5-gE&r0xwJtXEj%ummDalmM$&{ox#3|OK z(=*d-+1F8c9pV(hT1Hz54X$o*y3vxfzKcGBkNaPE8r8~6wSX51(yr<9wnBb&VcjjR z!mLwLttxdMtd9HmYyP$9|B5MYr~bF<|3^E6vi?8VJ$Tgr@8fsx@t-d~BytmwTTZMU z_cKM@(ZMbO^JOfQ+N%P+bW_{ zst+O32^DBdlj`}a3)vPO5T;!7>**&{V&xFxz64zm*Bq zDHVx>`4`EH&8}3%jm7XR#xy2~>_#6&7VY%C9Ib)EA8)lKYq+P}cNJYjwSB7&SWzT$w@}v{nIca}R1&jk z7NxXTG_uS}L}L`N=@4$8DXnmsO&Q?S?9BGKRbRHigD1D&rE%j%21&8>jYIo7;1f}h zXxZ(fZk(m*Zm{r*HRac2y{Hh;@2*6OTk3x;`hSs``4%=n+x`E;qe}j#oyYqB_w)OV z_5TfT!O18QX&-iKozw&kvGxjLG^R5Wql6PEOmI0Ng6O~04liZe5DOZhl&CNpsjbH> zMN^_(U}n3f5)KQqpsC7P!SJewa+$Lj$E>Beb`?Y(PI)=e`iMeY$!r+Bl)M2aSlbl` zJ71wK@*yBeibygcQ^Il76Di|(OuBi`n}!VLh@pctiW+Slyz7}>3SA?~Jmd{_cBUTk zrewicL%}eSbuhON5yn~&W)ax36Y7}K~2PJU-vD*l4u(P{w0LuS(QyTDP@!l-Hk@1qhKjt-lruS#zc(rkJ|#5J_F zVLmw6Yo5Uh>Jhfib=p|m-*Gr)Xa9CA?jJauvU9Woi+@-J@m&}3{hj}~9gn-<4hQ=y z@c8aZnD4t?eX~dmEP?r<3vRHx`_0m9UYG;=Xd#!Fs@!94FT^4FP<~lWFjc4P>tq<` z@F`?Iee#uff@lnx4txaaISKQ7SDZkZQq{$l%H^@`p{*-27dZw{Gd0hP(4haXWB+f_ z|5VzTJB|My9PRDzSL442kNV$z{O;ZVn}>fZ*3xd11%4C5f{v@i1XN$>{6=+QXKowh zX{%J)qRO6Dm$CSM9Uc!QAmx>%T#o*$&Ix2dnQtS_?#2JtM%vL>KgN~ z2*6iq7y*N?X*^=bbr*niLK-7LQcg&JifLTDfJxjiqgVX`O)Jx3=Wr_Mcm{#$Iz%9v zOHqDJ&;-xqAZAkfmnkZw4(^q8-Y6Rxc>$lcFK?L3oJS>q;}hgVZ}zgSSv78@ z`^vg;zvw!*{i+aUk1uhOn0uPmy|}$69+Xp6?eTZ z@*)zC(}{-$J1~b#&LP|(a8GcYe=oc|rk8$&V^Pmx*(YiypA?R>>j}|bq@2c7AZZLq zQZ85vCCD|4L4NEK3iTkL;(sb&-@4GsLdj%#Gx;WJgwi%5{`gp`VB(J`r?BUvcQlF+ z#CeS<7pcnoNK(S}g+RSNwMC^+Rda%RaKEUKmJ(<6Mvru?c{4;D$03{Mgi~PDbfO;m zjAHTlCw<5wU{*|7X{-X&$5jRG;IyWjq6`g4 zlDq(b>I(~zXV^qfuE>00H>s)fqQnL)2r9}fRLDCs35t{?>~;{^_0f5rG}a7tMsZmJ z6~vRfQ6US3LE4bV6@&}%hfB2}{c?GTZTV_zWs;;5tUr*vRT?+Z0x&14Zdg0$Js-UR zxf9JTQB)$A9`PwGPc5dZ6xGwGWvWO>ppI4b5T2+PPaMIl5Gp#BV=K^W)vc;~daiYB z=9nFyAkRa2&O9ynN{}7J^`p}N%1TO> z(n$DYlKx2M-*YyVTV}4HNZ#_0U)onK?VxhypwcaTv#?`mA-n$3vRyz2svX0^-qrLx z$0-IwHe&25OOQ8{x{)!1mN?PQ;p+MB`k@4ADyHQs;a5vFjDQ}i8<=|$9G|T$LUdv5MhBnQu z+H*@tlvAVE^S!Ya%ygKn=rApwLBq2!s#z-5#8ps%{Khv*?p_^LuR0ZPYchkYjO+D? zScd4jGQ2nAQY%&5bTM@e^9Bs*+>NH9w7!A5z_2;W>N;nPBpo_M$ zB&oLgsMDnX>NTwyXfFavD?35c2V_h>yiswur&071O~L)>y?_7Cq6OqL{V4Tvk#cmf zEO0w-sFzcsXko3dk4Q|i(I_G%fwpLzk}j{ZX+1U#M*m-Sm6}3ZFK?e96ACnkPOEZO zSW5%11X0;UYzeRPoG$-x04} zlyEYmEE84R3EM`vSZ1-SmTimuv#s70xx0Q7^>21R1| z#W!L~T@_v^{Q_`=gFg$n@4U3tU7bO?e4?ilMpr&_viv%4PZoc)@Q@sYX7wxmYK!~< zfdEdEa^_#N%i3*J(!2NGd(SKTFP8jPSvvKYHIC*{s;~3cBL9oT3U_z^WB1@-P`&^0 zSpV@}exE`9$06bQp@%wC%1@B;xT}Ql2~LDE(nP?LJX@juL#Qhtak}WvWldfXlxe?uai(iypc_PtM^a&yfq+)rK?ZRtcW zijK}#p6;#dre>=5fJr2D2X?WCsG+0-PI zb7t}Y`5H#TNkBr-Q6T+sY)TFS;U;OC9QXUvBGJ09qogS7i-gm0Us6i=lXMzw0PT8m z*}=b-S{Wuu7OKsX)x^Mq=2vb}k7XHJqmlD-D2l{s=Ao|UplR(it$Nv4s(6sINWK;g zs}+fX&_|tw2s*49oa%Wc70<&~S6cReb*gx``Ckrps`dW{kM`gF{O*1KSIL}dEK;s+ zVM2(|n50D%jP}Gf3opf$+NnGysb0~G{cWb`v3?5Q^vuI0^CdKNY;D5aM19xe4EhOX zw8Sca3-7WVjSjxCX3+QCbBOvQ7TDF&*TdiCi_KCvLP^aida8tQTX1?cfg*{@!okUm z5|x-kicYT2wAe^p5LAA1L}O%BuFZys5GOc0KS0?sM==F5E{9kzP8J=FUIIe$gO z)TUPVd!Ig`1!pMgSk2JTidAzC))3>mr9QcUB?J-R5sF#d)2)|bx#rNSQYiNonGak( zgaGbUInn8_d;vfYAHoLncbv=!7vx9z@c0DjKXogY%j~A*NxoT_SG{8Enr#+4lx`3B z4Us~13}f8`sN;}l6B1mBY>KdD3F+zajFklG8qiY}0Q0ms$J%*JA%&V=h&=f!x*mI~{N=mTH?PiK{qq>TDMpV%l9C`LA=;8Q zm{ltN)2CzkM7H_#sk@D|jv1?5-6~T!#CdQQkE1!_L=Kb0`j!WtF&b8>4eBShQX)w+ zj&c^Oi_>sDGrye~vOxHn3UEg=%~HlGjzk~smq23io`&9&(0iJCgp0-ARF^3vMFmMy zvzzBSfldu2agHK8ZQXKQWAZZDo&sIA#!?)O#wb-qv%9L@{ly17O(N)}8brHFH-Vt% zDkPbk%K%)LpM!tQSd>l4IpI?(g!!*;w6UD#{>6WCryn;*>@Rb53U< zVwfvsG_F1}>m6Z#=m!OxmhdvOe|(b9S+80$JU0;S2oL?G9aRYr{Dvv0rG?s!d+_5%#*kX$Lk`urVs=CCG26 zsc7MskKUHbMmzJ-&!9~fADruKmzpx4*oN>Td7gy@# zgs{}!{zDH+UTptcH`V&T23QCjha9i!3}`$59qg9#|L*P{J)ZyG%kSRpe|=SuNX1dH zQ&AZ;zj+9vND2|Sfw=I7Rn29}f>CpTO^3s#@OOUO($;`wH$c*j_^`|j4J6s2!}rl!p}Jw(GN?3xgv94eN=*Et`yssjjgS{ zIHz{|bnm@_ZpgTD9Br0!KS2fZauzX&vF@6enjoquamgesU;P#3)9O{OO;?87cxSqX zdA&Bo3Vo^iuKogaVF0zu0Aque?l2p;HFvD*>%v)cx1a(;_JKwe^SPDBM8&j#VF{8| zpRqGu%K5fXxV0`7lPGtA0eBRL>$v(1Vxtx9o*P1%qiAtVIafddQ?0FXo;CXxaILSR z3UX;c>za7Ia*Ls?Hupxl)ld5Jli?cN3unQO4QQSbGq44;cY+MyMtOZMh`JD$+tS@! zMppB^63y+cz-SP;uAs}pKls&W529tx%d4zzI^8!9*R*;3E%95y{+nV>aX4K4D7eM` zJ387c)qmd|9PK~afA{kHeD>c<$xhF|Tf6mV*!02JerBMJmLKG-xSiE!`nVgLuZE;6 zS$yVu4Gw4NA!X^L*>o(yksGc2puuc>!&us2 zI&$lk=k!_wM{d6+%-n*J>Bp_#x0|nvzkj0+0VInw4X4_o3iW}S#N}CPG>e^v&8D&D zk)E95HCx9H2JUD8Nt;n_k}t5raCH`P&A}wd?Gg?(XC3QyLKsR{iM&=fMET&w9zL+6 zBYiw;Ez}%{7IRs@sG7O2ru`C3SbTK{WU9kyF~$B}968JEfNS&RtWgDh;aHsr1ksLeFuEhgg)q5B1~wawuI8bFsVXN>cAyA)RLF zQ1Sv1qYH@4)+|d=NGY57I5BMcu!FTTFdmFS6V8n!{;# z#zCTIcgQ7N?%pR?+R+}APfn0@371?UmfDR+mbaa->a0Da)TrKO!1&8pj7x-jl$dEMG`q1M$G9?w;; zMt^a$xx9-omxgy0$92=+3jUvjiFC}#>Q11R_^-iH#s9N=@Oc04etw_N|8uU`=`Nf= z7NElDCJSNsX-|riTRM^*oIK%g~l3dvxSv}c;lwB zcm%FGT{2=CYAV;Zvih;uQ*la2J}mK-uE}FN8{Ap{Y`&)U9dtEML_0idqf>-ZwM>_i zhK&qb?xa0nw%$@UX>Yg6b86vI??dXk!&zWYH}&&y_t{ z58HiZoE;UFaK$NTP%H1y8M0pUVCfOviS#I%{+u6(wo4Gum8(m00pB8fjU^S8vDg*d zWYddUHYe7v>_YWD-hm{smDQVx5?9^*g1NYMJnNHgHlbIPbY-Y5pw=w!?B0@_i@aLf z_6ug0#xb?9Oan_KrDbmO!=iSp`j1!e|3cF{i2pm>-#IMD|Lq?<*8jSf-+KJNH*x^K zk^FQw*MAkOJ{aFGpwsO3h1a+9_^KZ6#@SmT=5lUX_1SVB*~Wl72gntf3qOIjB|uPm z40HM?33Z{%R$$gA{>&7|go+T&KI~L#n0#*6^MD$trEz$5K@{EAuc{xAKWc|&T!T&S z_C~#WnK-brv$#GAtQsU3QeitES0YvJLTo3J-E?X4I9UEH$Z3{NR-ezjs8L(==j@ivzHL_oH+H;ooSfbJ zm+!c4b3-WsyJ)Yj-xOAJKGnmxrDdjoK1i37+VNEJcw>mE(JxJD@W|+m^A2sSwP_*E z+kW#jt8eT%TTFUYojgBylntXF%Vcpuv83>6xfiJ8r@M zweT!wm%Z~Cq3&*9TPx^XU9}f_4Z4@?Kv(I!;oeckcCq?FM@`+^E7q!^_E|!#9`tVo z``_M@R`LS0*#G-Sdu987_wexX{@=a)K41KoHiu;!F!YC{YU?ZA9ooafe#YX_&W;o= zTV<8cGX=omk=JDF=fMnGMe6PBXf?T^x50XQ8|1w$qw+Orda90eEp6(CP%Rx@ng*0u zo4pxjy_4f|LX;|^Yh@a&O?gIBEK-kPj;E1x+p#eA8vH4RTG8lFsqa^yF^Qr4Z`fb{ znk7t8d;hAL9-Brc#3`=tqB-ti3BA79s&t9!+&ktNOzqqwXgsc%3k47R`9wF`MZOxg z#XYN;5jmIXx_66Ld;6Fg$KsVs6tphM>AYvREwo|lpO1^?eiu#2)Tls5J$HDfXs!uaW$OPJP^>S_0^ za?ZUu!}*O-xg7LX<}?|T^jXF^i3_Kq=an5dI1Y2kp(RGie`0!Sq8fa3$zH^>x0u^O zk_~7SHVnEf%;i8eQLKIZK7JpYXvD9?`?$u^QJpKy<;-ac_}zv;FV_R0z(4s)JgJJc zyofOlL-eHAlWLJPw@x-?b1elV7B~)lX@wQ6QOv&e%n-0biQC#Wb^5kMW5&r^ zbj%k0f9K#}$JPG_2fIg)`v1NBHqbdvrHm0!YaS+DZWu8dW;B8#+X)V?@R$g{vwo}St7Q>ekC6o}3A{rCF<3GRn^+Ik>oelI1xD>s8c7a05MaLi0v=9GP=y&|#pS%zM zH4i4^zWk5*Q_SLi0cePWt1JPlMRcC};yUR(^@sSX^VCnLN$2VR?`)vAm{XPsboTs( z==cd|zmp*C_%tNAuiA0;d&i%NfQ3ZDrqeMRu_z?GL#N~ZgY_`ft^YSKPM^Pg;ZMUg z_0e+w>u_iHsI>m~_jivT*Z+O|Hqdu8jq#M4)$kJ?a;a}TlPuBcoT6WTAkox){NG!q zNWR=Dd@)hw@l%%2K=dQk^jFPP8?sFoJlA8+vP6m$#b_vEV;Z0#Nv{csb41j4ey6js zfi8dg`|~%Q&Tqf{CUxRYND>l=OD7SS(mXI&u^!?|+W6L@JtjGe8d~^sVWB zHt1Z@I6Owu1gGPdIO$ADilzE1F;{rk*gW!u@JCq`sbEGpk~UvW=SsIh-VY>-7<$Ke z6nYAYpBTH6v`rbx1VJq02q$@%p}_3G95=wliW!Mmf?{&5xd>%akykui;o7d*+Rzlocuct8 z>9|bjbO8I*FF$5Of|EoP(600oKP0ohV)T$C5t~n?GAfm01s?unBLwT|nSxJa6hxUw z3D*pN&Iy?Nf~G`tIz1%&<1tBzKm&hw@9R!a0oe1u@pryf-$*-@NEqC6z#> zofWY_+Fl)m$Ok-4B65uK)z#@(tFWc3H+f5-o`Nq|gAG|TWIrC$_(P|Y;&B^T1t-O0 z8_d8T9QuP^NQM;0y}?e8AMSNJNft%tETTaxu0ZV39AO3iJpV91>jK5<$!TCxrgdVutFL&7C3&PBQ$3jx@K7vqKIA* z`9=_e$cL0;MB@?TQzatQz98&LQip|-w@+h4W0B%GAR5?^9CtQywzN5J!x8*0zideQ zH_ZM9vZf!|Gtt>VYUmmxkh^kSolB`NQW6KGSXufYxRp-k^i;K%O0R+C+eDCb>~uuR zI3AN{5f-A2H~%?dLOEOt1XJ{uMcI^~3k3)Pq-}IIGQ8*YylrH6^9r^q&(ktDq(b5; zP&kL}Qb}vM>Ct%XVC?n0P6r185#l8aNgKMS&=O5qSOgq5;_Y`>jCtb+ShIQ1WZ#dJT=(>R{!j=fIfq(*l z^ahw=R<}9NzHs7*3bqB!q-B)07tX{ZX$PM(*y&tDzasOOIFY*FaT%6=o~wZhWQi8-k^_h}cRM%Te7xHnJNC<-SDO$b{DXNai^yB`smV z60uB5s&~?WzSeP`NRU`iFo|I;Lhc(|MW8Xl8u4u;*p#4@PKl5Ju5k>DaxA}AnjKdG z2?-N|4rxTwx#|{lzX_pSl&K+A3p2YLg(UB5TEX*PuUD_WYO35^cSR_|LlWs73Ma|( zpQ$NA-D zV^*A>UR=C;{pNZ80x93(_nb|St%pbx8UoHn?wbYVGP9#btR2ObEC}^C49jN|ZkJbN zzOctD%QL-fhx)!%5!m?Y6VR`-VINxnSxYO*UHomU3B9!sF!cg^_4@L~g`a*%9h>YH z2gEx&_j^RVGq}Ma@v=E@+X4e`eOwH4b2gF^X~cLScTOhqBYb@^9L^x5%%V{Qx*doz z91&?wS4?RT#ZiQ$_KT)-edYs>^3p_|c;0r2mM5ME9RH-$bV*Nqxr0r!(0`R6O5XYA z6NXN{>d1$L@f2BLPByosT^OVhd~8nadLZW#9FY7jals3y$I$PB#S*;}?=Pso26sS$L74O#CrTC)p63ACh^s zzjQ;SIL$tQ*{NPa_GT513thI2Gz=|p|B3**}}#J2#+sa4K87{3d1w+d5vR}hP%dDln3 z{6IKa?C&&wPRRo}p?Xj~5bIqqdjlLxrV7!N0gVb{7Y|vc)|G|VZ|dOO@AS~mk_t)< z(r(q?DmcyddxBpTe;TnqYy3 zQh8@QB$Avg0VRRko)oH8jOq|DYcrJXMJ*C8W9c5g(MS&ulL%ZV(|C`JKx zLTRztLsN@JqAeET?Gi)pC7g^1H-hRHHX2cIIzqFM1(~#LV9pjVp4slNv%O!ZbgU-0 zzmfm5mkH7fuppwVmx+EAkJaRvF{BL5_B6NrEXXK}P(09>c+fM8>OBts) z5`9hti)N%J(c6Xp?)4HT(q4gzn(6+xHpFE{Q~SX%V&lGQLwa%~&}VP9+e?}L=U)F? z*w%FLWygxp{9C}1`QPO>wvWE!42J=mssN*u@G0`lGf&MBOsshZVV!c$`;1E=k3=>U zG^ChQNI0as3sDw_Iwbxy!NG(WM7EK+y|nA^pe@`#0URp1po`fnI-)PG9{C{do53`8Fa{IR!sR;VUG9bPCFW-?<>f>D)NWlv|eu zD8lhL!()QRY({tthxmj~sZhHuj>Aqwr!>_vwK5$4!5&vX{vLmizsKL>Z%x1d2><~9 M|NqO54ge4e0GIjV3IG5A literal 0 HcmV?d00001 From 680b4d701f827cf7eeb9c965596cbe7db09f731e Mon Sep 17 00:00:00 2001 From: Smorci Date: Thu, 18 Apr 2024 13:16:39 +0100 Subject: [PATCH 03/13] PM-1438 Add service account --- gpt-survey-summarizer/templates/deployment.yaml | 1 + gpt-survey-summarizer/templates/serviceaccount.yaml | 12 ++++++++++++ gpt-survey-summarizer/values.yaml | 8 ++++++++ 3 files changed, 21 insertions(+) create mode 100644 gpt-survey-summarizer/templates/serviceaccount.yaml diff --git a/gpt-survey-summarizer/templates/deployment.yaml b/gpt-survey-summarizer/templates/deployment.yaml index f597405d..cc01fc1c 100644 --- a/gpt-survey-summarizer/templates/deployment.yaml +++ b/gpt-survey-summarizer/templates/deployment.yaml @@ -24,6 +24,7 @@ spec: imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} + serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: diff --git a/gpt-survey-summarizer/templates/serviceaccount.yaml b/gpt-survey-summarizer/templates/serviceaccount.yaml new file mode 100644 index 00000000..75326089 --- /dev/null +++ b/gpt-survey-summarizer/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "gpt-survey-summarizer.serviceAccountName" . }} + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml index 18033d2a..5db13041 100644 --- a/gpt-survey-summarizer/values.yaml +++ b/gpt-survey-summarizer/values.yaml @@ -59,6 +59,14 @@ resources: {} # cpu: 100m # memory: 128Mi +serviceAccount: + # -- Specifies whether a service account should be created + create: true + # -- Annotations to add to the service account + annotations: {} + # -- The name of the service account to use. If not set and create is true, a name is generated using the fullname template + name: "" + autoscaling: # -- Toggle for autoscaling enabled: false From 7776618e42fe68c775f18dbbe6e46d998c1c57ab Mon Sep 17 00:00:00 2001 From: Smorci Date: Tue, 23 Apr 2024 13:39:34 +0100 Subject: [PATCH 04/13] PM-1438 WIP --- gpt-survey-summarizer/Chart.yaml | 4 +- .../templates/deployment.yaml | 65 ------------------ gpt-survey-summarizer/templates/hpa.yaml | 32 --------- gpt-survey-summarizer/values.yaml | 66 +++++++++++++------ 4 files changed, 48 insertions(+), 119 deletions(-) delete mode 100644 gpt-survey-summarizer/templates/deployment.yaml delete mode 100644 gpt-survey-summarizer/templates/hpa.yaml diff --git a/gpt-survey-summarizer/Chart.yaml b/gpt-survey-summarizer/Chart.yaml index 5b987159..f741b9df 100644 --- a/gpt-survey-summarizer/Chart.yaml +++ b/gpt-survey-summarizer/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 name: gpt-survey-summarizer description: A helm chart for the gptSuverySummarizer -home: "https://github.com/MinaFoundation/gpt-survey-summarizer" -sources: ["https://github.com/MinaFoundation/gpt-survey-summarizer"] +home: "https://github.com/MinaFoundation/gptSuverySummarizer" +sources: ["https://github.com/MinaFoundation/gptSuverySummarizer"] # A chart can be either an 'application' or a 'library' chart. # # Application charts are a collection of templates that can be packaged into versioned archives diff --git a/gpt-survey-summarizer/templates/deployment.yaml b/gpt-survey-summarizer/templates/deployment.yaml deleted file mode 100644 index cc01fc1c..00000000 --- a/gpt-survey-summarizer/templates/deployment.yaml +++ /dev/null @@ -1,65 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "gpt-survey-summarizer.fullname" . }} - labels: - {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: backend - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: - {{- if .Values.envVars }} - {{- toYaml .Values.envVars | nindent 12 }} - {{- end }} - {{- with .Values.ports }} - ports: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.livenessProbe }} - livenessProbe: - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.readinessProbe }} - readinessProbe: - {{- toYaml . | nindent 12 }} - {{- end }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/gpt-survey-summarizer/templates/hpa.yaml b/gpt-survey-summarizer/templates/hpa.yaml deleted file mode 100644 index 15828e21..00000000 --- a/gpt-survey-summarizer/templates/hpa.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "gpt-survey-summarizer.fullname" . }} - labels: - {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "gpt-survey-summarizer.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml index 5db13041..cc7e9e74 100644 --- a/gpt-survey-summarizer/values.yaml +++ b/gpt-survey-summarizer/values.yaml @@ -35,16 +35,25 @@ securityContext: {} # runAsNonRoot: true # runAsUser: 1000 -backend: - # -- Environment variables for the application - envVars: {} - # - name: FOO - # value: FOO - # - name: BAR - # valueFrom: - # secretKeyRef: - # name: mySecret - # key: bar offline: +# -- Environment variables for the application +envVars: + summarizer: {} + bot: {} + # For each + # - name: FOO + # value: FOO + # - name: BAR + # valueFrom: + # secretKeyRef: + # name: mySecret + # key: bar offline: + +# -- Arguments for the container +args: + summarizer: + - summarizer + bot: + - bot # -- Resource limitations for the pods resources: {} @@ -68,16 +77,27 @@ serviceAccount: name: "" autoscaling: - # -- Toggle for autoscaling - enabled: false - # -- Minimum replicas to be present - minReplicas: 1 - # -- Maximum replicat to be present - maxReplicas: 100 - # -- CPU Utilization threshold - targetCPUUtilizationPercentage: 80 - # -- Memory Utilization threshold - # targetMemoryUtilizationPercentage: 80 + summarizer: + # -- Toggle for autoscaling + enabled: false + # -- Minimum replicas to be present + minReplicas: 1 + # -- Maximum replicat to be present + maxReplicas: 100 + # -- CPU Utilization threshold + targetCPUUtilizationPercentage: 80 + # -- Memory Utilization threshold + # targetMemoryUtilizationPercentage: 80 + bot: + # -- Toggle for autoscaling + enabled: false + # -- Minimum replicas to be present + minReplicas: 1 + # -- Maximum replicat to be present + maxReplicas: 100 + # -- CPU Utilization threshold + targetCPUUtilizationPercentage: 80 + # -- Memory Utilization threshold # -- Node selector labels nodeSelector: {} @@ -87,3 +107,9 @@ tolerations: [] # -- Affinity rules affinity: {} + +# -- Redis chart values (https://github.com/bitnami/charts/tree/main/bitnami/redis#parameters) +redis: + # -- The redis architecture (accepted values are: standalone, replication) + architecture: standalone + From 1c6725c8f5ea18f992b30db2bbc31182345e14fe Mon Sep 17 00:00:00 2001 From: Smorci Date: Tue, 23 Apr 2024 13:44:28 +0100 Subject: [PATCH 05/13] PM-1438 WIP --- .../templates/deployment_bot.yaml | 65 +++++++++++++++++++ .../templates/deployment_summarizer.yaml | 65 +++++++++++++++++++ gpt-survey-summarizer/templates/hpa_bot.yaml | 32 +++++++++ .../templates/hpa_summarizer.yaml | 32 +++++++++ 4 files changed, 194 insertions(+) create mode 100644 gpt-survey-summarizer/templates/deployment_bot.yaml create mode 100644 gpt-survey-summarizer/templates/deployment_summarizer.yaml create mode 100644 gpt-survey-summarizer/templates/hpa_bot.yaml create mode 100644 gpt-survey-summarizer/templates/hpa_summarizer.yaml diff --git a/gpt-survey-summarizer/templates/deployment_bot.yaml b/gpt-survey-summarizer/templates/deployment_bot.yaml new file mode 100644 index 00000000..1554ed9d --- /dev/null +++ b/gpt-survey-summarizer/templates/deployment_bot.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "gpt-survey-summarizer.fullname" . }}-bot + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.bot.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: backend + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + {{- toYaml .Values.args.bot | nindent 12 }} + env: + {{- toYaml .Values.envVars.bot | nindent 12 }} + {{- with .Values.ports }} + ports: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/gpt-survey-summarizer/templates/deployment_summarizer.yaml b/gpt-survey-summarizer/templates/deployment_summarizer.yaml new file mode 100644 index 00000000..b7570ef7 --- /dev/null +++ b/gpt-survey-summarizer/templates/deployment_summarizer.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "gpt-survey-summarizer.fullname" . }} + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.summarizer.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: backend + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + args: + {{- toYaml .Values.args.summarizer | nindent 12 }} + env: + {{- toYaml .Values.envVars.summarizer | nindent 12 }} + {{- with .Values.ports }} + ports: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/gpt-survey-summarizer/templates/hpa_bot.yaml b/gpt-survey-summarizer/templates/hpa_bot.yaml new file mode 100644 index 00000000..04588db5 --- /dev/null +++ b/gpt-survey-summarizer/templates/hpa_bot.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.bot.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "gpt-survey-summarizer.fullname" . }} + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "gpt-survey-summarizer.fullname" . }} + minReplicas: {{ .Values.autoscaling.bot.minReplicas }} + maxReplicas: {{ .Values.autoscaling.bot.maxReplicas }} + metrics: + {{- if .Values.autoscaling.bot.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.bot.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.bot.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.bot.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/gpt-survey-summarizer/templates/hpa_summarizer.yaml b/gpt-survey-summarizer/templates/hpa_summarizer.yaml new file mode 100644 index 00000000..9ad0fe56 --- /dev/null +++ b/gpt-survey-summarizer/templates/hpa_summarizer.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.summarizer.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "gpt-survey-summarizer.fullname" . }} + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "gpt-survey-summarizer.fullname" . }} + minReplicas: {{ .Values.autoscaling.summarizer.minReplicas }} + maxReplicas: {{ .Values.autoscaling.summarizer.maxReplicas }} + metrics: + {{- if .Values.autoscaling.summarizer.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.summarizer.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.summarizer.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.summarizer.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} From 6b652f7150e57e132b80a05a31fe5ba8c17d64f4 Mon Sep 17 00:00:00 2001 From: John Marcou Date: Tue, 23 Apr 2024 09:55:25 -0400 Subject: [PATCH 06/13] Suggested values interface --- gpt-survey-summarizer/values.yaml | 84 ++++++++++++------------------- 1 file changed, 33 insertions(+), 51 deletions(-) diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml index cc7e9e74..ec9cf1ac 100644 --- a/gpt-survey-summarizer/values.yaml +++ b/gpt-survey-summarizer/values.yaml @@ -3,7 +3,21 @@ # Declare variables to be passed into your templates. # -- The number of pods to be deployed -replicaCount: 1 + +config: + openAiApiKey: "" + discord: + clientId: "" + guildId: "" + token: "" + +# -- Redis chart values (https://github.com/bitnami/charts/tree/main/bitnami/redis#parameters) +redis: + # -- The redis architecture (accepted values are: standalone, replication) + architecture: standalone + auth: + password: "" + image: # image.repository -- The repository of the image @@ -11,7 +25,24 @@ image: # image.pullPolicy -- The pullPolicy used when pulling the image pullPolicy: IfNotPresent # image.tag -- The tag of the iamge. Overrides the image tag whose default is the chart appVersion. - tag: "0.1.0-b66ffbd" + tag: "latest" + +bot: + replicaCount: 1 + args: + - bot + extraEnvVars: + - name: SUMMARIZE_FREQUENCY_SECONDS + value: "3600" + +server: + replicaCount: 1 + args: + - summarizer + extraEnvVars: + - name: SUMMARIZE_FREQUENCY_SECONDS + value: "3600" + # -- The secrets used to pull the image imagePullSecrets: [] @@ -35,26 +66,6 @@ securityContext: {} # runAsNonRoot: true # runAsUser: 1000 -# -- Environment variables for the application -envVars: - summarizer: {} - bot: {} - # For each - # - name: FOO - # value: FOO - # - name: BAR - # valueFrom: - # secretKeyRef: - # name: mySecret - # key: bar offline: - -# -- Arguments for the container -args: - summarizer: - - summarizer - bot: - - bot - # -- Resource limitations for the pods resources: {} # We usually recommend not to specify default resources and to leave this as a conscious @@ -76,29 +87,6 @@ serviceAccount: # -- The name of the service account to use. If not set and create is true, a name is generated using the fullname template name: "" -autoscaling: - summarizer: - # -- Toggle for autoscaling - enabled: false - # -- Minimum replicas to be present - minReplicas: 1 - # -- Maximum replicat to be present - maxReplicas: 100 - # -- CPU Utilization threshold - targetCPUUtilizationPercentage: 80 - # -- Memory Utilization threshold - # targetMemoryUtilizationPercentage: 80 - bot: - # -- Toggle for autoscaling - enabled: false - # -- Minimum replicas to be present - minReplicas: 1 - # -- Maximum replicat to be present - maxReplicas: 100 - # -- CPU Utilization threshold - targetCPUUtilizationPercentage: 80 - # -- Memory Utilization threshold - # -- Node selector labels nodeSelector: {} @@ -107,9 +95,3 @@ tolerations: [] # -- Affinity rules affinity: {} - -# -- Redis chart values (https://github.com/bitnami/charts/tree/main/bitnami/redis#parameters) -redis: - # -- The redis architecture (accepted values are: standalone, replication) - architecture: standalone - From c9197521863b6de6d4747477da113ef47985eca0 Mon Sep 17 00:00:00 2001 From: Smorci Date: Tue, 23 Apr 2024 19:05:54 +0100 Subject: [PATCH 07/13] PM-1438 Refactoring, secret handling, no hpa, two service accounts --- .../templates/deployment_bot.yaml | 37 ++++++++++++++----- ...summarizer.yaml => deployment_server.yaml} | 29 +++++++++------ gpt-survey-summarizer/templates/hpa_bot.yaml | 32 ---------------- .../templates/hpa_summarizer.yaml | 32 ---------------- gpt-survey-summarizer/templates/secret.yaml | 9 +++++ ...ceaccount.yaml => serviceaccount_bot.yaml} | 4 +- .../templates/serviceaccount_server.yaml | 12 ++++++ gpt-survey-summarizer/values.yaml | 4 +- 8 files changed, 70 insertions(+), 89 deletions(-) rename gpt-survey-summarizer/templates/{deployment_summarizer.yaml => deployment_server.yaml} (68%) delete mode 100644 gpt-survey-summarizer/templates/hpa_bot.yaml delete mode 100644 gpt-survey-summarizer/templates/hpa_summarizer.yaml create mode 100644 gpt-survey-summarizer/templates/secret.yaml rename gpt-survey-summarizer/templates/{serviceaccount.yaml => serviceaccount_bot.yaml} (78%) create mode 100644 gpt-survey-summarizer/templates/serviceaccount_server.yaml diff --git a/gpt-survey-summarizer/templates/deployment_bot.yaml b/gpt-survey-summarizer/templates/deployment_bot.yaml index 1554ed9d..24a391de 100644 --- a/gpt-survey-summarizer/templates/deployment_bot.yaml +++ b/gpt-survey-summarizer/templates/deployment_bot.yaml @@ -3,14 +3,12 @@ kind: Deployment metadata: name: {{ include "gpt-survey-summarizer.fullname" . }}-bot labels: - {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }}-bot spec: - {{- if not .Values.autoscaling.bot.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} + replicas: {{ .Values.bot.replicaCount }} selector: matchLabels: - {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }} + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }}-bot template: metadata: {{- with .Values.podAnnotations }} @@ -18,25 +16,44 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }} + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }}-bot spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }} + serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }}-bot securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - - name: backend + - name: bot securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} args: - {{- toYaml .Values.args.bot | nindent 12 }} + {{- toYaml .Values.bot.args | nindent 12 }} env: - {{- toYaml .Values.envVars.bot | nindent 12 }} + - name: DISCORD_TOKEN + valueFrom: + secretKeyRef: + name: {{ include "gpt-survey-summarizer.fullname" . }} + key: discordToken + - name: CLIENT_ID + valueFrom: + secretKeyRef: + name: {{ include "gpt-survey-summarizer.fullname" . }} + key: discordClientId + - name: GUILD_ID + valueFrom: + secretKeyRef: + name: {{ include "gpt-survey-summarizer.fullname" . }} + key: discordGuildId + - name: REDIS_URL + value: redis://:{{ .Values.redis.auth.password }}@{{ .Values.redis.host }}:{{ .Values.redis.port }} + {{- if .Values.bot.extraEnvVars }} + {{- toYaml .Values.bot.extraEnvVars | nindent 12 }} + {{- end }} {{- with .Values.ports }} ports: {{- toYaml . | nindent 12 }} diff --git a/gpt-survey-summarizer/templates/deployment_summarizer.yaml b/gpt-survey-summarizer/templates/deployment_server.yaml similarity index 68% rename from gpt-survey-summarizer/templates/deployment_summarizer.yaml rename to gpt-survey-summarizer/templates/deployment_server.yaml index b7570ef7..f6a0a96c 100644 --- a/gpt-survey-summarizer/templates/deployment_summarizer.yaml +++ b/gpt-survey-summarizer/templates/deployment_server.yaml @@ -1,16 +1,14 @@ apiVersion: apps/v1 kind: Deployment metadata: - name: {{ include "gpt-survey-summarizer.fullname" . }} + name: {{ include "gpt-survey-summarizer.fullname" . }}-server labels: - {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }}-server spec: - {{- if not .Values.autoscaling.summarizer.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} + replicas: {{ .Values.server.replicaCount }} selector: matchLabels: - {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }} + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 6 }}-server template: metadata: {{- with .Values.podAnnotations }} @@ -18,25 +16,34 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} labels: - {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }} + {{- include "gpt-survey-summarizer.selectorLabels" . | nindent 8 }}-server spec: {{- with .Values.imagePullSecrets }} imagePullSecrets: {{- toYaml . | nindent 8 }} {{- end }} - serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }} + serviceAccountName: {{ include "gpt-survey-summarizer.serviceAccountName" . }}-server securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} containers: - - name: backend + - name: server securityContext: {{- toYaml .Values.securityContext | nindent 12 }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} args: - {{- toYaml .Values.args.summarizer | nindent 12 }} + {{- toYaml .Values.server.args | nindent 12 }} env: - {{- toYaml .Values.envVars.summarizer | nindent 12 }} + - name: OPENAI_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "gpt-survey-summarizer.fullname" . }} + key: openAiApiKey + - name: REDIS_URL + value: redis://:{{ .Values.redis.auth.password }}@{{ .Values.redis.host }}:{{ .Values.redis.port }} + {{- if .Values.server.extraEnvVars }} + {{- toYaml .Values.server.extraEnvVars | nindent 12 }} + {{- end }} {{- with .Values.ports }} ports: {{- toYaml . | nindent 12 }} diff --git a/gpt-survey-summarizer/templates/hpa_bot.yaml b/gpt-survey-summarizer/templates/hpa_bot.yaml deleted file mode 100644 index 04588db5..00000000 --- a/gpt-survey-summarizer/templates/hpa_bot.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.autoscaling.bot.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "gpt-survey-summarizer.fullname" . }} - labels: - {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "gpt-survey-summarizer.fullname" . }} - minReplicas: {{ .Values.autoscaling.bot.minReplicas }} - maxReplicas: {{ .Values.autoscaling.bot.maxReplicas }} - metrics: - {{- if .Values.autoscaling.bot.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.bot.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.bot.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.bot.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/gpt-survey-summarizer/templates/hpa_summarizer.yaml b/gpt-survey-summarizer/templates/hpa_summarizer.yaml deleted file mode 100644 index 9ad0fe56..00000000 --- a/gpt-survey-summarizer/templates/hpa_summarizer.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.autoscaling.summarizer.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "gpt-survey-summarizer.fullname" . }} - labels: - {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "gpt-survey-summarizer.fullname" . }} - minReplicas: {{ .Values.autoscaling.summarizer.minReplicas }} - maxReplicas: {{ .Values.autoscaling.summarizer.maxReplicas }} - metrics: - {{- if .Values.autoscaling.summarizer.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.summarizer.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.summarizer.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.summarizer.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/gpt-survey-summarizer/templates/secret.yaml b/gpt-survey-summarizer/templates/secret.yaml new file mode 100644 index 00000000..50b90c0a --- /dev/null +++ b/gpt-survey-summarizer/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "gpt-survey-summarizer.fullname" . }} +data: + openAiApiKey: {{ .Values.config.openAiApiKey | b64enc }} + discordClientId: {{ .Values.config.discord.clientId | b64enc }} + discordGuildId: {{ .Values.config.discord.guildId | b64enc }} + discordToken: {{ .Values.config.discord.token | b64enc }} diff --git a/gpt-survey-summarizer/templates/serviceaccount.yaml b/gpt-survey-summarizer/templates/serviceaccount_bot.yaml similarity index 78% rename from gpt-survey-summarizer/templates/serviceaccount.yaml rename to gpt-survey-summarizer/templates/serviceaccount_bot.yaml index 75326089..011669b3 100644 --- a/gpt-survey-summarizer/templates/serviceaccount.yaml +++ b/gpt-survey-summarizer/templates/serviceaccount_bot.yaml @@ -2,9 +2,9 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "gpt-survey-summarizer.serviceAccountName" . }} + name: {{ include "gpt-survey-summarizer.serviceAccountName" . }}-bot labels: - {{- include "gpt-survey-summarizer.labels" . | nindent 4 }} + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }}-bot {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/gpt-survey-summarizer/templates/serviceaccount_server.yaml b/gpt-survey-summarizer/templates/serviceaccount_server.yaml new file mode 100644 index 00000000..33a02468 --- /dev/null +++ b/gpt-survey-summarizer/templates/serviceaccount_server.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "gpt-survey-summarizer.serviceAccountName" . }}-server + labels: + {{- include "gpt-survey-summarizer.labels" . | nindent 4 }}-server + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml index ec9cf1ac..77b714bb 100644 --- a/gpt-survey-summarizer/values.yaml +++ b/gpt-survey-summarizer/values.yaml @@ -17,7 +17,8 @@ redis: architecture: standalone auth: password: "" - + host: "" + port: 6379 image: # image.repository -- The repository of the image @@ -43,7 +44,6 @@ server: - name: SUMMARIZE_FREQUENCY_SECONDS value: "3600" - # -- The secrets used to pull the image imagePullSecrets: [] # -- The release name override From b37163d510fa4065ae7aa97c5325d93f03880405 Mon Sep 17 00:00:00 2001 From: David Lehuby Date: Wed, 24 Apr 2024 10:44:49 +1000 Subject: [PATCH 08/13] PM-1542 - Mina Payout Data Provider - Update base image --- mina-payouts-data-provider/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mina-payouts-data-provider/values.yaml b/mina-payouts-data-provider/values.yaml index 06a7e31e..ab3b73e0 100644 --- a/mina-payouts-data-provider/values.yaml +++ b/mina-payouts-data-provider/values.yaml @@ -8,7 +8,7 @@ image: repository: 673156464838.dkr.ecr.us-west-2.amazonaws.com/mina-payouts-data-provider pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. - tag: "2.3.0-9a10e51" + tag: "2.4.2-1df80a6" imagePullSecrets: [] nameOverride: "" From fbd34e471c6745626478c1d1189af526d086f7e7 Mon Sep 17 00:00:00 2001 From: Smorci Date: Wed, 24 Apr 2024 11:09:18 +0100 Subject: [PATCH 09/13] PM-1438 Helm docs --- gpt-survey-summarizer/README.md | 68 ++++++++++++------------------- gpt-survey-summarizer/values.yaml | 25 ++++++++---- 2 files changed, 44 insertions(+), 49 deletions(-) diff --git a/gpt-survey-summarizer/README.md b/gpt-survey-summarizer/README.md index dbc1b524..6bbecb6e 100644 --- a/gpt-survey-summarizer/README.md +++ b/gpt-survey-summarizer/README.md @@ -4,7 +4,7 @@ A helm chart for the gptSuverySummarizer -**Homepage:** +**Homepage:** ## Maintainers @@ -14,63 +14,47 @@ A helm chart for the gptSuverySummarizer ## Source Code -* +* -## Prerequisites +## Requirements -Before using this Helm chart, you should have the following prerequisites: - -- Access to Kubernetes cluster (If needed contact your friendly neighbourhood DevOps engineer) -- Helm >= v3.14.3 -- (**Optional**) helmfile >= v0.162.0 to install this chart - -## Installation - -> Note: **examples** can be found in the repository - -To install this Helm chart, the easiest is to create a helmfile.yaml with needed values and run: - -``` -helmfile template -helmfile apply -``` - -Or use helmfile only to generate resources and apply them with kubectl like so: - -``` -helmfile template | kubectl -f - -``` - -Verify that the chart is deployed successfully: - -> Note: `kubectl` is a better suited tool for this - -``` -helmfile status -``` +| Repository | Name | Version | +|------------|------|---------| +| https://charts.bitnami.com/bitnami | redis | 19.1.0 | ## Values | Key | Type | Default | Description | |-----|------|---------|-------------| | affinity | object | `{}` | Affinity rules | -| autoscaling.enabled | bool | `false` | Toggle for autoscaling | -| autoscaling.maxReplicas | int | `100` | Maximum replicat to be present | -| autoscaling.minReplicas | int | `1` | Minimum replicas to be present | -| autoscaling.targetCPUUtilizationPercentage | int | `80` | CPU Utilization threshold | -| backend.envVars | object | `{}` | Environment variables for the application | +| bot.args | list | `["bot"]` | Arguments for the bot container | +| bot.extraEnvVars | list | `[{"name":"SUMMARIZE_FREQUENCY_SECONDS","value":"3600"}]` | Extra Environment Variables | +| bot.replicaCount | int | `1` | The number of pods to be deployed for bot | +| config.discord.clientId | string | `""` | Discord Application ID | +| config.discord.guildId | string | `""` | Discord Guild/Server ID | +| config.discord.token | string | `""` | Discord API Token | +| config.openAiApiKey | string | `""` | Openai API Key | | fullnameOverride | string | `""` | The full release name override | | image.pullPolicy | string | `"IfNotPresent"` | The pullPolicy used when pulling the image | | image.repository | string | `"673156464838.dkr.ecr.us-west-2.amazonaws.com/gpt-survey-summarizer"` | The repository of the image | -| image.tag | string | `"0.1.0-b66ffbd"` | The tag of the iamge. Overrides the image tag whose default is the chart appVersion. | +| image.tag | string | `"latest"` | The tag of the iamge. Overrides the image tag whose default is the chart appVersion. | | imagePullSecrets | list | `[]` | The secrets used to pull the image | | nameOverride | string | `""` | The release name override | | nodeSelector | object | `{}` | Node selector labels | | podAnnotations | object | `{}` | Annotations to add to the pods | -| podSecurityContext | object | `{}` | SecurityContext used for the pod | -| replicaCount | int | `1` | The number of pods to be deployed | +| podSecurityContext | object | `{}` | SecurityContext used for the pods | +| redis.architecture | string | `"standalone"` | The redis architecture (accepted values are: standalone, replication) | +| redis.auth.password | string | `""` | Redis password | +| redis.host | string | `""` | Redis hostname | +| redis.port | int | `6379` | Redis port | | resources | object | `{}` | Resource limitations for the pods | -| securityContext | object | `{}` | | +| securityContext | object | `{}` | SecurityContext | +| server.args | list | `["summarizer"]` | Arguments for the server container | +| server.extraEnvVars | list | `[{"name":"SUMMARIZE_FREQUENCY_SECONDS","value":"3600"}]` | Extra Environment Variables | +| server.replicaCount | int | `1` | The number of pods to be deployed for server | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | | tolerations | list | `[]` | Tolerations | ---------------------------------------------- diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml index 77b714bb..1f2f1ad6 100644 --- a/gpt-survey-summarizer/values.yaml +++ b/gpt-survey-summarizer/values.yaml @@ -2,44 +2,54 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -# -- The number of pods to be deployed - config: + # -- Openai API Key openAiApiKey: "" discord: + # -- Discord Application ID clientId: "" + # -- Discord Guild/Server ID guildId: "" + # -- Discord API Token token: "" -# -- Redis chart values (https://github.com/bitnami/charts/tree/main/bitnami/redis#parameters) redis: # -- The redis architecture (accepted values are: standalone, replication) architecture: standalone auth: + # -- Redis password password: "" + # -- Redis hostname host: "" + # -- Redis port port: 6379 image: - # image.repository -- The repository of the image + # -- The repository of the image repository: 673156464838.dkr.ecr.us-west-2.amazonaws.com/gpt-survey-summarizer - # image.pullPolicy -- The pullPolicy used when pulling the image + # -- The pullPolicy used when pulling the image pullPolicy: IfNotPresent - # image.tag -- The tag of the iamge. Overrides the image tag whose default is the chart appVersion. + # -- The tag of the iamge. Overrides the image tag whose default is the chart appVersion. tag: "latest" bot: + # -- The number of pods to be deployed for bot replicaCount: 1 + # -- Arguments for the bot container args: - bot + # -- Extra Environment Variables extraEnvVars: - name: SUMMARIZE_FREQUENCY_SECONDS value: "3600" server: + # -- The number of pods to be deployed for server replicaCount: 1 + # -- Arguments for the server container args: - summarizer + # -- Extra Environment Variables extraEnvVars: - name: SUMMARIZE_FREQUENCY_SECONDS value: "3600" @@ -54,10 +64,11 @@ fullnameOverride: "" # -- Annotations to add to the pods podAnnotations: {} -# -- SecurityContext used for the pod +# -- SecurityContext used for the pods podSecurityContext: {} # fsGroup: 2000 +# -- SecurityContext securityContext: {} # capabilities: # drop: From cb7f2956287c2871779e3f76c2c2bd3da964c032 Mon Sep 17 00:00:00 2001 From: John Marcou Date: Wed, 24 Apr 2024 10:01:49 -0400 Subject: [PATCH 10/13] Refactor redis url --- .github/docs/README.md.gotmpl | 51 ------------------- gpt-survey-summarizer/README.md | 2 - gpt-survey-summarizer/templates/_helpers.tpl | 4 ++ .../templates/deployment_bot.yaml | 5 +- .../templates/deployment_server.yaml | 5 +- gpt-survey-summarizer/templates/secret.yaml | 1 + gpt-survey-summarizer/values.yaml | 4 -- 7 files changed, 13 insertions(+), 59 deletions(-) delete mode 100644 .github/docs/README.md.gotmpl diff --git a/.github/docs/README.md.gotmpl b/.github/docs/README.md.gotmpl deleted file mode 100644 index 269daeba..00000000 --- a/.github/docs/README.md.gotmpl +++ /dev/null @@ -1,51 +0,0 @@ -{{ template "chart.header" . }} -{{ template "chart.deprecationWarning" . }} - -{{ template "chart.badgesSection" . }} - -{{ template "chart.description" . }} - -{{ template "chart.homepageLine" . }} - -{{ template "chart.maintainersSection" . }} - -{{ template "chart.sourcesSection" . }} - -{{ template "chart.requirementsSection" . }} - -## Prerequisites - -Before using this Helm chart, you should have the following prerequisites: - -- Access to Kubernetes cluster (If needed contact your friendly neighbourhood DevOps engineer) -- Helm >= v3.14.3 -- (**Optional**) helmfile >= v0.162.0 to install this chart - -## Installation - -> Note: **examples** can be found in the repository - -To install this Helm chart, the easiest is to create a helmfile.yaml with needed values and run: - -``` -helmfile template -helmfile apply -``` - -Or use helmfile only to generate resources and apply them with kubectl like so: - -``` -helmfile template | kubectl -f - -``` - -Verify that the chart is deployed successfully: - -> Note: `kubectl` is a better suited tool for this - -``` -helmfile status -``` - -{{ template "chart.valuesSection" . }} - -{{ template "helm-docs.versionFooter" . }} diff --git a/gpt-survey-summarizer/README.md b/gpt-survey-summarizer/README.md index 6bbecb6e..4e4eb8d2 100644 --- a/gpt-survey-summarizer/README.md +++ b/gpt-survey-summarizer/README.md @@ -45,8 +45,6 @@ A helm chart for the gptSuverySummarizer | podSecurityContext | object | `{}` | SecurityContext used for the pods | | redis.architecture | string | `"standalone"` | The redis architecture (accepted values are: standalone, replication) | | redis.auth.password | string | `""` | Redis password | -| redis.host | string | `""` | Redis hostname | -| redis.port | int | `6379` | Redis port | | resources | object | `{}` | Resource limitations for the pods | | securityContext | object | `{}` | SecurityContext | | server.args | list | `["summarizer"]` | Arguments for the server container | diff --git a/gpt-survey-summarizer/templates/_helpers.tpl b/gpt-survey-summarizer/templates/_helpers.tpl index 02260232..870d25c3 100644 --- a/gpt-survey-summarizer/templates/_helpers.tpl +++ b/gpt-survey-summarizer/templates/_helpers.tpl @@ -60,3 +60,7 @@ Create the name of the service account to use {{- default "default" .Values.serviceAccount.name }} {{- end }} {{- end }} + +{{- define "redisUrl" -}} + redis://:{{ .Values.redis.auth.password }}@{{ include "gpt-survey-summarizer.fullname" . }}-redis-master:6379 +{{- end -}} diff --git a/gpt-survey-summarizer/templates/deployment_bot.yaml b/gpt-survey-summarizer/templates/deployment_bot.yaml index 24a391de..7479a990 100644 --- a/gpt-survey-summarizer/templates/deployment_bot.yaml +++ b/gpt-survey-summarizer/templates/deployment_bot.yaml @@ -50,7 +50,10 @@ spec: name: {{ include "gpt-survey-summarizer.fullname" . }} key: discordGuildId - name: REDIS_URL - value: redis://:{{ .Values.redis.auth.password }}@{{ .Values.redis.host }}:{{ .Values.redis.port }} + valueFrom: + secretKeyRef: + name: {{ include "gpt-survey-summarizer.fullname" . }} + key: redisUrl {{- if .Values.bot.extraEnvVars }} {{- toYaml .Values.bot.extraEnvVars | nindent 12 }} {{- end }} diff --git a/gpt-survey-summarizer/templates/deployment_server.yaml b/gpt-survey-summarizer/templates/deployment_server.yaml index f6a0a96c..c9c3ba20 100644 --- a/gpt-survey-summarizer/templates/deployment_server.yaml +++ b/gpt-survey-summarizer/templates/deployment_server.yaml @@ -40,7 +40,10 @@ spec: name: {{ include "gpt-survey-summarizer.fullname" . }} key: openAiApiKey - name: REDIS_URL - value: redis://:{{ .Values.redis.auth.password }}@{{ .Values.redis.host }}:{{ .Values.redis.port }} + valueFrom: + secretKeyRef: + name: {{ include "gpt-survey-summarizer.fullname" . }} + key: redisUrl {{- if .Values.server.extraEnvVars }} {{- toYaml .Values.server.extraEnvVars | nindent 12 }} {{- end }} diff --git a/gpt-survey-summarizer/templates/secret.yaml b/gpt-survey-summarizer/templates/secret.yaml index 50b90c0a..19024e98 100644 --- a/gpt-survey-summarizer/templates/secret.yaml +++ b/gpt-survey-summarizer/templates/secret.yaml @@ -7,3 +7,4 @@ data: discordClientId: {{ .Values.config.discord.clientId | b64enc }} discordGuildId: {{ .Values.config.discord.guildId | b64enc }} discordToken: {{ .Values.config.discord.token | b64enc }} + redisUrl: {{ include "redisUrl" . | b64enc }} diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml index 1f2f1ad6..5115a519 100644 --- a/gpt-survey-summarizer/values.yaml +++ b/gpt-survey-summarizer/values.yaml @@ -19,10 +19,6 @@ redis: auth: # -- Redis password password: "" - # -- Redis hostname - host: "" - # -- Redis port - port: 6379 image: # -- The repository of the image From 38cebebe07c7b210727055758a4bc6af84be602c Mon Sep 17 00:00:00 2001 From: John Marcou Date: Wed, 24 Apr 2024 10:11:03 -0400 Subject: [PATCH 11/13] Add summarizeFrequencySeconds config --- gpt-survey-summarizer/README.md | 5 +++-- gpt-survey-summarizer/templates/deployment_bot.yaml | 2 ++ gpt-survey-summarizer/templates/deployment_server.yaml | 2 ++ gpt-survey-summarizer/values.yaml | 10 ++++------ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/gpt-survey-summarizer/README.md b/gpt-survey-summarizer/README.md index 4e4eb8d2..1ce5401a 100644 --- a/gpt-survey-summarizer/README.md +++ b/gpt-survey-summarizer/README.md @@ -28,12 +28,13 @@ A helm chart for the gptSuverySummarizer |-----|------|---------|-------------| | affinity | object | `{}` | Affinity rules | | bot.args | list | `["bot"]` | Arguments for the bot container | -| bot.extraEnvVars | list | `[{"name":"SUMMARIZE_FREQUENCY_SECONDS","value":"3600"}]` | Extra Environment Variables | +| bot.extraEnvVars | list | `[]` | Extra Environment Variables | | bot.replicaCount | int | `1` | The number of pods to be deployed for bot | | config.discord.clientId | string | `""` | Discord Application ID | | config.discord.guildId | string | `""` | Discord Guild/Server ID | | config.discord.token | string | `""` | Discord API Token | | config.openAiApiKey | string | `""` | Openai API Key | +| config.summarizeFrequencySeconds | int | `3600` | Summarize Frequency Seconds | | fullnameOverride | string | `""` | The full release name override | | image.pullPolicy | string | `"IfNotPresent"` | The pullPolicy used when pulling the image | | image.repository | string | `"673156464838.dkr.ecr.us-west-2.amazonaws.com/gpt-survey-summarizer"` | The repository of the image | @@ -48,7 +49,7 @@ A helm chart for the gptSuverySummarizer | resources | object | `{}` | Resource limitations for the pods | | securityContext | object | `{}` | SecurityContext | | server.args | list | `["summarizer"]` | Arguments for the server container | -| server.extraEnvVars | list | `[{"name":"SUMMARIZE_FREQUENCY_SECONDS","value":"3600"}]` | Extra Environment Variables | +| server.extraEnvVars | list | `[]` | Extra Environment Variables | | server.replicaCount | int | `1` | The number of pods to be deployed for server | | serviceAccount.annotations | object | `{}` | Annotations to add to the service account | | serviceAccount.create | bool | `true` | Specifies whether a service account should be created | diff --git a/gpt-survey-summarizer/templates/deployment_bot.yaml b/gpt-survey-summarizer/templates/deployment_bot.yaml index 7479a990..4ca86394 100644 --- a/gpt-survey-summarizer/templates/deployment_bot.yaml +++ b/gpt-survey-summarizer/templates/deployment_bot.yaml @@ -54,6 +54,8 @@ spec: secretKeyRef: name: {{ include "gpt-survey-summarizer.fullname" . }} key: redisUrl + - name: SUMMARIZE_FREQUENCY_SECONDS + value: {{ .Values.config.summarizeFrequencySeconds | quote }} {{- if .Values.bot.extraEnvVars }} {{- toYaml .Values.bot.extraEnvVars | nindent 12 }} {{- end }} diff --git a/gpt-survey-summarizer/templates/deployment_server.yaml b/gpt-survey-summarizer/templates/deployment_server.yaml index c9c3ba20..7934a120 100644 --- a/gpt-survey-summarizer/templates/deployment_server.yaml +++ b/gpt-survey-summarizer/templates/deployment_server.yaml @@ -44,6 +44,8 @@ spec: secretKeyRef: name: {{ include "gpt-survey-summarizer.fullname" . }} key: redisUrl + - name: SUMMARIZE_FREQUENCY_SECONDS + value: {{ .Values.config.summarizeFrequencySeconds | quote }} {{- if .Values.server.extraEnvVars }} {{- toYaml .Values.server.extraEnvVars | nindent 12 }} {{- end }} diff --git a/gpt-survey-summarizer/values.yaml b/gpt-survey-summarizer/values.yaml index 5115a519..ccbfe316 100644 --- a/gpt-survey-summarizer/values.yaml +++ b/gpt-survey-summarizer/values.yaml @@ -3,6 +3,8 @@ # Declare variables to be passed into your templates. config: + # -- Summarize Frequency Seconds + summarizeFrequencySeconds: 3600 # -- Openai API Key openAiApiKey: "" discord: @@ -35,9 +37,7 @@ bot: args: - bot # -- Extra Environment Variables - extraEnvVars: - - name: SUMMARIZE_FREQUENCY_SECONDS - value: "3600" + extraEnvVars: [] server: # -- The number of pods to be deployed for server @@ -46,9 +46,7 @@ server: args: - summarizer # -- Extra Environment Variables - extraEnvVars: - - name: SUMMARIZE_FREQUENCY_SECONDS - value: "3600" + extraEnvVars: [] # -- The secrets used to pull the image imagePullSecrets: [] From 8117bc07a6c1ba88c2d8894a0388daf15e87e58e Mon Sep 17 00:00:00 2001 From: David Lehuby Date: Thu, 25 Apr 2024 08:26:07 +1000 Subject: [PATCH 12/13] PM-1542 - Mina Payout Data Provider - Update base image --- mina-payouts-data-provider/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mina-payouts-data-provider/values.yaml b/mina-payouts-data-provider/values.yaml index ab3b73e0..9bacb204 100644 --- a/mina-payouts-data-provider/values.yaml +++ b/mina-payouts-data-provider/values.yaml @@ -8,7 +8,7 @@ image: repository: 673156464838.dkr.ecr.us-west-2.amazonaws.com/mina-payouts-data-provider pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. - tag: "2.4.2-1df80a6" + tag: "2.4.3-8796a9a" imagePullSecrets: [] nameOverride: "" From 459806dfcc90ead08e9c007f3fb3365b651c391d Mon Sep 17 00:00:00 2001 From: Simonas Narbutas Date: Thu, 25 Apr 2024 13:17:57 +0300 Subject: [PATCH 13/13] PM-1450 update coordinator helm chart to reflect code changes --- delegation-verify-coordinator/README.md | 5 +++-- .../templates/deployment.yaml | 12 ++++++++++++ delegation-verify-coordinator/templates/secret.yaml | 9 +++++++++ delegation-verify-coordinator/values.yaml | 4 +++- 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 delegation-verify-coordinator/templates/secret.yaml diff --git a/delegation-verify-coordinator/README.md b/delegation-verify-coordinator/README.md index 83273ca5..84f560c0 100644 --- a/delegation-verify-coordinator/README.md +++ b/delegation-verify-coordinator/README.md @@ -71,12 +71,13 @@ The command removes all the Kubernetes components associated with the chart and | `coordinator.aws.secretAccessKey` | AWS Secret Access Key | `` | | `coordinator.aws.s3Bucket` | AWS S3 Bucket name that holds submissions | `673156464838-uptime-service-backend` | | `coordinator.ssl.certfile` | Path to the certfile for AWS Keyspaces | `` | -| `coordinator.envVars` | Environment Variables to pass to the container | `{}` | +| `coordinator.envVars` | Environment Variables to pass to the container | `[]` | | `serviceAccount.create` | Create or not Service Account | `true` | | `serviceAccount.automount` | Automatically mount ServiceAccount API credentials | `true` | | `serviceAccount.coordinator.annotations`| Annotations for the Coordinator Service Account | `{}` | | `serviceAccount.worker.annotations` | Annotations for the Worker Service Account | `{}` | -| `serviceAccount.name` | If specified, name of the service account | ` ` | +| `serviceAccount.name` | If specified, name of the service account | ` ` | +| `secret.gcpServiceAccount` | JSON data of gcp sa credentials | ` ` | | `podAnnotations` | Pod annotations | `{}` | | `podLabels` | Pod labels | `{}` | | `affinity` | Pod affinity | `{}` | diff --git a/delegation-verify-coordinator/templates/deployment.yaml b/delegation-verify-coordinator/templates/deployment.yaml index c93f3223..f38a81f0 100644 --- a/delegation-verify-coordinator/templates/deployment.yaml +++ b/delegation-verify-coordinator/templates/deployment.yaml @@ -113,9 +113,14 @@ spec: value: {{ include "delegation-verify-coordinator.fullname" . }} - name: AUTH_VOLUME_MOUNT_PATH value: /var/mina-delegation-verify-auth + - name: SPREADSHEET_CREDENTIALS_JSON + value: /usr/src/app/gcloud/gcp-sa.json {{- if .Values.coordinator.envVars }} {{- toYaml .Values.coordinator.envVars | nindent 12 }} {{- end }} + volumeMounts: + - name: {{ .Release.Name }}-gcp-sa + mountPath: /usr/src/app/gcloud ports: - name: http containerPort: {{ .Values.service.port }} @@ -134,3 +139,10 @@ spec: items: - key: "entrypoint-initdb.sh" path: "entrypoint-initdb.sh" + - name: {{ .Release.Name }}-gcp-sa + secret: + secretName: {{ .Release.Name }} + defaultMode: 0600 + items: + - key: gcp-sa-json + path: gcp-sa.json diff --git a/delegation-verify-coordinator/templates/secret.yaml b/delegation-verify-coordinator/templates/secret.yaml new file mode 100644 index 00000000..b133905c --- /dev/null +++ b/delegation-verify-coordinator/templates/secret.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "delegation-verify-coordinator.fullname" . }} + labels: + {{- include "delegation-verify-coordinator.labels" . | nindent 4 }} +data: + gcp-sa-json: {{ .Values.secret.gcpServiceAccount | toString | b64enc }} diff --git a/delegation-verify-coordinator/values.yaml b/delegation-verify-coordinator/values.yaml index c98c14ea..9f60d736 100644 --- a/delegation-verify-coordinator/values.yaml +++ b/delegation-verify-coordinator/values.yaml @@ -44,7 +44,7 @@ coordinator: s3Bucket: "673156464838-uptime-service-backend" ssl: certfile: - envVars: {} + envVars: [] # - name: FOO # value: FOO # - name: BAR @@ -52,6 +52,8 @@ coordinator: # secretKeyRef: # name: mySecret # key: bar offline: +secret: + gcpServiceAccount: serviceAccount: coordinator: