From 1b3a1408f6f350ddf6d91a366055df019907d299 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 3 Jan 2026 21:34:20 +0000 Subject: [PATCH] Release gohoarder 0.1.13 --- charts/gohoarder/Chart.yaml | 4 +- charts/gohoarder/templates/_helpers.tpl | 2 +- .../templates/deployment-scanner.yaml | 117 ++++++++++++++++++ .../templates/deployment-server.yaml | 94 ++++++++++++++ charts/gohoarder/templates/secret.yaml | 13 ++ charts/gohoarder/values.yaml | 66 +++++++++- charts/packages/gohoarder-0.1.13.tgz | Bin 0 -> 17943 bytes index.yaml | 29 ++++- 8 files changed, 316 insertions(+), 9 deletions(-) create mode 100644 charts/packages/gohoarder-0.1.13.tgz diff --git a/charts/gohoarder/Chart.yaml b/charts/gohoarder/Chart.yaml index c2ee078..f74895e 100644 --- a/charts/gohoarder/Chart.yaml +++ b/charts/gohoarder/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: gohoarder description: A universal package cache proxy supporting npm, PyPI, and Go modules with security scanning type: application -version: 0.1.10 -appVersion: "0.1.10" +version: 0.1.13 +appVersion: "0.1.13" keywords: - package-manager - cache diff --git a/charts/gohoarder/templates/_helpers.tpl b/charts/gohoarder/templates/_helpers.tpl index 859f65a..d4585a0 100644 --- a/charts/gohoarder/templates/_helpers.tpl +++ b/charts/gohoarder/templates/_helpers.tpl @@ -181,7 +181,7 @@ Validate SQLite configuration - SQLite cannot be used with SMB/NFS network stora {{- if .Values.metadata.sqlite.persistence.enabled }} {{- $storageClass := .Values.metadata.sqlite.persistence.storageClass | default .Values.storage.storageClass }} {{- if or (contains "smb" ($storageClass | lower)) (contains "cifs" ($storageClass | lower)) (contains "nfs" ($storageClass | lower)) }} - {{- fail "\n\n❌ ERROR: SQLite cannot be used with SMB/CIFS/NFS network storage!\n\nSQLite requires POSIX file locking which is not reliably supported over network filesystems.\nThis will cause 'database is locked' errors and data corruption.\n\nPlease choose ONE of the following solutions:\n\n1. Use PostgreSQL for network storage (RECOMMENDED for production):\n metadata:\n backend: postgresql\n postgresql:\n host: your-postgres-host\n ...\n\n2. Use local storage for SQLite (OK for development):\n metadata:\n sqlite:\n persistence:\n enabled: true\n storageClass: local-path # or another local storage class\n\n3. Disable persistence (data will be lost on pod restart):\n metadata:\n sqlite:\n persistence:\n enabled: false\n\nFor more information, see: https://www.sqlite.org/lockingv3.html\n" }} + {{- fail "\n\n❌ ERROR: SQLite cannot be used with SMB/CIFS/NFS network storage!\n\nSQLite requires POSIX file locking which is not reliably supported over network filesystems.\nThis will cause 'database is locked' errors and data corruption.\n\nPlease choose ONE of the following solutions:\n\n1. Use PostgreSQL for network storage (RECOMMENDED for production):\n metadata:\n backend: postgresql\n postgresql:\n host: your-postgres-host\n ...\n\n2. Use MySQL/MariaDB for network storage (alternative to PostgreSQL):\n metadata:\n backend: mysql\n mysql:\n host: your-mysql-host\n ...\n\n3. Use local storage for SQLite (OK for development):\n metadata:\n sqlite:\n persistence:\n enabled: true\n storageClass: local-path # or another local storage class\n\n4. Disable persistence (data will be lost on pod restart):\n metadata:\n sqlite:\n persistence:\n enabled: false\n\nFor more information, see: https://www.sqlite.org/lockingv3.html\n" }} {{- end }} {{- end }} {{- end }} diff --git a/charts/gohoarder/templates/deployment-scanner.yaml b/charts/gohoarder/templates/deployment-scanner.yaml index d0fbe92..308db42 100644 --- a/charts/gohoarder/templates/deployment-scanner.yaml +++ b/charts/gohoarder/templates/deployment-scanner.yaml @@ -29,6 +29,77 @@ spec: serviceAccountName: {{ include "gohoarder.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- if .Values.migration.enabled }} + initContainers: + # Wait for database to be ready + - name: wait-for-db + image: busybox:1.36 + command: + - sh + - -c + - | + echo "Waiting for database..." + {{- if eq .Values.metadata.backend "postgresql" }} + until nc -z {{ .Values.metadata.postgresql.host }} {{ .Values.metadata.postgresql.port }}; do + echo " PostgreSQL not ready, retrying in 2s..." + sleep 2 + done + echo "✓ PostgreSQL is ready" + {{- else if eq .Values.metadata.backend "mysql" }} + until nc -z {{ .Values.metadata.mysql.host }} {{ .Values.metadata.mysql.port }}; do + echo " MySQL not ready, retrying in 2s..." + sleep 2 + done + echo "✓ MySQL is ready" + {{- else }} + echo "✓ SQLite (no wait needed)" + {{- end }} + securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1000 + resources: + limits: + cpu: 100m + memory: 64Mi + requests: + cpu: 10m + memory: 32Mi + # Run database migrations + - name: migrate + image: "{{ .Values.migration.image.repository }}:{{ .Values.migration.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.migration.image.pullPolicy }} + env: + - name: DB_DRIVER + value: {{ .Values.metadata.backend | quote }} + {{- if eq .Values.metadata.backend "postgresql" }} + - name: DATABASE_URL + value: "postgresql://{{ .Values.metadata.postgresql.username }}:{{ .Values.metadata.postgresql.password }}@{{ .Values.metadata.postgresql.host }}:{{ .Values.metadata.postgresql.port }}/{{ .Values.metadata.postgresql.database }}?sslmode={{ .Values.metadata.postgresql.sslMode }}" + {{- else if eq .Values.metadata.backend "mysql" }} + - name: DATABASE_URL + value: "{{ .Values.metadata.mysql.username }}:{{ .Values.metadata.mysql.password }}@tcp({{ .Values.metadata.mysql.host }}:{{ .Values.metadata.mysql.port }})/{{ .Values.metadata.mysql.database }}?charset={{ .Values.metadata.mysql.charset }}&parseTime={{ .Values.metadata.mysql.parseTime }}" + {{- else }} + - name: DATABASE_URL + value: "/var/lib/gohoarder/metadata/gohoarder.db" + {{- end }} + args: + - --driver=$(DB_DRIVER) + - --dsn=$(DATABASE_URL) + - --action=migrate + - --log-level={{ .Values.migration.logLevel | default "info" }} + - --timeout={{ .Values.migration.timeout | default "5m" }} + securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1000 + resources: + {{- toYaml .Values.migration.resources | nindent 10 }} + {{- if eq .Values.metadata.backend "sqlite" }} + volumeMounts: + - name: metadata + mountPath: /var/lib/gohoarder/metadata + {{- end }} + {{- end }} containers: - name: scanner securityContext: @@ -38,6 +109,52 @@ spec: env: - name: CONFIG_FILE value: /etc/gohoarder/config.yaml + {{- if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.existingSecret }} + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.postgresql.existingSecret }} + key: username + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.postgresql.existingSecret }} + key: password + {{- else if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.username }} + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-postgresql + key: username + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-postgresql + key: password + {{- end }} + {{- if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.existingSecret }} + - name: MYSQL_USER + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.mysql.existingSecret }} + key: username + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.mysql.existingSecret }} + key: password + {{- else if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.username }} + - name: MYSQL_USER + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-mysql + key: username + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-mysql + key: password + {{- end }} {{- if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.existingSecret }} - name: GHSA_TOKEN valueFrom: diff --git a/charts/gohoarder/templates/deployment-server.yaml b/charts/gohoarder/templates/deployment-server.yaml index 92dd164..3cfb70c 100644 --- a/charts/gohoarder/templates/deployment-server.yaml +++ b/charts/gohoarder/templates/deployment-server.yaml @@ -30,6 +30,77 @@ spec: serviceAccountName: {{ include "gohoarder.serviceAccountName" . }} securityContext: {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- if .Values.migration.enabled }} + initContainers: + # Wait for database to be ready + - name: wait-for-db + image: busybox:1.36 + command: + - sh + - -c + - | + echo "Waiting for database..." + {{- if eq .Values.metadata.backend "postgresql" }} + until nc -z {{ .Values.metadata.postgresql.host }} {{ .Values.metadata.postgresql.port }}; do + echo " PostgreSQL not ready, retrying in 2s..." + sleep 2 + done + echo "✓ PostgreSQL is ready" + {{- else if eq .Values.metadata.backend "mysql" }} + until nc -z {{ .Values.metadata.mysql.host }} {{ .Values.metadata.mysql.port }}; do + echo " MySQL not ready, retrying in 2s..." + sleep 2 + done + echo "✓ MySQL is ready" + {{- else }} + echo "✓ SQLite (no wait needed)" + {{- end }} + securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1000 + resources: + limits: + cpu: 100m + memory: 64Mi + requests: + cpu: 10m + memory: 32Mi + # Run database migrations + - name: migrate + image: "{{ .Values.migration.image.repository }}:{{ .Values.migration.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.migration.image.pullPolicy }} + env: + - name: DB_DRIVER + value: {{ .Values.metadata.backend | quote }} + {{- if eq .Values.metadata.backend "postgresql" }} + - name: DATABASE_URL + value: "postgresql://{{ .Values.metadata.postgresql.username }}:{{ .Values.metadata.postgresql.password }}@{{ .Values.metadata.postgresql.host }}:{{ .Values.metadata.postgresql.port }}/{{ .Values.metadata.postgresql.database }}?sslmode={{ .Values.metadata.postgresql.sslMode }}" + {{- else if eq .Values.metadata.backend "mysql" }} + - name: DATABASE_URL + value: "{{ .Values.metadata.mysql.username }}:{{ .Values.metadata.mysql.password }}@tcp({{ .Values.metadata.mysql.host }}:{{ .Values.metadata.mysql.port }})/{{ .Values.metadata.mysql.database }}?charset={{ .Values.metadata.mysql.charset }}&parseTime={{ .Values.metadata.mysql.parseTime }}" + {{- else }} + - name: DATABASE_URL + value: "/var/lib/gohoarder/metadata/gohoarder.db" + {{- end }} + args: + - --driver=$(DB_DRIVER) + - --dsn=$(DATABASE_URL) + - --action=migrate + - --log-level={{ .Values.migration.logLevel | default "info" }} + - --timeout={{ .Values.migration.timeout | default "5m" }} + securityContext: + allowPrivilegeEscalation: false + runAsNonRoot: true + runAsUser: 1000 + resources: + {{- toYaml .Values.migration.resources | nindent 10 }} + {{- if eq .Values.metadata.backend "sqlite" }} + volumeMounts: + - name: metadata + mountPath: /var/lib/gohoarder/metadata + {{- end }} + {{- end }} containers: - name: server securityContext: @@ -125,6 +196,29 @@ spec: name: {{ include "gohoarder.fullname" . }}-postgresql key: password {{- end }} + {{- if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.existingSecret }} + - name: MYSQL_USER + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.mysql.existingSecret }} + key: username + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.mysql.existingSecret }} + key: password + {{- else if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.username }} + - name: MYSQL_USER + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-mysql + key: username + - name: MYSQL_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-mysql + key: password + {{- end }} {{- if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.existingSecret }} - name: GHSA_TOKEN valueFrom: diff --git a/charts/gohoarder/templates/secret.yaml b/charts/gohoarder/templates/secret.yaml index cfa1876..656ffd9 100644 --- a/charts/gohoarder/templates/secret.yaml +++ b/charts/gohoarder/templates/secret.yaml @@ -53,6 +53,19 @@ data: password: {{ .Values.metadata.postgresql.password | b64enc | quote }} {{- end }} --- +{{- if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) (not .Values.metadata.mysql.existingSecret) .Values.metadata.mysql.username }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "gohoarder.fullname" . }}-mysql + labels: + {{- include "gohoarder.labels" . | nindent 4 }} +type: Opaque +data: + username: {{ .Values.metadata.mysql.username | b64enc | quote }} + password: {{ .Values.metadata.mysql.password | b64enc | quote }} +{{- end }} +--- {{- if and .Values.security.scanners.ghsa.enabled (not .Values.security.scanners.ghsa.existingSecret) .Values.security.scanners.ghsa.token }} apiVersion: v1 kind: Secret diff --git a/charts/gohoarder/values.yaml b/charts/gohoarder/values.yaml index c3431ba..39a69d5 100644 --- a/charts/gohoarder/values.yaml +++ b/charts/gohoarder/values.yaml @@ -51,17 +51,17 @@ image: server: repository: ghcr.io/lukaszraczylo/gohoarder-server pullPolicy: IfNotPresent - tag: "0.1.10" + tag: "0.1.13" frontend: repository: ghcr.io/lukaszraczylo/gohoarder-frontend pullPolicy: IfNotPresent - tag: "0.1.10" + tag: "0.1.13" scanner: repository: ghcr.io/lukaszraczylo/gohoarder-scanner pullPolicy: IfNotPresent - tag: "0.1.10" + tag: "0.1.13" # Service Account serviceAccount: @@ -272,7 +272,7 @@ storage: # Metadata storage configuration metadata: - # Backend: sqlite, postgresql + # Backend: sqlite, postgresql, mysql # # IMPORTANT: SQLite CANNOT be used with SMB/CIFS/NFS network storage! # SQLite requires POSIX file locking which causes "database is locked" errors on network filesystems. @@ -286,6 +286,13 @@ metadata: # 2. PostgreSQL with any storage (RECOMMENDED for production) # - Set backend: postgresql # - Configure postgresql settings below + # - Works with any storage including SMB/NFS + # - Supports multiple replicas and high availability + # + # 3. MySQL/MariaDB with any storage (alternative to PostgreSQL) + # - Set backend: mysql + # - Configure mysql settings below + # - Works with any storage including SMB/NFS # backend: "sqlite" @@ -305,6 +312,8 @@ metadata: walMode: false # PostgreSQL configuration + # Works with any storage including SMB/NFS + # Recommended for production deployments postgresql: # Use bundled PostgreSQL (sets up postgresql subchart) enabled: false @@ -313,10 +322,57 @@ metadata: database: "gohoarder" username: "gohoarder" password: "" - sslMode: "disable" + sslMode: "disable" # disable, require, verify-ca, verify-full # Use existing secret for PostgreSQL credentials existingSecret: "" + # MySQL/MariaDB configuration + # Works with any storage including SMB/NFS + # Alternative to PostgreSQL for production deployments + mysql: + host: "localhost" + port: 3306 + database: "gohoarder" + username: "gohoarder" + password: "" + charset: "utf8mb4" + parseTime: true + # Use existing secret for MySQL credentials + existingSecret: "" + + # GORM connection pool settings (applies to all database backends) + # These settings control database connection pooling and performance + maxOpenConns: 25 # Maximum number of open connections to the database + maxIdleConns: 5 # Maximum number of idle connections in the pool + connMaxLifetime: 3600 # Maximum lifetime of a connection in seconds (1 hour) + logLevel: "warn" # GORM log level: silent, error, warn, info + +# Database migration configuration +migration: + # Enable automatic database migrations via init containers + # When enabled, each pod will run migrations before starting the main container + # Gormigrate handles concurrency automatically - safe for multiple pods + enabled: true + + # Migration image configuration + image: + repository: ghcr.io/lukaszraczylo/gohoarder-migrate + pullPolicy: IfNotPresent + tag: "0.1.13" + + # Migration settings + logLevel: "info" # debug, info, warn, error + timeout: "5m" # Maximum time for migrations to complete + + # Resource limits for migration init container + resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + # Cache configuration cache: defaultTTL: "168h" # 7 days diff --git a/charts/packages/gohoarder-0.1.13.tgz b/charts/packages/gohoarder-0.1.13.tgz new file mode 100644 index 0000000000000000000000000000000000000000..df8752cdd7d5b17f415747fb36bdfb9232648766 GIT binary patch literal 17943 zcmZ6SLy#s+(5>6Il)Z_J0NNCNMT``VnXQP@ z&bGmwUKqxTKKA-!H#@uYUp$)59`$;9dcOOMAi?!E8t%+K%d;Jv*3dCk54 z1%A2t7vDf;f-UU3_Ic6rkp1cUkQdiAj7Y>}*8j{8AFTi2Slhn4#aq>$#*PTx?zI}i zhQG>YFc$ciUDYh4pMM5h5Mw?TR?i+|AuLf3g8%HcPmliW1_(xrt#D6~^@XkycuDVu|3lHf@iRVsOGs12&=@Wc_LMlIk;BUOw}H)r}Cm zGUMxT@eFFr$vyG677&E*XJ?)?=SkDPklLQOL8TJJMie}q7Jq->VXK40%D#j5TY?@s_PA@5V&QhNbkPKYpER1S%MBrl8dJ86FB z>SyPlpk=oh&@iNzea9zQc4evp^CFK!&$cIIXG6bvGxIf*i7JKg`_(0 z!!^~E{4BMSvlMVkKFnNUx2IJ{=&4cc_OL>fjkDU*Aj32w2;BSdI7I~bEHa|+`G{S)u zr)666y>eM*B8-LrQKVfE1w}1X1rfGpw$2GN%QBCKjI>J73q;fTfSV@Kcl-gVa4Mh} z6Y4TbP8paAutiN)bBmpPdBM0%S4HJ6=fr<>1M|%GbWJ#-aB9)zyC0=}LgS@qcjP0? zKqz2Ilk@V5{cBqi-f(4>sb#@S)~6I_3gZPLG`u_x@=is&*=4E)&j8LyGwc>UUt8N+ z2m_U7^;if&3HN|RulEpf6{KN{fB1Z3B!cw>Dpug`xZRjSM;UHzA)HhExC)nTfQK}* z0sj00pMZ2MJl2Bzk4oU{M@N4M5gXn+G?3QRaj9iB3ynka(F1_#Ea1?=?#TBU%TJA< zWiPZF?}h1!{+>QsxSU8Ar7aw4^gVUxxylu?N2SYpl|%vu7@=_bG1AA@I*ksVKyzZ3Bh`bwxT@=ExH-Ffc$*%-oN1HW)MX;AcMNuCjsyGV_hsVw z=OW_E-HY8MTIl+%kC2&)_^dfjIoC2|*@baX{=GA$Di~6wT$DrEWk#aW3XveP0D%-7 zH8j>xk2F8jZy`}O{1A@L7*lw|2TeLXt?^fwaSDr%frnDW`96ab zYo4gKK8^d@zEW78Ux!< z=Y*CAqmqk~=Nvesdybi0rh+Y@EIIFbh8CWgoq;eb_*JNvJ?uMYb6o?mU3i?upN`bg zYx&cM>ANm`^{Dn}frX~2gAc>0`jSC8!dGY77#9&g|E^XAxDPT^=O zt7?$U-BcKN7fI9xUy&Ob$L6xhMXhe-CkEjrVhi=jK^(nM&c3g3`az1+e8BnQ^QlP? z&c!F2U43V=mv6eJ7XrP*E;Q&92srE-cF(8%B$aUg{a?d6cbUNTERlYMC!H9VJ+RQn z)It=4T3#9|bL2AbdaGURo=aQkCI-rFrH_`p9FVz?nqX569_nI+qix z0yP1^c?@RHXFUNrXh72Xj)%ByAi$Chw;y;H7&7z`un9bseUcJXTbUiE;jo`192T!z zMMA0Y-*O1$eyoU|8N&yd#-bzarxM09+oO(PuBx}}6YiM|K=z3d4@y6C zZRxF`6+3X`FNUNK4DDB|!W~*L@q62PtM`)uZ`N0o01r16oI=`DV}A#0sPIqQSM6}= zzzPI2fW7EkCEs`+Bi8(xFn@2 zpn7h3H>jWar(zc;5rd1ffiNz$n{-I&kI2Y{m7UpKadkahzpd@NAOV$Yz$A*;qAwKA z2*eP>`Av8aUn}%=;D$40`Ohw2TNB`D0#rH?5 zXY_if4SYkD6h+P#4w;IhLbb9m@^CxxW^&%<_81Ce%GS)unC`uhu&^R)s*vAz>03U6 zh+wfssMq#nC_OOHAOv#>yajoP?k}mNUMm7ygxQcEg!sR5F2iZC(?s@SxJv0DI83G6 z*G!1ag2%rs+FsGzSTN1qma^iEsKq(feNc}|ZxjqBycMp~e?_C{Vn88Tt^LVNZ~`8G z#6P)cdF>rnw){JWDhaA`I+ksGp{lSs5Q6Ajnw`W)8Jj5D=Fs^iy=Q;qHv1z(Z0HH%B8AR-stgpsP!f-om5*j>=;I$RZ7e zB#shp&nzH%X&aa9z{c0p4CnGJ38N5?=UerIJo5h_+}9|9{_8A+G)WB1L&n^IwaHj1RIKfJV(toaoR=@(`m2}B!03+ za#{!8>PC&>{|U*2MFD+J%v-67Zyp;`3R_wp^I_xOaQF85|Ap%(CNbdo?$707JSHS% zB}m}TFa}Fq(#%{j{oW78x6fQA&y$k~IB@_&$i2N*_v8BJ_Y-gt6~~7N zhM)h?r7~YWvVX|JdoC$hs#q@@N7nMY9hMW^ErmdO9%S{xhg$ zQFhxe49hPwI!GQiXwzr!6b+{Qdg@F9E^>tK)wQQ4=0AAK>(%?3`|{`I9{F(5;`StxMl1P53uXJJ&ie8KDE(xmuWyorEn&EFtUm z#ppqxa7&;m(leVA;%I524;_*tI|8+&q(QLZUBa zE?`V`QsF2)aBP2+*YOyCF#HJO64~Tn!W1b1OcXnDDgyRtND31l;#Gdg&)FW|m%;r< zQ(iIOpsenRu7R25@Hf0j?-XEyb`O-sIJTe>s(sh?KkVosNs1+A@>8eP0Tcro(?51Ls#HbJY($FLXmN~VwVaw3z}ZAl#=R3HPou8wEQ&sZo#YMAssqUY*8<_3 zDBfn4A@9*RTJKH{m&goiwhXvE6C0kllr9BkGw`Vs3#A37Y&WX4n>wsf`8WM?z38(q z9oE>uK`agw(bT&@NdCDa`$SQsT8;Lj1`}6dwZ^+vjNk}S)EB?df9fWm>Q4`o>5^c7 zm3U#gI!$>wRdFw1!k|}9u3F`hvA2Zj4Mr(Me9d|xD168oBLDYKNd}_J5Fv48p0RUu zS-in`7~SfId$1AAb;YfNRcAld0F|s^!A=U+-v#?6#mPB6k$~7|t+)IF@|ZSuS7JB= z(P01+lp%f05Fv(R2q>Tp%iy|-E)^)V|mXMFc^RN;I9QMAHiQ;8T(jj;l=bIa#$@B}x7A3NeJ)nB!lQC?!5f z*!aX)KcMS41M_*hf-H_D%lTg^-t+g`BexlwTHc$ej4z_zQWll0-|wHZ zcb}WD)y7lN+1wdl?vciBc+;n317LS6g8+N{L(I5S{nyyKZtcoz)_u6jNA4AVc}yNQ zbz(AswkK|mrB`|Ul)_vd<{;)RuSx_oEcpCWLa%oPc zh-X~qdp{8_@C5w4L!?YEM1y7ZFZnUZvu9b()W9FRuY*kKe07|gemF-nCZu=J0#m^& z{UN)?)UNLba4e;a5Q2k8^k-RVG=oxr@Z#>v&kh_Di|z#}MFO?%az3eW6XKjPyb!!_l=NszMio(fnKAtbJvVXu*%}29g4^gS>4?}e^J8qu}lBocTqed>2@ z)_{23o%P9Gp0CHcrLL1h6I^-c&DCAdKE{cZrTo1xd$uChEy|_%JT6;tO5oX;Qpb|e@9?Du!1lW6(V5^`Nfz<>`7R&|i zm?5sm$Hx$q-AJg+z%Bt1w>-=wjmHF}KD2KS$CIvin51F*r?YwcCMM1$F~~Z1U$!&i!FB9#X{ZPZW+1MRPV{dF%lqJ)`_3bh-d3dcz z>6ON5089~xduR&pphFe?B3N|lD&=-^YfBVX;Nuo(o@w3qmJR2Yods7L{gLsx6N+z}C>Tnf$6L)VCykmvfkr zUk~sL@TSY>nf}T|NF`#5eb%PMmySyml8}hl+U2W`^PgoVroufQ`E|$7SlV}Lw6a#F zb&uC%m%J1JW+!d_esm(mGhRb5UtCo2V!Zfz{T}FN=Fa1!3a#xUh4vfFEvp3)H5rI;R=ue7)}2e{rRfss%~i+pHv$YoF@=V>WnXd9Cq`_J|j zvf1su=YJ)>6}oYd;N|a>ooWG?!*|0cNCFekhPHJ2X6YZslJr#9&X699$4Wr*<(twT z!vo=PlXq9o16jg`c6Y@FT6C&pi%>?5fGhltRIOoVrzSNCQ#rb@b{jkpQY@Ul2`GOV z8RIC#jQerBpQV}eA7+JEHcR2l;3iS+Apj=MLV5< z%d6x)P&+Mjip@(rlt)Bb)D%l6Ce`ILCs&y?mFGY-ozx|E`l>H^FD!w}@?^phhw zGzG9G`BfwmDQGu3bXcw#?KgGUM7!5Q2LqL}>1;@ya{%Z}^;SvB-K`B8C5&&U61>UY zdA&o1mJy}J87qkP^8Li|VzKokp~KJXDD^0`_etvbr)XSa4tZG;v|!O_-(u523ZmxF zZBy;d4%mr>-dgdJIQEJJG6%Cc^P8>aBe<`%W)ASB{tz1b=Tt4$G58Z^amHP)@!V3a zJdc>FCeW|YnjVV={Q;|sS!CN3XyrV9S_4&*mdf`**K~|#I?qE zhV;Pv;y3=r**z=OfU*f9ZIUcX(-5SnR{hs1M{SyC#?S(4-){!CbPjVW2^|WP2zBcO zz#J6IVztGI>_y$XG(wfAtzA>IF}l-OQnf0Bn#SA}jhItOn48=$;0^G0+WU=u1{eCR zZ@FxzdXo89Z$*ZcKMk%owoY_zNRo!QuSV)#EyMJnl<%Z1<^GF76WmKxO65LVT!kR0 z3S|o++NsJwQI9PSR@6?ZCc>xIuxbqO%;iD!s#uO*`Bzt7zgInFp~X(lM?4{9Mb@8d zsZh~>OjjmzDX$2bkQjdL9XcVkeaz_6o2A(=Sqg|{h)Njv z*fDGJyJ%oQm^FuaU&)$$(vM5q9sV;1zEKN#@9Oa?e+q&`77_SA-d144N-6Kd-^{AcqjNiS6Tv0E&ji9p9)`nkC(M?6hcN7kFVQgxpXNi7BZXIwPf zp}lJ$Qu3fB?`OJne&6`>sE83uyXU5>_bSJyoGe)RXw_I_R0+dbCM3IFdA1@67L3xe zxvNmcq_1Ho1z!yP;;joMkei2h&D+6pApQ!qB zz0%m8)X;WW7DFSLtatignyg?Vzg-#89tJ?PO|7{QXEBlhJPGDIir}S=CGLQwuN< z8|W-BdvNfEkARLc2DLf9?-&-F#r&usKzmM&h;#b1Lq$m!w?eH*b}`E^y~>m|trfYR zwEuN3HBC=FHqjzIUHfoSe4YT1RgrlMohuj*s6#5Tw5rR%MFO18i_D`}fYYP{QozfW z=o=UEszK>fIjQNBr5u_l9*$)bD-u-Q?8B?K%->nUerr z1zD^|G|Uv&-N3?XRW@Y1PhYgu;dC>-W1Tq%%fw%SxiD1VrwVZIZxZ9 zJqL`Sf}A~n}y1XvX|Clxz9R}NQ6F{;{}ssc?C zmrx$A5c6j5gCr4`QyS~wQfH`8aQ@@Wp1E-_P*_z486)kXye#iCV$Ncc&4CvLsed>a z&!u3^0T)L%o1hg&kqYQaz`9V(7v?0w<;y^=mC(v~n8u`5q$3^NGA?sCRbHAhTB9s1 zk|%S2+<{0S-JuN3Yq(ZEBl#yqL#+!#BtF@ifX07DOCsW7?xK9{mD8J0-AP=#E8%2R z(_{R0v`V&~p_0<4z}v-z>#5!{Gd@ty2)*Iwb8WqQ^xrKk`*=&nuF*q*q^JB-8)(}8 z{TtZ*-Cg>a8~d>K`AZJBZi56Cw*%(8N)AL>e28Ta6uih2><5Hq(2g`mnd0ZLDZvCl zXl&%^KAy=ae9^uU?+iX87MrO}Z`Dvmr%ba!l zlj9{kKZVs8f^aB53z0Qv2b`GZ#?=i_dx2(4rliD#H`nGY%7n{D46ggvXr_9jcQc{Y z)aiKR*}0kbL(M`An-2ERlG(4lkUvsGS``T0x42Jv8MdD!-KU~H!TBEu&L%7Y%%7+2 zrI%7G>UkOA>Zwu*ovJ+=c8VNPTL{EtIjl$>{WZUHVpPoTC0C#D|j7WL6E4nG`=G>B0rq)8Ta=iY#K?Q5hI zX&Zx?Xu}f@EBJh--s+woHdtoY&Q|v)>QUqH_l3)`Nd~72FuGla?49E0YE4~lI|oK| z*;MhLS4^?K)|QE?pCl&xQ&aD>F3Lo)NQS?A3Asq);`UAqLt=5SId`G9n#-WZN@Y6rO=+YGrk1ZUqql4_pQb@7QUJ~zBWXUwe z%Qgj4JyV?=Ar%c-Td}%hZ|~2*HE{gN<8Zr7qgXbN81z(*{7a6IJr|ltcr2ojqO0R*@8eXvn4^b@>Y0%H+`G;kxTl}4g6Q2e^Ma_Y{jY7O#%5z;mS-3tX#ZM z?kH!)N#joJ)#fpskV-NjP;@T!oy`<;7d%_Gl3H8rz3V$W56zx0DVonmwl&JJ?Y%GW zjNbdz{u$jbET9G01N;0S`k*29axR>XG81dBh=T3Nbjgkrc&g{%Q|Mi^ta`XM?Ra%d zx~?8x?i^P=*KnyEmnyjy9~Aqk_=~u$mD!;x*H_NGl7EVhMD*6{6KQpS8glluq2-~I zmDxzAUXLezO{Nk}8&|j{9*VE#X0DIVGJ-Gk#_HVCeF>=vgS<&X35hn%@rsSP!43z)d~BmCX*NCUiUsvtB;V`qm^{( zrhBL}=+fcA3@LVGy=FTs6PGxCI_T1g5wqMM z_=(Pk)yy%G!%{WvQ5&sOfvLs+yzs&1ZXPSl9L7zTYXyu@BRtXKJ#Ge3DT7@dh0N2x z16$K{NP6(8HGro|H|RD9b`&}Ah<{vLpf8%LF6lDnlsm}qx~RpOzt$H7Bn&?ef`M}n zLwbKVQv8StkNIfhuA$!Z&i3$fjg9_dd;eYmeopCgcGc`+JD4oG*K)4FHDjGLq?$cq zO@}FJ4m={D0$_?CD22hQaZ5`5@=E>i-C&?R{&z~`{O`hlwf{ehf%#4DdmXxPiE+oa zE*rS8#gaQt&G5Z}r@ymjXRmOQwroIKIa_>V>qS#wO?1}Q6lqm&>{?`LJGv)d@;u)= z9(iKtRBaq;`1rZsyTTe27Nq*O<2uD!xi(J*U2K~#rS+bjx2s|d)$P$|RrW6zB(31G zA5>Sj7|E)FBZbMGnWYb5Xt9Q<1zYT_XKJJBKz79LX^uBI|Kxe+&mKnaVDX#`?k=5e zqwb>?x{i*Y$xc8xo^$g;6^m25*i?uGK7rv6rQb$JgDerw_;Qn`|JFn6SJhN z<9%<2Jf9KUVKI6HG=2P^yhrqbss8^`XMk?~PUslR^J^-c)am@^kyN8qao2EV2<$?U z&MkfM6VUgu16qVS$nD|PWbraTQ21;zP@B$BPxYgEBN0@8s!rgci)`3&@DuvoZ5sTx z8+ZySd*2&-e`IiXG?y!+c8AK3%c%eI5u!?;`Cqp#n{&J4u(?X7aDEI7mdt)&A`1|U z_(R%UxEcn`(%-v#6zKa-I7HnRLB<9{hYq!%oywugrqK2qIG<;NWqZ;qCM6YfF3Y?8 zpI>xU>T$U!`)vE%JCgKMzN0|v>QnKra@i-;TZrp3*f06(=iyj#JFd~(W=vd%coOE3 z5ITyEmiUPY=cTpknYyx8{+CfIhj-AwG5IT*Q}*7e>A>|NY2sH8O@E|E<0jK|`I}c% zRFwVQ*Xil&J@Lyoij4O6c`nmgfAGkc8m*pTw$#|#z1G%?sK3hnIWVa&9O8@uqc=G+ zSi*{NQ8J0wLXOQ;UO$POG7E7WM{K~wz5#^|VTDuGSeUEI3#WF73A@^*rcbV`#!sBsC;whLFCVapXwijUJkMHU z-G#DtckO;jIkehDt`M|aXc(qkHW)~-qD7Jkq8eDId19cegf6(T6MwkZdkl(tR<2O# zDyD?)ulK8T0>8O2y8f(%J6~__20gja*}vb8B&(eKLf2+{K7N1cH~*gQovrK7{61d2 zEB?fey01jT<&dHqthDMa%9Q9wl#pc557v?=X69DHX5xn;|3UPntmQ}cX8&u8F$%2e z8Po8V{TM~uInugjL_Ti^L=Km^ZVeIoK>%;pw>WKH_^nj;0`9DcsEx#DHBVYCSFtK# zai*%^d@)44k{Mv54o*O{(-=Yek28)}yE?zhD(WlXT4aK{X4yaOqfApgDCJ`T4*rvk zP5u{iMoVK~RZpIBVvpaQ$=sBiR9mD3b*rQ5f_mM>TJCkCS5mXu6hF3 zlWZ2|+t=xi%J+A7e*aZe_T!g6M_H7S)zQ82A(W`Hc)vmWr#Y6$C;Cj09_ah;H};`X zEiYN3QEc30VjfPyk=$VeW9%?;yvwr@XE(W9!r>2PeyY=gh2V2jL;660VK^=|@1&|l z9V!B9jpNBJ@S6Z`NT+MfSk_M^hmyH#jTaD%=|cryd4M%&9mtdV%T9pxty9J_V~7ynPlU~mV@2xZ7giS%!=dtXS;&so@e-_Tv&>R;T$ z@;LGYU>{iZtjbtv3>t4gZ3&XO3Rm|b*J_)ED=GM9>!ueS4$*ly$K=}ai4&!i6hPtw zAk*yQ<~$;|I&A)z0?jQ5YI>mN+mKEmf8JR=pJ8MVF|FUi6P)vFW8v)F{mL}_N0b8f zZ8Z~^^67VHey8#4z4rUN^m|v-{ed$go$5}SY#{7Vz{poe^6bEpGLoeIq}Qgla!IA` z!!efPfOqVGIQw^+{l$v`)-33@Jv#Z6_x0iBcYnXJ^gCD7okh=&ZB)L`Pf>30533_~ zA2Df;WB_K+Si1n@R7NvA#w;`_TIj+WFw1BTBx9`1QZN~D+BIJg_s}?V3cvP>CrVp0 zJk*_(4C@-4aS^)9a?tmo3i5}4D-hOL1_%k1Js2*u-GAZ=M>~cs+RhqOrtEeRXeTG? zKeMQk*)-^O;+OKta(bM0zUHgfoj&(E;x|3_iepV0SUS!TH59)P$zoI51$m_<6WK|5 z)5byfOPYwG()#yLGrU_Qp@1R8_98+h^I+HyC}-CSF^x!Pg`3c?yrm9fXonih{5Cgx za@+J_xWIy7Vu)Y{>~1Bqdr%E@qOWZqz}Wx~Qfu)P=J0Pw_RG0&>3Qb^F0^S3AwrF| zO=XKds(~YxCyi8Hd?rmC&>Qw;g$KDMjq{ofyswbYnSRUXtwsPhx9(%n!*7@8!g(~u zpScl<-&uK|-`~Bxz46~i@>yY5xYMD2;KAk%Xn1tQ^l5f04o$l{*E{T)L&_l^e*y;| zb+;y!e|uwOQl#yqa3^d7iQrR&D0WvjeM|!wXG#*8m^+9R;NY+XqnPl1GHitYasVi7 zEE)?Z7%d7Ej$>BxfraT9j6wu{>`ry@QZObf7;_c8bF63T^{~iz)y0GvuLO_a5p2RK zHz6aR4;*TAaDLAEDLvoAq)8%!}E11D-L_5eBx zO_UGOF2v!|rN^`AvkXDdRI|bsmK;MqWRGZL-K9H-BxKQeO$5HQn2MjFld;E#2r%{S zaG}R2qV!w-56&Xx>`RkIm4Ce#ePzE6Up3rUe6C=D`oGq%O^z_nFHjwY9|&ESF}lyY zQTy7SY*w!$xB0(F8{MyW9h;on{xh+G`ld_)KXohJ7+J2IrJQru*;&2p*Do`BZ_^ka z-}G6ov>k^tfT&M=tfjn;?06uTdCZ(Hi`S9s!y9+kFQ3wv2F@GkG}=!=v%x%WY**Qx ztkzIEH%9CyQ5>^Znf%pTXHVMD?H%>gg2jKV`I~_{cpSEz-Skm9&9k$@ip?*X_mw|# zdyr(`{h#`;SIZbW&$F_egNWF!dtIA6Jhx>f9=H2PUEAGj{);cdpH)Pb&!e>*gBj!{ zb%Cz690$o}wcCL&<87O_;Wk-Mo`?FMMqQwXKXzG4-m5syE_vKnF<|^U2%qSj%=|My zlJZ5H$j=@);KFfO3`7ff6T7w|*Ex#)Q?TR&^oXQ`3PtBvtkB+X5!-uTrnHw(66Na>LeFsbtpk z{3Lu~Gl!FA$cncx^Xvo%U2jl>Qf2`Vq)kHV7iA(QcLK0h>(Te1q{B=P3+kSQFY`nD ztrR4~Xt}@QrMTdTQ2!7ESqu^Lm~@!QBuC{J+GyxIKtUqL+|APK2UXg8We;Tz`Z)gbep^=O%duPC zg!e+)g5zl;>pSd?*(Iu1jrd0r$?9gZM*lsOzk)*Zm*!6-zRCCpVk=JE0em>7sQMa) z{%_7jd-;m4eWh6C^KO3-tlr(4hDV64$WIF$iJ!bxMa|N6HL=9Dh)TCR$QH?>7)gp? zC_j=7El+t63zacbD)Ah0-0I{i8y62c<_rYDQywOxIV0#`FjDU8$v2mFA#pK+23u42 zdZb)pB!PWCV@%+1SM3L>;x8iTp7;+yE=}`hDV0TuVUJ>eW>y+ha0m_^7TdKoXCh+9 zt>jYy%!CE!IEJm~mG6x&9r~e?u7#C_&hTu+&~^(p3@dO#IWJLQc*Qc=LpIO&kn!;x zsp!((#2YGt>uoLCfLKnuravy~vX(V8gL*>yB`o-@tV1!tC=iHFZ>cxrX4u=6gqrbL z@ZGU_^CC+7S=znxnvJ)K9{4EZUaf_46Pfvo>pmZA>vq@RIKS=v{XJ}6>e|AI>4hyb zKJE#B;e6^H;}968MHEBOo`)9oP_f*h7?z%7$djR8V#E+2r%Dglb>X{h%HvB8qI==O zk);~82`Xh9@DKFAOQDvNaS~=r7QaG@>u|WH$k7Y+ECGgBFz&J>4mNcpvpBPjQ0WMQ zA$B9^VTGRdVa#`<{b|ax|9G5TS0LSxNln<-X(wce&i6+mydH3kUgXEiN+Y) zZTV{L?qxO3g+Zy0kB6I!eOe==7AVHVS2;Y_OXuT_rce|l6RsA>Q?Bf|Uq6y*{yW~K z+LSqp97tl-Cv4DtrdixHMi-?LM+ouPv* zx~Ow#LQ@>XlMeGQ1g?qHxFSC)3OS5=APf(T!I67pNgQw#l!#)MKd;05v=QkiIUnPd z8SMdL0jz@J0|d=$qEA{lIc z_%xCbK)|1sZaX}fl5!M#27Lz50pM^faYgCoOQE!^#}N|&eGK`dDdXjTSlaY?^sGOn z(BErHVt7pX$XbbE5D8bd@PjQAX-9_b-*jV~2D36MnydB1o zsG6Ib=fp}1>UACty1EJR-2DbjH-9!wvnLN<#xG@Njh+J zriBbCf&S4+4P~eQRXqQK!-)UqFWzufY^|(ar<@?&Ly_1O5M!e@n6a?(N`h{RD&P5k zppwr8Eq8@3g8h}UbWq3^u2wn88t%CPj!C!=0grYfi?)5sE9t~99(niVDn)f^Bz)8T zV(=GOyV*}u)BmpYWA{_*)2@bufQtihF2*Fb5#Sson(xWtMftx)z@ur7*d#QN^ufne zjVgs1!j|x7neMq%4o^;uoS+kzv|_nq1sX(+H>(ER^RH4m4Y(d*VDRqn<(Tp<%9ef5 z&w@k6c>D&CUG^PKC(Nx*o)1kff40?o4>lyrPv2)UBNL|!%CHfypk zst+wMm^?>O-+%7bQv%spK7i6W# zK#0Pul?te{5ChLI$v>6_I>sk%Ad_sb;2f#6&`h{g_GQum8NNHmii?6{avHDJd~7<) z>cVsxy`|;sez|uqm8GLxJ@t*#Qf1t61e`yM)Axd+)BHxi2kyWtc-y{8?9oqw}R6=ac#Wzv`~j0N*6 z@K5djH&Yv;IF%I^goJr7**_+;TT%WWZ#UG47#IK)E{38usi?A%qj0iq`X*Ovd6DjS zJ8@Ca2ZMpB8UqdvEpwTA!vZ#k4|OHPr-p z+5M^MKVD@6iRreZpqhUk*wGR53i*@UW7dO6s&IxViqUM}ck7Ko1g;ITn*R%OoFk=5 zGFH3ePeT^Jx#~T=#2kOHzHxGW@!`R8ils^$*_>Rew7|evf0NCF%IXEnBpShBAyhrt z3$9pRY`O9$YeOMAXfBwPEdy1rl5&uD49ZeR11^*9J5|0cn5~}ADaWSy)I#0{Q$69qh$ED5)8#_;M_6_M>!Np9EU>m3sBWLv@=>O`1@Ge4{8{>4M+`d-ZMywdc?VY!TI{izb0uRHu3 zljn|H2hwODwt|qd&UhesQiW$FrhUfzgMTCB!&BM$-ZOx>asz+r5{|5BVCd?DyN(H< zu4G<-Za@y>IJ1=Pw$y$BN#qqhY-_F?sVdILI|r2ZLy(R**rrrcKxpptrMGIbN0Bpd6KGOb3Cum|i-4G{`uHxuOl*=Pw&XEf?hwHQt zL#u}zZX9Y~)X7(J@zYfuRYp5LX$Wd?G(xJA?Y&( z3&=SZkV#d>nuWUjpPAZri}y_PDhOoFL5p>)xCK~#28aqbc{!By=Cg)Kl`D5g9tt&H zmcao^hD^avEW}wMitoreTy9JY{MDrTjNkE+Tph-=E6Yex|Yw;M0rib?K)8 zA1sj}2&uW73>=+^oBKl(ax&Q+kRzQuOA`;a!}@DhktK>ziNMB;ixCNEKW&_Fd}*spg*bE z?#-@9D$~^%|;5I5S%~%auW?3pDKh8(0orOuEBg z1a1&)UNlJoI&gLYjsqi^%L5P3rrD)9>;-49>`h^x%4$j-_elAXyRLNlJh3*=V_9!r zbXwX{$`D9l$<=g;lN8%l94Jsrcwuufr6>@nj6Fgy(x)d!yxvE<%G74yCWNHMC?{wU znlC}b?(9x2yn36B2++1Xyt*+=qWQ7V`!+k@HqM^#*jX zW0tNhP0UfM4pEnRc6e#`6(KJDU(~MlmT$X%-)rIm#;-!wr=PkEFTA;SV_fDDy)`c< zeiEsSuK}10G5#K&f@5{cuu$N)Ex{J7=zj&51!($yvQ{z*!V;9fIj(v)UqFdYQ&LIE z;f!WTRRR^#NlquR{*($sF~C->VS_Yl)Y#HcAC!vP-1=Z?sagYu$ie9WC#kYp(4ES# zmc)=zk?KsSIK9}}kq3)!h=egng{M%cax_zH=#=9Crbtj$1^i^Cl^l5`%eCpE)Wy3w z;_!|J-*HJAMW}+gA}DHg-N3Xop}8V_dpntN8&Y|m_Iuxr;j|CqSKU$0lrvqw{S36c zJBkwohjx%NH!xv_IRlqW<)%qO2E!gUCudZ7t^GY>AnbG3!0hw7~+ue2qPb+m^*VBm4A^ZL@SHCQ2Mg83VO7-8c5*c z5X&4D-a?%&Ae_vSvjKWyCdUYX1V;TQjt-3@vygP@O(0Burlzo%ItCeG|9DtN`EPHZ z$a!{>TJxGXdC%wQaCdZZyahO5aU|xr=cSXCVVrhMOAF(o5Y#cKCkPuT$tr?d^iaFG zLNp*JqKu{7B}7idc+wM2wVXgnbs-;ifbzMp$z(L7Fv;X9N8xp?QlLn_$Lhdj+uRK= zyDkh|c@jd9xM3ZxAxxUg*b^)42Aqop)dYD$2C3y)dX_XvMh_7RT* zt>2mjo(!F18Ri5_QPmnkRu&Gqn8~vv`npgYB7^FH&m$Vo6zBQ*kw_)Kgrvm3n@ko# zFJg_G?0-7n{%;s#XC6ppdWtzB9%~6+GUl?>z91HUe36ry$C|McU1Y8Q)Lwj1!e*5W zY;SYyhYcCB`>)w$(e}2!O`=r+F=vgcFQdgb>W}?^Z!-}+}6rm$3-%;I4&%3 z6q9_QtT{~7DM@rJ4Pek8b$_(T#T18>Xw!o1VMOo|3NVeCrT3OI43Ju|Xs^A}wm zkavR?4CaUdag`s?Gsww^u-tfQX9TuNN3wHF$`*(Sy8=3e5Jj9IZ&&wCEM6sTYunp@ zjVVXKBjj9>V5Ylynvwu=*sO?tB41f=@-P8<{?7mKm>0!lcGkXt-x6U+DbcITW7P{R!u zGW0IWyY<^s6;7C9zmxd8Ff3>sC9^>V??v(izfc;9lK{Y#^a z&85yFB>6-}+Oqqb&MkAB26iVNo$UIE1ST`hmXvW%IS8Jfr|0Q;dhX@<{{sL3|Njcl J3|s(q0RW%V