From ac8b2660fd64233ee6154fd33e9059096a5df179 Mon Sep 17 00:00:00 2001 From: aajimal Date: Tue, 4 Jun 2024 11:52:12 -0700 Subject: [PATCH 01/18] Add scaffold folder reference --- charts/helm-cronjobs/.helmignore | 1 + charts/helm-cronjobs/Chart.yaml | 12 ++ charts/helm-cronjobs/LICENSE | 201 ++++++++++++++++++ charts/helm-cronjobs/README.md | 145 +++++++++++++ charts/helm-cronjobs/templates/_helpers.tpl | 55 +++++ charts/helm-cronjobs/templates/cronjob.yaml | 88 ++++++++ .../templates/image-pull-secret.yaml | 12 ++ .../templates/serviceaccount.yaml | 20 ++ charts/helm-cronjobs/values.yaml | 99 +++++++++ 9 files changed, 633 insertions(+) create mode 100644 charts/helm-cronjobs/.helmignore create mode 100644 charts/helm-cronjobs/Chart.yaml create mode 100644 charts/helm-cronjobs/LICENSE create mode 100644 charts/helm-cronjobs/README.md create mode 100644 charts/helm-cronjobs/templates/_helpers.tpl create mode 100644 charts/helm-cronjobs/templates/cronjob.yaml create mode 100644 charts/helm-cronjobs/templates/image-pull-secret.yaml create mode 100644 charts/helm-cronjobs/templates/serviceaccount.yaml create mode 100644 charts/helm-cronjobs/values.yaml diff --git a/charts/helm-cronjobs/.helmignore b/charts/helm-cronjobs/.helmignore new file mode 100644 index 0000000..4032ec6 --- /dev/null +++ b/charts/helm-cronjobs/.helmignore @@ -0,0 +1 @@ +.git/ \ No newline at end of file diff --git a/charts/helm-cronjobs/Chart.yaml b/charts/helm-cronjobs/Chart.yaml new file mode 100644 index 0000000..3164d5a --- /dev/null +++ b/charts/helm-cronjobs/Chart.yaml @@ -0,0 +1,12 @@ +apiVersion: v2 +name: helm-cronjobs +description: A chart for cron jobs +version: 2.0.0 +keywords: + - cron +home: "https://github.com/bambash" +sources: + - "https://github.com/bambash" +maintainers: + - name: bambash + email: bambash256@gmail.com diff --git a/charts/helm-cronjobs/LICENSE b/charts/helm-cronjobs/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/charts/helm-cronjobs/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/charts/helm-cronjobs/README.md b/charts/helm-cronjobs/README.md new file mode 100644 index 0000000..8ec821a --- /dev/null +++ b/charts/helm-cronjobs/README.md @@ -0,0 +1,145 @@ +# helm-cronjobs +You can define an array of jobs in values.yaml helm will take care of creating all the CronJobs. + +## How to use as a starter chart + +1. Find your Helm data directory, `HELM_DATA_HOME` + + ``` + helm env + ``` + +1. `cd` to this directory, then + + ``` + mkdir starters + cd starters + ``` + +1. Clone this repo + +1. In your cronjob project, set up your new chart with + + ``` + helm create -p helm-cronjobs your_chart_name + ``` + +## Configuration + +Via `values.yaml` + +### Overview + +```yaml +jobs: + jobname-1: + # job definition + jobname-2: + # job definition + jobname-n: + # job definition +``` + +### Details + +```yaml +jobs: + ### REQUIRED ### + : + image: + repository: + tag: + imagePullPolicy: + schedule: "" + failedJobsHistoryLimit: + successfulJobsHistoryLimit: + concurrencyPolicy: + restartPolicy: + ### OPTIONAL ### + imagePullSecrets: + - username: + password: + email: + registry: + env: + - name: ENV_VAR + value: ENV_VALUE + envFrom: + - secretRef: + name: + - configMapRef: + name: + command: [""] + args: + - "" + - "" + resources: + limits: + cpu: + memory: + requests: + cpu: + memory: + serviceAccount: + name: + annotations: # Optional + my-annotation-1: + my-annotation-2: + nodeSelector: + key: + tolerations: + - effect: NoSchedule + operator: Exists + volumes: + - name: config-mount + configMap: + name: configmap-name + items: + - key: configuration.yml + path: configuration.yml + volumeMounts: + - name: config-mount + mountPath: /etc/config + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + - e2e-az2 +``` + +## Examples +``` +$ helm install test-cron-job . +NAME: cold-fly +LAST DEPLOYED: Fri Feb 1 15:29:21 2019 +NAMESPACE: default +STATUS: DEPLOYED + +RESOURCES: +==> v1/CronJob +NAME AGE +cold-fly-hello-world 1s +cold-fly-hello-ubuntu 1s +cold-fly-hello-env-var 1s +``` +list cronjobs: +``` +$ kubectl get cronjob +NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE +cold-fly-hello-env-var * * * * * False 0 23s 1m +cold-fly-hello-ubuntu */5 * * * * False 0 23s 1m +cold-fly-hello-world * * * * * False 0 23s 1m +``` +list jobs: +``` +$ kubectl get jobs +NAME DESIRED SUCCESSFUL AGE +cold-fly-hello-env-var-1549056600 1 1 45s +cold-fly-hello-ubuntu-1549056600 1 1 45s +cold-fly-hello-world-1549056600 1 1 45s +``` diff --git a/charts/helm-cronjobs/templates/_helpers.tpl b/charts/helm-cronjobs/templates/_helpers.tpl new file mode 100644 index 0000000..9356ff5 --- /dev/null +++ b/charts/helm-cronjobs/templates/_helpers.tpl @@ -0,0 +1,55 @@ +{{/* vim: set filetype=mustache: */}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cronjobs.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cronjobs.labels" -}} +helm.sh/chart: {{ include "cronjobs.chart" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Expand the release name of the chart. +*/}} +{{- define "cronjobs.releaseName" -}} +{{- default .Release.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + + +{{/* +Create payload for any image pull secret. +One kube secret will be created containing all the auths +and will be shared by all the job pods requiring it. +*/}} +{{- define "cronjobs.imageSecrets" -}} + {{- $secrets := dict -}} + {{- range $jobname, $job := .Values.jobs -}} + {{- if hasKey $job "imagePullSecrets" -}} + {{- range $ips := $job.imagePullSecrets -}} + {{- $userInfo := dict "username" $ips.username "password" $ips.password "auth" (printf "%s:%s" $ips.username $ips.password | b64enc) -}} + {{- if hasKey $ips "email" -}} + {{ $_ := set $userInfo "email" $ips.email -}} + {{- end -}} + {{- $_ := set $secrets $ips.registry $userInfo -}} + {{- end -}} + {{- end -}} + {{- end -}} + {{- if gt (len $secrets) 0 -}} + {{- $auth := dict "auths" $secrets -}} + {{/* Emit secret content as base64 */}} + {{- print ($auth | toJson | b64enc) -}} + {{- else -}} + {{/* There are no secrets*/}} + {{- print "" -}} + {{- end -}} +{{- end -}} \ No newline at end of file diff --git a/charts/helm-cronjobs/templates/cronjob.yaml b/charts/helm-cronjobs/templates/cronjob.yaml new file mode 100644 index 0000000..2e1ae3d --- /dev/null +++ b/charts/helm-cronjobs/templates/cronjob.yaml @@ -0,0 +1,88 @@ +{{- range $jobname, $job := .Values.jobs }} +--- +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "cronjobs.releaseName" $ }}-{{ $jobname }} + labels: + {{- include "cronjobs.labels" $ | nindent 4 }} +spec: + concurrencyPolicy: {{ $job.concurrencyPolicy }} + failedJobsHistoryLimit: {{ $job.failedJobsHistoryLimit }} + jobTemplate: + spec: + template: + metadata: + labels: + app: {{ include "cronjobs.releaseName" $ }} + cron: {{ $jobname }} + spec: + {{- if hasKey $job "imagePullSecrets" }} + imagePullSecrets: + - name: {{ $.Release.Name }}-docker + {{- end }} + {{- if and (hasKey $job "serviceAccount") (hasKey $job.serviceAccount "name") }} + serviceAccountName: {{ $job.serviceAccount.name }} + {{- else }} + serviceAccountName: {{ $.Release.Name}}-{{ $jobname }} + {{- end }} + {{- if hasKey $job "securityContext" }} + {{- if $job.securityContext.runAsUser }} + securityContext: + runAsUser: {{ $job.securityContext.runAsUser }} + {{- if $job.securityContext.runAsGroup }} + runAsGroup: {{ $job.securityContext.runAsGroup }} + {{- end }} + {{- if $job.securityContext.fsGroup }} + fsGroup: {{ $job.securityContext.fsGroup }} + {{- end }} + {{- end }} + {{- end }} + containers: + - image: {{ $job.image.repository }}:{{ $job.image.tag }} + imagePullPolicy: {{ $job.image.imagePullPolicy }} + name: {{ $jobname }} + {{- with $job.env }} + env: +{{ toYaml . | indent 12 }} + {{- end }} + {{- with $job.envFrom }} + envFrom: +{{ toYaml . | indent 12 }} + {{- end }} + {{- with $job.command }} + command: +{{ toYaml . | indent 12 }} + {{- end }} + {{- with $job.args }} + args: +{{ toYaml . | indent 12 }} + {{- end }} + {{- with $job.resources }} + resources: +{{ toYaml . | indent 14 }} + {{- end }} + {{- with $job.volumeMounts }} + volumeMounts: +{{ toYaml . | indent 12 }} + {{- end }} + {{- with $job.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 12 }} + {{- end }} + {{- with $job.affinity }} + affinity: +{{ toYaml . | indent 12 }} + {{- end }} + {{- with $job.tolerations }} + tolerations: +{{ toYaml . | indent 12 }} + {{- end }} + restartPolicy: {{ $job.restartPolicy }} + {{- with $job.volumes }} + volumes: +{{ toYaml . | indent 12 }} + {{- end }} + schedule: {{ $job.schedule | quote }} + successfulJobsHistoryLimit: {{ $job.successfulJobsHistoryLimit }} +{{- end }} diff --git a/charts/helm-cronjobs/templates/image-pull-secret.yaml b/charts/helm-cronjobs/templates/image-pull-secret.yaml new file mode 100644 index 0000000..9df47db --- /dev/null +++ b/charts/helm-cronjobs/templates/image-pull-secret.yaml @@ -0,0 +1,12 @@ +{{- $secret := (include "cronjobs.imageSecrets" .) -}} +{{- if gt (len $secret) 0 }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Release.Name }}-docker + labels: + {{- include "cronjobs.labels" . | nindent 4 }} +type: kubernetes.io/dockerconfigjson +data: + .dockerconfigjson: {{ $secret }} +{{- end -}} diff --git a/charts/helm-cronjobs/templates/serviceaccount.yaml b/charts/helm-cronjobs/templates/serviceaccount.yaml new file mode 100644 index 0000000..d2c6930 --- /dev/null +++ b/charts/helm-cronjobs/templates/serviceaccount.yaml @@ -0,0 +1,20 @@ +{{- range $jobname, $job := .Values.jobs }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + {{- if and (hasKey $job "serviceAccount") (hasKey $job "serviceAccount.name") }} + name: {{ $job.serviceAccount.name }} + {{- else }} + name: {{ $.Release.Name}}-{{ $jobname }} + {{- end }} + labels: + {{- include "cronjobs.labels" $ | nindent 4 }} + cron: {{ $jobname }} + {{- if and (hasKey $job "serviceAccount") (hasKey $job "serviceAccount.annotations") }} + {{- with $job.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/helm-cronjobs/values.yaml b/charts/helm-cronjobs/values.yaml new file mode 100644 index 0000000..4c65ffd --- /dev/null +++ b/charts/helm-cronjobs/values.yaml @@ -0,0 +1,99 @@ +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +jobs: + # first cron + hello-world: + image: + repository: hello-world + tag: latest + imagePullPolicy: IfNotPresent + schedule: "* * * * *" + failedJobsHistoryLimit: 1 + successfulJobsHistoryLimit: 3 + concurrencyPolicy: Allow + restartPolicy: OnFailure + imagePullSecrets: + - username: fred + password: password + registry: docker.io + # second cron + hello-ubuntu: + image: + repository: ubuntu + tag: latest + imagePullPolicy: Always + schedule: "*/5 * * * *" + command: ["/bin/bash"] + args: + - "-c" + - "echo $(date) - hello from ubuntu" + resources: + limits: + cpu: 50m + memory: 256Mi + requests: + cpu: 50m + memory: 256Mi + failedJobsHistoryLimit: 1 + successfulJobsHistoryLimit: 3 + concurrencyPolicy: Forbid + restartPolicy: OnFailure + imagePullSecrets: + - username: joe + password: password2 + email: joe@example.com + registry: quay.io + # third cron + hello-env-var: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 2000 + image: + repository: busybox + tag: latest + imagePullPolicy: Always + # optional env vars + env: + - name: ECHO_VAR + value: "busybox" + envFrom: + - secretRef: + name: secret_data + - configMapRef: + name: config_data + schedule: "* * * * *" + command: ["/bin/sh"] + args: + - "-c" + - "echo $(date) - hello from $ECHO_VAR" + - "echo $(date) - loaded secret $secret_data" + - "echo $(date) - loaded config $config_data" + serviceAccount: + name: "busybox-serviceaccount" + resources: + limits: + cpu: 50m + memory: 256Mi + requests: + cpu: 50m + memory: 256Mi + failedJobsHistoryLimit: 1 + successfulJobsHistoryLimit: 3 + concurrencyPolicy: Forbid + restartPolicy: Never + nodeSelector: + type: infra + tolerations: + - effect: NoSchedule + operator: Exists + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/e2e-az-name + operator: In + values: + - e2e-az1 + - e2e-az2 From 5bf6c47739662445e18f4acd2a2f006b4a3ec009 Mon Sep 17 00:00:00 2001 From: aajimal Date: Tue, 4 Jun 2024 12:47:40 -0700 Subject: [PATCH 02/18] Add sample chart for spamoor --- charts/helm-cronjobs/Chart.yaml | 12 --- charts/helm-cronjobs/values.yaml | 99 ------------------- .../.helmignore | 0 charts/spamoor-cronjobs/Chart.yaml | 6 ++ .../LICENSE | 0 .../README.md | 56 +++++------ .../templates/_helpers.tpl | 0 .../templates/cronjob.yaml | 1 + .../templates/image-pull-secret.yaml | 1 + .../templates/serviceaccount.yaml | 1 + charts/spamoor-cronjobs/values.yaml | 31 ++++++ 11 files changed, 63 insertions(+), 144 deletions(-) delete mode 100644 charts/helm-cronjobs/Chart.yaml delete mode 100644 charts/helm-cronjobs/values.yaml rename charts/{helm-cronjobs => spamoor-cronjobs}/.helmignore (100%) create mode 100644 charts/spamoor-cronjobs/Chart.yaml rename charts/{helm-cronjobs => spamoor-cronjobs}/LICENSE (100%) rename charts/{helm-cronjobs => spamoor-cronjobs}/README.md (67%) rename charts/{helm-cronjobs => spamoor-cronjobs}/templates/_helpers.tpl (100%) rename charts/{helm-cronjobs => spamoor-cronjobs}/templates/cronjob.yaml (98%) rename charts/{helm-cronjobs => spamoor-cronjobs}/templates/image-pull-secret.yaml (90%) rename charts/{helm-cronjobs => spamoor-cronjobs}/templates/serviceaccount.yaml (94%) create mode 100644 charts/spamoor-cronjobs/values.yaml diff --git a/charts/helm-cronjobs/Chart.yaml b/charts/helm-cronjobs/Chart.yaml deleted file mode 100644 index 3164d5a..0000000 --- a/charts/helm-cronjobs/Chart.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v2 -name: helm-cronjobs -description: A chart for cron jobs -version: 2.0.0 -keywords: - - cron -home: "https://github.com/bambash" -sources: - - "https://github.com/bambash" -maintainers: - - name: bambash - email: bambash256@gmail.com diff --git a/charts/helm-cronjobs/values.yaml b/charts/helm-cronjobs/values.yaml deleted file mode 100644 index 4c65ffd..0000000 --- a/charts/helm-cronjobs/values.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. -jobs: - # first cron - hello-world: - image: - repository: hello-world - tag: latest - imagePullPolicy: IfNotPresent - schedule: "* * * * *" - failedJobsHistoryLimit: 1 - successfulJobsHistoryLimit: 3 - concurrencyPolicy: Allow - restartPolicy: OnFailure - imagePullSecrets: - - username: fred - password: password - registry: docker.io - # second cron - hello-ubuntu: - image: - repository: ubuntu - tag: latest - imagePullPolicy: Always - schedule: "*/5 * * * *" - command: ["/bin/bash"] - args: - - "-c" - - "echo $(date) - hello from ubuntu" - resources: - limits: - cpu: 50m - memory: 256Mi - requests: - cpu: 50m - memory: 256Mi - failedJobsHistoryLimit: 1 - successfulJobsHistoryLimit: 3 - concurrencyPolicy: Forbid - restartPolicy: OnFailure - imagePullSecrets: - - username: joe - password: password2 - email: joe@example.com - registry: quay.io - # third cron - hello-env-var: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 2000 - image: - repository: busybox - tag: latest - imagePullPolicy: Always - # optional env vars - env: - - name: ECHO_VAR - value: "busybox" - envFrom: - - secretRef: - name: secret_data - - configMapRef: - name: config_data - schedule: "* * * * *" - command: ["/bin/sh"] - args: - - "-c" - - "echo $(date) - hello from $ECHO_VAR" - - "echo $(date) - loaded secret $secret_data" - - "echo $(date) - loaded config $config_data" - serviceAccount: - name: "busybox-serviceaccount" - resources: - limits: - cpu: 50m - memory: 256Mi - requests: - cpu: 50m - memory: 256Mi - failedJobsHistoryLimit: 1 - successfulJobsHistoryLimit: 3 - concurrencyPolicy: Forbid - restartPolicy: Never - nodeSelector: - type: infra - tolerations: - - effect: NoSchedule - operator: Exists - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/e2e-az-name - operator: In - values: - - e2e-az1 - - e2e-az2 diff --git a/charts/helm-cronjobs/.helmignore b/charts/spamoor-cronjobs/.helmignore similarity index 100% rename from charts/helm-cronjobs/.helmignore rename to charts/spamoor-cronjobs/.helmignore diff --git a/charts/spamoor-cronjobs/Chart.yaml b/charts/spamoor-cronjobs/Chart.yaml new file mode 100644 index 0000000..6617cfe --- /dev/null +++ b/charts/spamoor-cronjobs/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +appVersion: 0.1.0 +description: A Helm chart for Kubernetes +name: spamoor-cronjobs +type: application +version: 0.1.0 diff --git a/charts/helm-cronjobs/LICENSE b/charts/spamoor-cronjobs/LICENSE similarity index 100% rename from charts/helm-cronjobs/LICENSE rename to charts/spamoor-cronjobs/LICENSE diff --git a/charts/helm-cronjobs/README.md b/charts/spamoor-cronjobs/README.md similarity index 67% rename from charts/helm-cronjobs/README.md rename to charts/spamoor-cronjobs/README.md index 8ec821a..925be1b 100644 --- a/charts/helm-cronjobs/README.md +++ b/charts/spamoor-cronjobs/README.md @@ -1,28 +1,22 @@ -# helm-cronjobs -You can define an array of jobs in values.yaml helm will take care of creating all the CronJobs. +# spamoor-cronjobs +You can define an array of jobs in values.yaml helm will take care of creating all of the CronJobs. -## How to use as a starter chart +Credit: [helm-cronjobs](https://github.com/bambash/helm-cronjobs) used as scafolding for this chart. -1. Find your Helm data directory, `HELM_DATA_HOME` +## Getting started - ``` - helm env - ``` +`helm create -p ` -1. `cd` to this directory, then + ``` + helm create -p helm-cronjobs spamoor-cronjobs + ``` - ``` - mkdir starters - cd starters - ``` - -1. Clone this repo - -1. In your cronjob project, set up your new chart with +## For debugging +`helm template --dry-run --debug -name ` +``` +helm template --dry-run --debug -name cronjobs spamoor-cronjobs +``` - ``` - helm create -p helm-cronjobs your_chart_name - ``` ## Configuration @@ -115,31 +109,27 @@ jobs: ## Examples ``` $ helm install test-cron-job . -NAME: cold-fly -LAST DEPLOYED: Fri Feb 1 15:29:21 2019 -NAMESPACE: default -STATUS: DEPLOYED +NAME: test-cron-job +LAST DEPLOYED: Tue Jun 4 12:27:32 2024 +NAMESPACE: spamoor-cronjobs +STATUS: deployed +REVISION: 1 +TEST SUITE: None RESOURCES: ==> v1/CronJob NAME AGE -cold-fly-hello-world 1s -cold-fly-hello-ubuntu 1s -cold-fly-hello-env-var 1s +test-cronjob-curl 1s ``` list cronjobs: ``` $ kubectl get cronjob -NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE -cold-fly-hello-env-var * * * * * False 0 23s 1m -cold-fly-hello-ubuntu */5 * * * * False 0 23s 1m -cold-fly-hello-world * * * * * False 0 23s 1m +NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE +test-cron-job-curl * * * * * False 1 5m23s 5m49s ``` list jobs: ``` $ kubectl get jobs NAME DESIRED SUCCESSFUL AGE -cold-fly-hello-env-var-1549056600 1 1 45s -cold-fly-hello-ubuntu-1549056600 1 1 45s -cold-fly-hello-world-1549056600 1 1 45s +test-cron-job-curl-28625488 0/1 6m6s 6m6s ``` diff --git a/charts/helm-cronjobs/templates/_helpers.tpl b/charts/spamoor-cronjobs/templates/_helpers.tpl similarity index 100% rename from charts/helm-cronjobs/templates/_helpers.tpl rename to charts/spamoor-cronjobs/templates/_helpers.tpl diff --git a/charts/helm-cronjobs/templates/cronjob.yaml b/charts/spamoor-cronjobs/templates/cronjob.yaml similarity index 98% rename from charts/helm-cronjobs/templates/cronjob.yaml rename to charts/spamoor-cronjobs/templates/cronjob.yaml index 2e1ae3d..71a6339 100644 --- a/charts/helm-cronjobs/templates/cronjob.yaml +++ b/charts/spamoor-cronjobs/templates/cronjob.yaml @@ -4,6 +4,7 @@ apiVersion: batch/v1 kind: CronJob metadata: name: {{ include "cronjobs.releaseName" $ }}-{{ $jobname }} + namespace: {{ $.Chart.Name }} labels: {{- include "cronjobs.labels" $ | nindent 4 }} spec: diff --git a/charts/helm-cronjobs/templates/image-pull-secret.yaml b/charts/spamoor-cronjobs/templates/image-pull-secret.yaml similarity index 90% rename from charts/helm-cronjobs/templates/image-pull-secret.yaml rename to charts/spamoor-cronjobs/templates/image-pull-secret.yaml index 9df47db..a7d984f 100644 --- a/charts/helm-cronjobs/templates/image-pull-secret.yaml +++ b/charts/spamoor-cronjobs/templates/image-pull-secret.yaml @@ -4,6 +4,7 @@ apiVersion: v1 kind: Secret metadata: name: {{ .Release.Name }}-docker + namespace: {{ $.Chart.Name }} labels: {{- include "cronjobs.labels" . | nindent 4 }} type: kubernetes.io/dockerconfigjson diff --git a/charts/helm-cronjobs/templates/serviceaccount.yaml b/charts/spamoor-cronjobs/templates/serviceaccount.yaml similarity index 94% rename from charts/helm-cronjobs/templates/serviceaccount.yaml rename to charts/spamoor-cronjobs/templates/serviceaccount.yaml index d2c6930..334ddad 100644 --- a/charts/helm-cronjobs/templates/serviceaccount.yaml +++ b/charts/spamoor-cronjobs/templates/serviceaccount.yaml @@ -8,6 +8,7 @@ metadata: {{- else }} name: {{ $.Release.Name}}-{{ $jobname }} {{- end }} + namespace: {{ $.Chart.Name }} labels: {{- include "cronjobs.labels" $ | nindent 4 }} cron: {{ $jobname }} diff --git a/charts/spamoor-cronjobs/values.yaml b/charts/spamoor-cronjobs/values.yaml new file mode 100644 index 0000000..e0d2f16 --- /dev/null +++ b/charts/spamoor-cronjobs/values.yaml @@ -0,0 +1,31 @@ +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +jobs: + curl: + securityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 2000 + image: + repository: curlimages/curl + tag: 8.8.0 + imagePullPolicy: Always + env: + - name: URL_VAR + value: "https://curl.se" + schedule: "0 * * * *" + args: + - "-L" + - "-v" + - "URL_VAR" + resources: + limits: + cpu: 50m + memory: 256Mi + requests: + cpu: 50m + memory: 256Mi + failedJobsHistoryLimit: 1 + successfulJobsHistoryLimit: 3 + concurrencyPolicy: Forbid + restartPolicy: Never From 9ae62c47e4ea55c39513788da5db22c6bed9989d Mon Sep 17 00:00:00 2001 From: Bharath Date: Wed, 5 Jun 2024 21:53:58 +0530 Subject: [PATCH 03/18] add values to charts --- charts/spamoor-cronjobs/values.yaml | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/charts/spamoor-cronjobs/values.yaml b/charts/spamoor-cronjobs/values.yaml index e0d2f16..ce0b77b 100644 --- a/charts/spamoor-cronjobs/values.yaml +++ b/charts/spamoor-cronjobs/values.yaml @@ -7,17 +7,20 @@ jobs: runAsGroup: 1000 fsGroup: 2000 image: - repository: curlimages/curl - tag: 8.8.0 + repository: spamooor + tag: latest imagePullPolicy: Always - env: - - name: URL_VAR - value: "https://curl.se" - schedule: "0 * * * *" + schedule: "*/10 * * * *" # run every 10mins args: - - "-L" - - "-v" - - "URL_VAR" + - "spamooor" + - "--privkey " + - "--rpchost https://rpc-evm.dev.astria.org" + - "erctx" + - "--max-wallets 10" + - "--throughput 10" + - "--max-pending 10" + - "--count 50" + - "--timeout 60" resources: limits: cpu: 50m From a4c5730a07e9623bb47739b3e67a174ec069acb3 Mon Sep 17 00:00:00 2001 From: Bharath Date: Wed, 5 Jun 2024 23:40:49 +0530 Subject: [PATCH 04/18] update values with a mock priv key --- charts/spamoor-cronjobs/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/spamoor-cronjobs/values.yaml b/charts/spamoor-cronjobs/values.yaml index ce0b77b..00daa1d 100644 --- a/charts/spamoor-cronjobs/values.yaml +++ b/charts/spamoor-cronjobs/values.yaml @@ -13,7 +13,7 @@ jobs: schedule: "*/10 * * * *" # run every 10mins args: - "spamooor" - - "--privkey " + - "--privkey 0x3f47c0880Ff6d7a6F22Ab1CA8e6fb6801ed0374d" - "--rpchost https://rpc-evm.dev.astria.org" - "erctx" - "--max-wallets 10" From 87f9b2a38ede13af3b3479df42dbad8d41857500 Mon Sep 17 00:00:00 2001 From: Bharath Date: Wed, 5 Jun 2024 23:46:32 +0530 Subject: [PATCH 05/18] remove the 0x --- charts/spamoor-cronjobs/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/spamoor-cronjobs/values.yaml b/charts/spamoor-cronjobs/values.yaml index 00daa1d..c37d24f 100644 --- a/charts/spamoor-cronjobs/values.yaml +++ b/charts/spamoor-cronjobs/values.yaml @@ -13,7 +13,7 @@ jobs: schedule: "*/10 * * * *" # run every 10mins args: - "spamooor" - - "--privkey 0x3f47c0880Ff6d7a6F22Ab1CA8e6fb6801ed0374d" + - "--privkey 3f47c0880Ff6d7a6F22Ab1CA8e6fb6801ed0374d" - "--rpchost https://rpc-evm.dev.astria.org" - "erctx" - "--max-wallets 10" From ca465b98a2c8947390199b41c219f85800290bf0 Mon Sep 17 00:00:00 2001 From: Bharath Date: Wed, 5 Jun 2024 23:47:32 +0530 Subject: [PATCH 06/18] add the priv key --- charts/spamoor-cronjobs/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/spamoor-cronjobs/values.yaml b/charts/spamoor-cronjobs/values.yaml index c37d24f..723c688 100644 --- a/charts/spamoor-cronjobs/values.yaml +++ b/charts/spamoor-cronjobs/values.yaml @@ -13,7 +13,7 @@ jobs: schedule: "*/10 * * * *" # run every 10mins args: - "spamooor" - - "--privkey 3f47c0880Ff6d7a6F22Ab1CA8e6fb6801ed0374d" + - "--privkey 70bce70f9c770c8e79f999f86bd76dcab8e2ac0c349622e15c85b9a1a5bede9e" - "--rpchost https://rpc-evm.dev.astria.org" - "erctx" - "--max-wallets 10" From 699b99cf6ded6dcb523d8bc87e15fc2cb88bdcc5 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:52:20 +0530 Subject: [PATCH 07/18] Add docker builds --- .github/resources/goomy.png | Bin 49140 -> 0 bytes .github/workflows/reusable-docker-build.yml | 2 +- charts/spamoor-cronjobs/Chart.yaml | 8 ++++++++ 3 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 .github/resources/goomy.png diff --git a/.github/resources/goomy.png b/.github/resources/goomy.png deleted file mode 100644 index 5f4d86f7796848133f05852b4a5a2c6bee05e461..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 49140 zcmX6^1yCDL7Y|NxD23pZ7I$}t;!pyG;%>zuxH}Xt?og~iad(&EZb5>(yMOu5m(1Nw zGMn4moxHa{c^mOnSq2l07!3dbV9Lo#fne81*ztgh3_D}F(h$Lw5;6lb*A+S3GP&5`VU@T;dglfU&G9IB-MQ>geU3i#>P^-W z>V(-ufT1K6N6Od5-x&n-B9JOA!2dDm;b;jkcQDk`WAI5Tif}1WFJ(;_+kJd|G_(}3 z^>IBq4Tz7Ypoi)J8W7^t1??*zy2r038k?FsUbo7US^Z>G+*B0YRIo#lQL0S_T?M?i z&o?$U;wMPbZ>gnCqqQ|oe!TKhWI7gbW67xIf7(fYRJ<)B;w-Yy6m-)+`=+UvWo2jg z#m7fDJtJdkZVq#RpS=N$JK66=X0;<^gL~LQT`M5473D}ScqFTs2JH2x~(PP{LGcb@0*US zl3h46s64fWEuzS)=Nz3dRmW<^T~1$SRsa6!OZ7exKw7L)rBKxMVJGG7;OuRUf{Xck z9k2jD990T&00=axB16e}N)R1b=zOg=GIke5cw%P{X|r0WIJ9=(29p6sI3^+C=baiA zy49C@XP&W+JKr?(^J~%N>Hp9NgIbD=AhkLdWfYIO&WG0}>+(k>tc$|~f3&Vf^&=%S zMbU=+N1D`I3h`(sWDQ9XmZp0tjJ+q*#R_H8uw|o%g*H&yFvn9U`*SaK^ZuK@yQg z&4oxeF8nKA6T)NEGtWePf;+SRucZ_&=~y3w<3MXnh;NP3=!AMNI-NI=M;Xyu$GW-( z3HbwknSm}ECp@id_D^Pp4we9Hk$b}!1ks(SEVlN}Z-V+}B0GMM2&R|_{(%5H{W^!K z9G}<9w<6z-9%+Yy_qpleV(fA6aSIX`n=bH}wCnyvifM{D)D=zFmp%UYMJW$HM7C3QNRGW-^*a{kf7m#-+s9fH071T>s~&2f_2FGvBlv z`hcjQ-)kVF--8c@KMuUSJgO39!bl)G7NjAs>1UtYwvHPB10(tda}sF3n|TM|`zjIb z;YTf_j4E4V?hL&u(UUM`)p?gj>3j^~?Fj zpu`MMISbB@ajjA-QXX1VxnG&Y=xe&Zvr8?_#W)Mu5LVZ^e0)9G&9Ga$EcUx4w6wMj z`b4&17$m+g06O4m!ubk<%{4W(d_SIi2%b9pkk*O`HYuRz!ekK2H{OJ(JXf)bgm_JA zGFi)?x@B^v+vYy?Q{`p8cxrMIm7dH&i86`4cDEx5wKV`k^_Gk>Dmu1T^+(^wQs(3o zM=n%M9(u8okY>f*w>9sXjK=3F3z5iq0$!Kh9OnUGR3coSl_BL~GUlKo^g9n}tIY*H zJ*kSr>fqpDwabwP&Xh8;YbqyJZnAzW8&k_<90l2dwUx~?v{>{-(B|TonH@tkyTd@Y zgiW~?T{jOiTdaH8cP{~KdGOe zE!=XyGKh=;z2fIC_Xv?Em2`U48e2KM(|kEQU&!g3~(swT7kqM>j) zdd^_3XD>bi$^D+$GXi{M2(`OQnonRIwkwFXdTCGWT35ENxlBYbjMmqY(XrZ-=yS{^ z$C&9X*1BPLvGs-UAprg~`_FmcDarh_6yAES@%0CFtO1~Mworgtv9h>>uOi-uv2<<~p&DJuijU~s4}!Hz zE8i$y>kS644>;S1kqKurLx`^aIFr{8k18ZpSw4?_H-0{SBTMFc2U>2;aB(bAEol-g=?pYWOp5^@_OgllrWYkaG{wU;qr72?(H#Kg@@M ziM3Y$=uK@;0w1O}js1Ndm#r(gD_RbTS)+HCkD53za2do%kXa)||0!gA3v6pMa2R)l zcEPPU4yxo9JpQyTAq@WGVMr(yl|6&GpV_PNVgA$$|7OJbqEJ|81U%xkT?y9J(*wr` ze=zA`G)JS3$F3E5}U6JO@i+ris-%gXig_U{$H@V79AnE z`ySIh5q3t8T?a)aVee4(SnOGW*ATw_`|uI%N<-^t9 z&8PuX`Bvf`+hCvQyaNi)Bc1h_euZRY zOsTnh9ID3BFww8WxidHEg8N0de%Y_Ho>VZcB~>QwMB$d+LQ2?1PUMfc&V zS&^sR6P8y00H{ooGz5JkMMY=FJ&*TsqcE^_(s7MX|CpNZBK1b3b+h|58&JRhF->r>B9}8!HCK|OJ zyqvuOJUu-rCFd-L-~SXFeZd;}fr3M;zNb(+N8`0H+rYHqG@|KvKNSDcx5!MSBw4L- zW6S@CqsvB`bFx7hK*znJV3$mtrmP+B(pF`+_IRtBd8yHcmI z;;FQ((nT#j09_eQA^Y=#lo5LNY$l$cc#@<;fDDBXP_%W+q5*V0K|=U<f^<0?2;?HH>HW>PhVozjZG()X! zYILI+pW9TXqv!`RK?dAKu;s2Zs?J+1C!9b?)|EVz}ty+?L5>+BcnnrmLT@MQ9b z&*qkOi@+D+QcXKY2K{O(!rVhhZ^d* zn|wZx_^^C?2w1d+@C;agaKyowT){kB<}O>%eUkCJ)-tVK8ip@)7P#8;UFG_CK02ea zk*w2!1##`LS-x$L`K0>Zw+#@$!iR#eJARzCRBO0l{KvUm+vM*d$5y5h^q43rHaeMa zacY?w92><3<*R9@Pk1SBY=0qZKH&5e)(iVhS`6V^80qVLA1-%XY)?+&HHJzS@pvM>iF)l~FhNBAHS;mKGt&x2 z^L8a;DNgQ05-_*zr(0LJ=(+yZq;sAq?bnDPK{4sl?6@>r@mR49!D_@E(I683=}-x_fR>98ds5I{Ul z?=ybAMilV4*N0w+ri$+yeK*6U;C|6hDE_lyhpTtmk$4+5w(;w`bf%!j ziCObx9HolbhAzPWW7tjCEVs@vlr)So0=pwV-JQ9S7P>l9tFo;xesGN05~EL=3cioV zB;nzjIL>-Ubd4YUL7UcTqWCugPN(iES*9Zf76wfEIApE1h15>4SH(I*<9bo6tg9c8 ztf$)5HGL!{CG})vid!dtrLH&KRDd3dUkUd}izhOBpir@hATqD~vallHRfsT80~fEs zP4?Y02gj1l{&lGM__#0uc9?QDb?mbm9EibtE4gwbM(~u6I_VL^#5)W#L;`c0ut9n+ zv-j()8beae*2Bf2!oHb$pW}eT_Bn1;OiVIY_m%ziw5B9)R~MJ`xYxWvTb|>?1`L>L}ifG|_NTg-7##?pF>R>0}I=3P23 z*gV*FoGxSH^u}HY1jLX{oOP`~j~Q%?E^)4Zf?8WC<){BXBI$Oa?fGMcHt--n&L2zz z-#_1^L!QE$3OYWcgDpC!F~9P$EM+?am_0RS;-_8w_jmc7ca_)c4nTAV+RHT%{rKMV zzueMPw3kUnbS3>EN#YfNlu-*HDQSlUAJ*yP5L}? z&t>wwhAGEV$)#XIx(mpk-ZoRn1rL#QBQO@=E*vvso>`p;jS>WXFz_wPFkE&GtFW?f zzWiA>xioizCc?4nRv6sun0QtcT%Jr*b$dGSky>oHaUXB}c~|qIZz~p)9XbKlTer|Q z$5gWaoEudAh2G3s#|vdTZIsbE?wmQsiFs~l2=(?1f^p5=KVrIStxCg?yMPrriZFLz+i;Z*?+WluiH5+RcaKRhW> z124!mx0nVxXNtJs6|3a@LiBW9;b4Ciz|EK>GGv^yMZK7)eSBJX?ZxD+Nlqp>UTwYm z`E=TPHWn5`{<0O7=NHX5mL}innpGqz076(C^Wl7&Y3F=GaM7dE%oj#;Tgc?3IQM^x zsMT`7H~<%r2Lq(x2Mb10R@H&kT^Gw{!A+C z;`e(HE3O$i{Sn1ZD(H%_we^6jH*?4F`k1?kF<^*WSljYi%&YJB0uj9_Q88J24uNJ$ z3SgZ!?^R@XK4eV1tv2lC5N1ZO7B|He{YubwR+`ZOG;M5Rl1$CcVjM&Zn%kkCXxkV& z_UeOjpT;EWhwV+Ez))@Ba19j|~D7go)14?6gWgQS;a=N5%SH zn=mga?$%=c<9~kxz~w{!64v_eSc%Y}4OfAHHLR|1FkH;Gq}27A-9LRZK%08w^;OzQt?}#%AM0y~(tjf9HXK$_3QM<*b{?S(=qZ%-fy(sgqnP)zDxW0#@)jF>zT z#{KLEOH60p)k_p43# zymq5XoU2nhu?n)9p_E@z#*a^Yo?6#l$W1xY#2n&#-Yc~=JKtbp-q*)I3$zFbtXBq= z^R`_Pia52z1ll?dEJma6vMS!)jRkDU5+>@SjXL6!LK=rz&TSRC8xmXL+%*KMmhpBl z#hY_R?l1~I`}1K@@CWO3Tu|eqg`5e>zlusad@Fq?*XGFVIo$6e|EOqd_DX|xK56V0 zf-W4#7?_9#!cA2F`qSZZ`&|^_Wf0n;TSp|ud@+bpLYwV19@`rlG)BU*hC1lj#TRA{ z%&ya@LlKjYNMh79>J7ytBfVa0v%UB`$uO>^Z8_tj1Zn$mBLMue99bsZxC+6KSm_}+ zz_HOmB7iswMV|d}5+eWZa7UAMNt28Jl_~jr%-)v>1^dKL4)=u}g`}eS*xoQVLE+K~ znagzAszDNa6s`i5zvQwJY878|04z4QY?hp6<#f;p}8)0v+NNxsVK zH~OyjGby7*?yq&zC;1P#Z5~^5WI0TO`W$0$??3ECXgQoI50Tqcs>b-GnEi(m%3N` zZ6ouO!KelI$N5U#db}kY0ziN@X%yUa{I|nNxI+9Qm81S1q)0@IV-AP@Bg{{ftS;S8 zu*R@dh3n#i3D*=~74VpsAZkvJ;a(`AuT~!oaXg0^8$?gHXC49QCs#zhLpt?MZOC9f z)P0F9`cM6Wf ZhsB)@eTn0_5;xu^|4VfNPBw`_`GiG-u<>%T{74^3v~7paVObo zTW2P?1cidSVX|Rzmbb*v>M{6J^qlp)xaG3b!PnYEJpR1@G;~|5A9iUC=3}93e@8fH z+Hyp~4eY*^;*j30zd6Hju8KTpxKmy6#ISyRhIkT=m%>JifL&~EZXpaYNXzMc62qR0 z-Y$`Y%^ksZeEaO<&?L^~gLgNavX;EjwU9>A6c9m;tGJ}P#CooDE}M-e$aabD!_Tjv z(3M-u>YwWVPNYU&)w48627a4qsKcIzyJm*cfxXl?blNx8|;t>1cFVpmTh~ zVPxnZu3yR~@!a132n*8&M3Tk{lRNf8E4E-jz&zN^ZRhdH0tvKW2h7J?O{c7<)BEDR zJL(IrbK_!zQYl&DM0HQrEu|NgFE<&X*DO8yTY7PO$-!(g=J)H5w<*2&D8erA)@l3ndk*pzt{aN-70b z)zkCYJN$MOpego6`45>)FvZ#{v-eqp{Rdn6Hv#(*6kC}*^&`dBD*p;cEG5)zg~D{T z^yKlwfyB43+Pt}~;ygd8XIv!Pzqe-2P**ziT6hp88pr)idPf!Pbc|NTL^2pd7Vz1l zFMb?HFjnSCmR?+*$7x`9^zbOmXg@DB-ZYrLKQMY?kCr2i)O;chr9{26#%!RD38Aar zw)~{6*z0j5+k4BNVQ%v>jJyNI;CY%b^ZEXM{e$h30r!{T#CpeBLX1h0DExFaqAbn^ zIQbWDIS)eGmJrUBOaiKeDVj4M$MCL@(2aOpQc>5o6{MXH`c1hkgch=cdfN=@w`ddX zn5?EVb!-AW@P+#q^NKG`#(VZZ#;hsRiby;sj+?Il112?!;RD2Lrw3_ppOSo~352_i z!oZ~7R~ZI<6?&{~pM!6U1FzyYK-Hl!=a)Gs~wx;=J9DC7w_)qBs(1(H&yBM356ZvgpvlobQFxD`Xug*N?C z*eMNwgYF+yLXBiu#;;t6l6~Y#iHBJE7KH5~aiG;U7}!+me7I1N zm;vM95)+eLkWf4+!Hn(~&fT$$&QN@xoADqNUUP1QX0TZ=QuCYKcyrd+Y!V4=rc+k^ zwF0Z8?XQ15!Bb5Oj-($8B$y!)-pfBYc@F5fz404_Lc3xUK?e1I zg$Dj=>-u)X2^U+D(d!w&w6WF9=h;SCc>}q z%z%K}Dy9P-wcugStuAGFcXva82@Ii|R588BqTlk?@R{Q#v$*omgL%ULObvktP(cNv zdZ_OYCZ}EFz1)rtxK-g9xKQ2%kTuMQL~U=cE&992ndUXohPmUl{wClm^0q=5;1j^f z&hm{p$yFSF)hQE6X>6=^p`so2qjYt+v|hE-hu7fpaEe z0l1haE6rp@T2b3h-tj^In40V(!dJRnZNP{Pw(%8K)Q;q>r%?bb%gkzx(?Y;%495p> z(l=INvv=%CF}L$rY`Hp|*P$bsA+4DJWjqqfJ$7qraN@uWmD%-|OBR38%&QibR3$x?`rgK;jHf zlRuofc!@ZqfhvSb#=p@m6Svj&)AU^WXpR*hBE*fjkai>{odC1zRP$$h4C+XX^v%KuF|ICcRN`% zv~BUl#RNMQ>=l(7&V-L6W>{9YOc0Tg1%R9~;RcsHGPU0WxCUwfFsa!Esu;ADs3S9x zMQ<_WNzhhShBD)6F2!(E^mxaBstf=L+%GS@kqH_sviAYs_UdpDTw!tr&*TS7PfZzG z@G8JV;%)A5C-Jjx!w#A^6rnSH#FW$Tc{IDd409rc7EqSL{MkP`IwmIfJ00SwTRp+t zIhEp1NCYZ^B!WW$>70v?;!NGuofHRhcP=|y{K#$_59APuVf089+g^X;3Fr^=>>V6N zv$+?xRC*@7w6>1ALb`6rCZHWpXNV@pk@C|B;#aCCP5#URd(2AA%oWJ3DtOd=aZ)T^ zOdrnI?tF0wE7uoMCeQdlW}N9*NIltlD7j+AE_z{;b=wguQ2`-^xyA?e=SuP@FxKp^ zeyA?DEP3mpi0?7X7X!~vNc=Ox4fQ#D z!qL{zwl~MHS2_?7qIN{BQXNMES_Jf85IW_i;?*wyyJ%tTW8>liQ184OOh)>($9gnQ z6apnj@z|C-Gij?XClRYsprH)#vblRz%xj_RLaO4uy}CL%?R|YAfyb_LPH&S1u~s z)X!$5Z-1W+Kx#E?`tQ*`*Up#-D zjSyya83;a-p`_cXpX2NquE)!p#VMP0@x|J;N#WvXYNpXAWN&Td-w*J1hQFs(IX2CF zODl?)x>z>sKojq_$7GJ$S08oNzTb|{<&gutbZNKgjv=Z_w!#Q?T z1~;fPr6V8|bHY+ZMALpk5DD(xtSjmFWNBhTS~0N=?m7{rGz?jW_Wi}10`+3VBKiS> zcZU23MV!B_`u@bTSMYLi0herO%1AIfA zfyr)qE6}+>jb0Xl91o9MNxbzG#DaIV8?{mF=1mbReBtoU&~H7J<2HM2VOV$lt5}MZ zg-Q;;@Q9<0WjX;LbdN|(W&6s>(U@vgQoy(U#eMp$i_w< zjX|$B)yVrs<(>Y2>>?teQ`NZCO>71yquSc2I9=RTUtp%wRsW{60AUL6?&0pc_3PC&*!I>i!w)jrjm`q0IB`a8$;oT5SHoP{ zLU=R@ukmu-fu*f=P#%e;&5vM%gWX6_OH|{}zQrXQEKZBtyuw1H7Ne$9*T4FPRFi`< zHm@q<{7x=6-CjB9aDza}ywpKIpB)3o{h{tvN^g-d_qD%DS{{<{K5zGnK(r9N>9kB< zbirA(U38hDn!i;LTeAj{MrKhxf(GdGj@w$cQZnHq7`6{oWm^R+bK}W5fDn z=zX95ph+r94ecH}^kUlgs!a&J7J2(Vmwg3455)&%;~3un!5opId=AKk5+W1f$~Dea z2Sj-RV)Qr!>@xaPs43jsytcYE?v9Z3IqSu?2lOiQ6YaYC`d&7S`w}54Bw7&)X5<3I zd5-(Wilfx|nV>y4p;&KU(wm#;id(X>&(k#UUZy4hL%~~q4}=O@N|>wb>wTqT@Fnl- zeZb_64oYaK(Y)?0?_X&@BQV(15;|&FROb98S6?FA`qb0IPJcmDJc9KrJvB><<$D5V z?d99inb=MldNZt8EJ=E9>X8qPr>7DqX#GMq5b~|AMfJ}GPN!alg}+F`HxR5oxtv@d z%s^PRy>MG$PPZeh*hW=T6MF!d`0J~@#4uZx6}-a?e%Cl@*O+*vSxZz!+0qF&f6N$e6?m5$K4 zG`j-cf}vNEMw_+38$yGq|74FDF4;ok-wzi9ygTHF zP0}P}ByjPYEt7m(E7WKbVa2E!8d68V5(B#*mTguKmu6&VzIR@ZWAzIk6aKm9=>2wL zGa=o+cs>8Dps%zaA9&x?-i{DsVq)rUDX}2*>cf~l(xxp*HJZxv9`hzTsZXEn@@L>! z0DI`hhWN^5^jqKgIVEr}r8w=?gMN+~c~6jUuV#C8sELH2rIU)4G7-HP5 zgpNdAnZ!M3#KC-=&H%EsKk9+3Kk7f9tiSOiBTsBX^L$c8+F2bo67;SQ4f$NJ*_a>= z;-grD`z{g)xP__E6akR0rMAi)H({m0I(XG(!DMSdVRCXmhS7>};9(xWUs69LBV;yMyZ@)+jdsMc22h&GO}s2h{rbV5M$06kp)8{XGR5Ha+SII-(U_vH_03%)2;s ziXVR}-zJNqNuJhk8{DA3Bj;h{Yc8_0jD5F*8XF;%#&JUn{$ijM$E6}AH+*t>{^#zl z`SEI_plY8ZhXjjvjACtY-iEkMlRJ8pI9)G?xxDO9cWZ#t#>-t9w4_pUBk=;ao-x^B4GULXPp zGb%Rb)bp@J1~$>Ys&f*_C2RwLs)t{U7wwRa0Lif1UPl|Y0Y*U9Z0xD%@td6%0cxEB z12M`hW;#wz)|BAZ@3)%_iap--XY<(wUNQN1CF)cNy}Ta_6?J6{SW7Z=0R ze0=ykF6o#?f{hA(P2>>bAw5>T+XI_|QG*aH+7-L|96NB}VWnA-6wl`xx;{72O}ptC z?Zkk<%F?WV+YbMV7#%Mj6)xr*+ZJFpq#%puGI2F^rx--9J1k9(Ud7Jd~5b+ zBsYiXcU%RaWa=Fg72y}YfkBy1EM_b17?=C6Lnfu9Fe}KKW$kj;&FCq{0+zVD`}B|K z&gmUAMRO7i^6`A8x6Bl+^O}f6fK3!iJli^xE?sYr=viGub1hvT1+T_ zukuN1f@4X*hcqL;VW4@oIeVrtOaP_w!Ne9o*W3`>7_>uWtJ@|1} zbX-1WsC_x~DwwsfJ*cw)V`?i|9rgeO5Wc32MRP)5%XMt*b#z^ubn2!lrtalhdK(Zj1V=!7L4`*&1&o}uUx7&qon=ktEvVg;xPp4Rky3}_^^UcEwN+)SA zFE82hkZ+F7v{&q#e?7Q0J6kx+T~-_UCZNjAT2+Q{x2NkN)fc!>(#P|WvpohVOouSs z9bFPPQJOU)%z}Qq%R4z{roFKV|lPm9NA0n-s6NqJ5RV=lLmI z^Sr)U?9T>lJgv&%#K!s)Vs|WpT@UCF7ZB-<`w2KJ%1uadH$8kT%R_A`c@eRGVSMq+*{+Y+qV)Sz8-yun& z3f6#MsMkiwWR>xbfcJHNXHe|(GOe=@r^U+;fuzS6OqaCKLfMFP*0)C_0Zmz}bh$1! z3cu%%N6_weI|^4Ouo-&_C%Gu-Yx|C}Wc%)6Mx1={MWmqp-Q|i}t+`!qgcNUzPT)| zq#$~|4o6i;N@5;YD&!I}zta%_^kx++=d9dL_PVLS4;)VSn`!Fj<>#YwdOcO2G?&AS z6%4)%?Z3t9TGlaCNq^@yEk3Ue0x7uy)On(9e6Z45NI^?nQDC(63Q0~dumm5hcgMq% zW4QHA_t_GSsrobrbyZk+|LCX}25@5XHoE)9%zjsOIg*kJd*bNn2@jb$f0%H#ArXE3 z=cc+o8SeHnjnd7nO2ZQmw*6K4Ua5xyAm*mRx^{Jny|v5Ro-dj)_Nw#G)h=^wZj6{S zjW|%>UhFPK)`!OH3-0P`Le5&~%acCZ>^B-`!Ls-tX^L1Gtj+MWD&&LC6T%TCQ6lD1 zdEc3G)fs+wq|yclNa0@ zu61>Z6KY-2@ve4n6kAR;@ArKu9kFNA7)PpMZIpcr-hm=4S@v0+m&CqxXT~(dux9Z& zADZMBg5=BM!Ih%9dt@ZikU*SGNEjBG_Xe%#i?6hZ>+i&`D-s^mhfU9yM{MO50;jES z%CPi?zX=Ylt~OeXfr(+tZq?F_Ia!`s{+>AT~U+2Jr{ ze0?|36LT_w_#sSguj2B|F;mFnKdCuY)Q=s=n2;)Ax!Af#E!2MF*tWCl_Pfk^nZFTE zbL4x~BtJ&$8^#VX9Q^sK!7HlBYxVlSu}t<|VP~`H^;sxwU^q8Ov30z`A zQ5cB14>!7PX6@tN<}jmu_?TACVYh@1 zPyyg^%@{UlgVXGJb@sFq3$4w05cO2KtGjce=@<=XJ+ZU=`|K%reC(z(E!?%f_K(Q))ULFnG( z$OttH$of+w$clDZfD_@7hY#cFG|y8MuSiD+X}%xgTg-C5H~p!(6!b_CC&OgL!~t{%n*&dL z5i1wv_2SX(lyW|aIY(779NcuB^lIw`1$SuoljGDf=KlVEgu^?ziz?U(^Lp1AARU=( zGE%4+=7|AJ1Xnrs5{#zR4%P0ek%i;dFXpN3Wer*e_ZZ*2!$>OO$B{f6)%xCIilm&) zH}A38SIsC-ePrpIQ_p#)f^1Vd<|0@baH@@sj3rVO?uv-lBDZO^Nv&2aSZvO(}CemTl;-Q zGEk@E*&=D=L#UW$uB{)-YSs4u_dgKcZzg}8aVfw+Xk33qsB3628as@nwRv+X%tb!` zk0QW45M*>hCdOhSahN6aMa@}3TCa^lK_yw#ZP0j-VsA$=@NE?+5zBtZeR1FORA20c zJYU(0m{|)Gne=t7-zcu+kOb1@3JvGDwkPa!1%Gx$#EqE63dE2KxjqlgwNwz5X;ft3 zbtU}$W+M418}f?bda@P)>lJHBS8vDo#;)I({68$fW8g$Ry`J1;$Zxw#DyvrW(So(DN#&ai5{zwwl zzv96gO~eQ2@b#xMb-wvtYc5=1%iVt7bIV_3wl?8!6!v48dyjh(PNmWx|MNaI-JCnL zYc2B0V$A5p$GNm6&r?d$oM$RGZbaL z_h5#$+UzO`Dp58%$f?Qlm=|^y3PM}ZdouU;_Lo_&?YY5Dxz5vVAbIu~UnOy#Ad1BB z66^nhTY-<^r5&ZZ@3GNHZJ8cwrl7gGU1H+n<=V-Iohzf(B4RW5g)?Ve>~8BOsz`zD zR-#0G#R1xtO$3XrFV@yi{EU+h1BL~l`~ED^P_wkfrj43+))lo&Oy=X6ADC5kSfCpb zJPzX@pWQP7)P)w^@rs|@N!^6C3BATyX{o^AYnZ6J8I$vZ>b%DS=50oVdk5ihgurO8 z0tSsBFPf}mg~jecw& zs|#Ji$LA9k>0)$owkLjyZ8Nfx5_3eQLg92Od;5f!t!!sZbG5)0A~Nzul5b0CJzfDF zT%>P5Ne=0#>Xk-}w1K#y${N=)5_OdN{VG*f`ChM^Y=tH#1Ucd2LI^$FVBABr)TJ}+pkFoU0s`G!5G;Q>48uJ&$UUB zn)B9#PVN(WwKy*zgbY+Nuh;6PpZL#o@fS5?S6X;Wz&pSlGX?-wTGF(aEjT%~7Ey1_ z<6a~G4_%-muE{Xl%os{lDy!4*ydf&38b{l7UTH=_fJDT$+uZOUH7Cv@Tg{f?dayus zJL`|sD&;t$YhBJnkT99#LWa4e+{jAzxwk@}bGEn7b)6Y_U-FLE29u6gxs3VM&qc#P zXt1AKT3K}`sEAB&@XZ@j&$V0SVIEN~N^xIj#fqT-)Z~Df3h=^(1;>zwO=ktzC}IA@ zCSqC7Cq)lnRf#&WipUKrOs#ZSO1AE55_592{_L{M&13psI!XTZ>5mx~)DDIxe ztTcvOsH z0xJ9TGmm5GlI7^==uT$hnP(k5|5MjA{QT!XLR)J)R;;|pO^L-USWpz>x$Hqz9A|;+ z$u&$-p6Y+-h)tnY3Xn3X`_KO#Jdw-{EOt-=996~P9B$mrT<=CV%1MT}5GNr%11|Gbk=*!i0?iXe8Jb%LQh@PHa^v>wTefQs)vP`qr zmd-C2!>C=0*Uvwo=ZqADp3+D;f4XJ!rEmVsXa5AVX3xR0Wy^5?efQx02k*v`#VgR> z-kGRe>XvW16<~`OEyuE@tB~VuRp+@GH8@)YiyYr3~7#vJT&Y#*)};N|;yJo6Z6+YXn_N=*>)-xl)c$90y>+2ej&E=wx2X3jK zLi18Uq8u|$)sp{D#pWyyNI&J|x4#ohbla;I;1Plpq*CPq970))lLr>pjm@LPS`@U1 zdr#3)xr$9J(xem#7s}O&?iX}F5CtDhc>oVhd=&!Am#xO} zX~iRt-ft9(#igcWKEN42r3(f})xiEg3iON+ASpEveQw3_6>s{?Xa7Ic*Ed8}WdO9b zwBeFVw!m?0-13btVfu`j= z69rL71i63BJ3D%iPG_*~xu;qj%St=8{c{E;Ybm$?VW6kD22$#Z#>R%v{n2OsIJ0`q zMHO?<7+jY!l}cgFnzfkO*N?hvLz#&W&nQ#jiZ)(mcQrRA*StzDKOX12ij>v46tBFJ zeIRu6<7O7mB`0hPE?4D}Q_2GXDDZNFoVx#exo{?7bE(n-?AElG%Uk`TqDfi4YRyNU z_Pu|L42le_H6md^81a6|FREP{@3jjSECwlw?K_^Gqm+D3Xxi>tr`!J^(9=RdfjSx3 zKfUd3Z(sP~5C8gvF|u!k`ub;~tE<~hCy`%WRW5b`$}T!%?jqH72B8C*&I7`Y@d^Cs zbEtS@=Ky9F4m4Q2TPwC=5tfjmMC+%N7o$srTyYQl@!9cHaG&E{XD%QCANXZCJ>-}^s^R66ZVU15o6 zVcc`wJi!OyrDej}i<-_ribaTNKfd&dw^wR`X|fHVqJEoDIhrZ1m|A@c@e5DNQgrSY z_JJ)WAVaZs7y#Ac@5C6nVx#j)Ruw@J0}r|UksNwLtnH^Yi3rbbeFnGx`Dqy* zNEZ3PE|;|W<(h6x{>okK$ztttEKLzj)T(~wB!Af_8w2oqaky{Uqy!vEppa&KIecL; z-MM6-Q`jrz#)x3_oV#TU1W zLx&FZDyW|^s^!-ITY;_%fzG-HjFpQ2Yw^MbZ~KEk{0tfzr#gF^B33i%{zeT_V9B-0 zn(k_@^;GXiY^EAxNElT#(U|3_IQ-@B9H>@>npBho9Gf6jSst2HH0|U|M@J;FV&atn zQ;zWTmCyhS?>?W?Ks8Pyw1Er{4dLtG_!?e1x&zm~Ycm$Fnv1%IEDS?~rfaBg%%P*Z z1vBSP!=lym(B9R8{d*7M!3Q2eV?!hQ`uf2+t0<6C(mNNJe3ER+NF!I5!{bjp)KxS~ z1Jl~NA1V~bQ6uL5n}D9t4dg9rnlAXCz5jh5=)UIK>!&^}ASeWhvPyn_H(-hV(pFKK zHk)kLX{Zc40^&FWoEVaXbSlPzUz&c)ncCYR)8cG)VPz!#J!qTpWzmJ z|I2dWDe)k>QG`K0Had!b`F~$PQ5(Vy@3|b!t&LDhMLt_tSV9Pf?%sARSUv}~W8>bt z?}x?&=FOcS=~!bPAtzP27k?sq;8)EZJ9e1u-t|J~XkqLpob#Gh|L*{LN^sO?awwUl zkIbJp?|r}b`+vxqnwt~kk0!8r3=yV1QvK!U$^8nq7#UUFYKN_JNO>lZsINAjh*bgc zWFwcOb@zTP2u;Drmsxcdu@Ao~<<-K{7|RrvO;-@>uMgShE^S0Izi zgc_2l>iHl7(wP+IF6l#KTOEG(M|8whn1UP{5=Uv*384jSFgZ#Zu<@% zfBX?w`pSDaHS=}#U>QeHDdu;R9WDaJU0w6)|@$yOxz7Eo~K0IsItY7|vKlmfo+SVS4r;<47 zIHMgFQ;qaaC#acD97QBEZwVVBs6$o3KoaO3QrhguuKytP8^42S;%Cv zVBmoTbz}1w$ioCVO%CkDkyR7UsE>IYK^m`I#8fO6@xveAhUJ^*VOoFJ6f-Cj&&kW= z(wNrQg$M3>3>q{nTC_N*1a#YSr#AVD0WeZ&bai&)p@;8j$rlPkB`F_FaSgK8v;OJ= zU2p-%v^s_0fBm5k{c6wkH{KN0Ne>G(R$ z9*?FNb}%H%J2THK;Edtukt6ui&;2p}^%hp!FneL=b8`h_4+zdqXo^r9?({0U?t*g=u&lA6 zasH-Fmw@}7PN8&FxgY}xrJ0+vtI zNu}`RFaIZg{G;1({P=O~+O->h_xFE;C!c&AoQrb73?=XtvHtY13;s$$9*Ncc*qq8C z)7a=J?z#VN%vsY5k!GG=0HIPdzS3{2UeM#dpCW}dmn=n7PaPh7=%JvfiXralRUi7{ ze@7v7yyeaBMo-W5X+-LMdE4en@ETfQEuc51(|}TNl-#gr@uKYf1q-2+j1B>qkQhVA zwf5s+=CROJ)zu7!`vp)h(`e!REXDN2Cv<%g>JXd2>a!{N!DZi@bB4o*58>{+@A9U% zy0hPghllawAKwn!wj9;Rc$@yb}MZ-Q)sa~|Hc7<5C&@{1SXz6bBYfddBu#aXvrqFe@DEmZOUt&~D{ z_cW}#Xd^fmZ>iVyMLMqm{Z#|HW!rE_H5)=)b;+hn(Ad~m#o470aRrZY3SYSRBB)Gf zRgM~_q~#T{IGPZFL~?v#R&&cEizx0cR_WlH2v(eP?AZPsPMtah&dPF4f^$6ilGaptrTI-!d}$1rSbEh-vOyqWN;(rY--;DfUX(1?wU8FrMab- z2=BfBAHIaF&}xW%HGs|;hf-=yM@Pr5V!d`+h`?NbeFEiqDL9^=xbPlR}d|c zGtCn2x%)2s;qU(r{^=k77Gq;$!K9Y3&_lrNV~V2BM3L77(P-sFiQv((u`zc#OoRg9 z7#tkHi4!M6U@O0~3hBrBR<~M5TDAB!X%~ub0)BWwVIF`O#>ewGdg=%oXVjzUlu&X^ z*vbZhph&?X2M#%jYBv+-S;7RV0(6E&>*wN`=bpjA0|y{HEqS*%idV>iyI}#Z*npK% zSh8d#wrsu<1iF6nr#{q!T3Y>OA6nUMPl0QU$#LhVB}41uKmS+AkB>tL4Y|5{{Mtu;Bj}Be&_qctaFV4& zyip|dT&j}ZBesZaWgig4Lp@j18MM zZALbmE62LAJS~C69lVeoXTfs_VRyCqYK@X+ekB?OVihM(p1`-i{Vfy=1?ajCQVMtc z^v4()8me&HscJBQsk!Ksocjv;tcjrOh6^Z<=pt{jt3RP89KM7LT73PqYN{(QH%<>f zUMa}ve$T^44nZ^mT3SFV1zR~NI3bTzVov`Y z%$_yJAi_JOBh$81OS8Qqpc7+|M9Z>ub+cEjT7{_8H>*NY#TI9{9WnMZY<1#kv9eX5 z3V;eBuy5~P96WdsObFL<3ywpF4&(5lgWway*yqTxduV1AM4C@d`+)74HUrs=J6$Gd zIVD1_t{x4IO(0Tb9W{j@y;Ke4lQHaJw>$~-)d)R*bCQn4-u=6fZc9V?*GvJ9bWoBe z3U(1C$AanDu%!)0Iqpq5u%!*tDWPB&U`ZR6W5aSRNF|}5AW6bf4oqpo_S}C*Np#F= z$B8q?aOm)U*URyyJu;pgtC!Vm7^HMi7$3#>*a&jD9In`MH4NRjm@&4Tu^K7&vVpD% zj-qWd1$yg@88aID`}#qOAh_$okx~$xyD@Qff4Fip2&LtsaV7--rwF2wQE>F=5m=@b z=_MZ-9l;AP?5zAuQzX?YpIjbp;PViksYbZZTuO-*D_3L9+KV8i3S3;J6z0vDhmQ76 z&l3rWJF2OJJjp7@0ncKZZAnC4a7h@$_}C~89@&dja|))CFr|%>vM_EJF>V!crZ9xT z(lAENF^rmdj9Uemjs-_Ku1hW@N{)rRUBtMRN5Lt%mS5U1r3G7BaFh+HBqS*~j*aH7 zdSsdnJpcTTz?(tH>kEH&U#^NV2FJFLA00w|d<4?VN-SQm1Z}Nt?ULvnW448q5H;k! zoEV*R4ui2S5M8=)!$!2VwIe@1hTVI1VcT=taN^`i%$qwGmtTG*T3T8sZ&jt_)<`4> z8zOGu6ONIQVK>bey1<-sWHOmo=PV>;3aW$|N)fV|9B#V#t$5;z$6yvqV2mM~$>64& z--dKL4abpg9IDhggM2Endo?#cX|fCR$iv~WVbmKvFr^a|F1W6=iImV_Iu0un&eGJb&_5%LuZ$6LT``zC|?~Ivc71-on#B+C_tGL~>`umYdrC{5RM|=}< zbvbl*_e>5Vs@8tV%7X?Hs%t3(_MoXG6t5eGfscITH*xh<*I{sI5Q`QqLnf062sbI| zH37K~^r;uoFqF&^Bvarz_cq?}wIMh}kd6(DIVd_N{1H!#F>oOCdvpYLO6X7^7+iyh zNO?0TVrc4WfZoWkZQIkh{<;}(LhOkj2AQQi^5dg0O9d$9xC*&S!nRD9#R4qbgpv;0 zT3WGi{=(GZ<43P7I?j(Wx=uyArYm<&7Ja;6>jGFcXVzQ{4i4aZw|@thzkNNHuUi0J z*U;VDj>T){qJP13eD{k#!&krh6@233pF~4LW8h-FRy{^aDJ)yQ0^L15ICSt(u*h?n zEb1F3khPj>NhwR_U-^<&1+;5JJP;xeLKKgObV9_8jHNhAJ;}DF4gTs`zYxzM)a~&K!NQ@Ey zp>wqKHR9mm{cs!^Y_3WvSXK$eanFi7Hhc|iDQ%dgBFs_|j$;L$Bj+5m`ubt$`V~^C z8Kl(V8hp=zj3XilMs1w)xqUNd;)g%}0hVr@gB2SVfpZQemAi-~Vd2U-xa`LDc;e|N zaoZ2R?^^U&-2HND8rTFNRZ5|wvkRAOzBC|blu}r=dJWp!+oBCO5t_UzYgl~`Am)|q zmYHlBN{JE03VR4H0VSnZctWl=oGfd=z1BxkHC-Ic`TQ6Ns=7osqjE|Up+OQLC=eVa zVM!Y$$40@iP?R=I<-j5dQ#mL}3kAo5tt1>Tbysvuj9Pi<%{oq;I*#%2aS#wN>LY`v zF*Z5~+cw=!Hz{G7MHI$IQ7nwZc1-u$`sKW&(AnOFT()km#`tBrrXf?Sf1mOpIOibH z!dy1*#64$zx~n#3N5*#*7*0?VTBAfM1=}8~u<%VBY-s zDCWm8FgSp@bLZiYKJ!_0baWOu`l!PMJrc08rqytk~ zDA*>7(uA!fEYrrprw?KAyk%%;XvEma5XMFZVOeHSNF=2Vt5ig(n1^k-uDbu8K}#_K z*-RD(4(;bBPM=~@$scM$IF_vC)u#k>As7Ix%cP8Vr!#4>>4w#q-rp4pUCT9Rf@?5R z23p!1u>I+maO~)DtiNbI(&_YTYP*OC_4N(dvgLAIamAIm`Q|rcMr4DDi#t}fQc_6h ztwMAvRH;P>iAI1$y1Ple$zFm0f=<{e_(i*br zp&WKuG{6H_nfWA^AU^5+P#_odN(OcFl4MXZM?_GZaPoz-=xy&qeKw2nu@P@3fcv;( zyRo=gDndF|xl=OMqznMMu0tup^DphpIa1zEU;|D~KyqrXyW3-p4gxb8+UqcTu?rv; zxWWE{;%LrxAgecE`mAoO+^`sX_UyqkTc1v-Uw+jPUe38I1XcDO}@ub|CRI1o>Lu4GO&;}7J0wQw758Zg&1^j>aK~;n`A~o}zyYkOT(pfxI zBgBGo0{G&+6|bVo&U8ftn2|#P)c;cytF*Z69a5_p#SY{EW!ng}^ zX(#gsF}`Nu{Dqj-+1)K2xtaq=*BV`>2K1(kfDmGVVHjAnW-hY1bYQgH96?{Uixz5RU{ty1T?TEU;er-|<9PA4 z@M@iHlf~=+L2wRfN|4`(69Ra+E{K7FQ{`UZ4nX#- zdsSWqkV<(4IT9tyMm}G{_*enywlq$iIe}uS;CcemfmJG?R2YY4mMTGBC0#>AXsB<% z{JHZr!TFU%+vWl_si`Re{p^^PW`wy-t&Nzww7;xiO5`>~Fu#;jx)o5;h9ZTw&K4|R zw*W8g*@YKheBqT@bwWaQT(z_qB~W>xl2yfmG#G_qZa?lWyYC+0ZGyC2kUNg6#NwyM zq8mb49!g3UYzi+M6-46zsqZaIf9k}F-0PZ!t__v9gfs!W6 zC3zDh6|9nt{8$0`(E=>ff|k>eFXb^lHVSE%P%Mn2SjfY+O(>G*yjWH&U5=K&Uog=|9#4?g$+q%*|} z7E?||Rd$+9a3953W|T+u#u;dzSo1>wf7++x0$fT2gAU6*c8(Lo@kiM?~oE>PAaT%Nzk*%xZ!Z zQv^Eajhyq={`u39${1yEz)dZ=3toBYBPWm_B2s8-t;ehdGq7v-Zj1~MRd?Sfsb!zo zVu$Y!Nl*Ej>55ejRPYO2d_u^pv~5!bQZhz?5cF%rv&b5 zR=hH1BX9Ju542G082nK{E;&@zQYQk)0myU9{h46CMGl(Qd{^BUGgRfxfg}Q#ezKu~ zlf~J=E!M#m$VRj1Mi6(+!@w?kG!x5FH8wQ5HSfpABfa?5_b{k>;4uIRja}0YCcr9k~4$Kf&1exVs6VTw)xVgjc1DPY4YQ z=FWqWN?nm+qHm%wsCKxA#(=g|)=1U2=3qG%0Jm8IEUXpA!2Ht5uuy~~%wE`ww(chE z*uEX>*IhgTu&d>_Cvwv%(4I>cTlAVUyxwqkTMGSkMXm)8>zn(VKzJjF#LX1_q_Mv8 z$@VVB*d&SZ_>f7KSkmg}=i}$9+6GgNI3yypw{;<%%D^eu6NU|bO*^9yg%G0GeZtN? zuM&32fo(caj*JKaNJqI|lP%q1D+0LA(bG8{i~E*f(doucJAzXXlriiJ8|mNI-!aEuxc8y6T9w=b!T(wbh<7DOWClzmP4hKXT{64 zQp%q~64E`(WK(GGX~ls<2T&>&ku*squAdfueN=UYB6?@av!tY^CI~5|3vAyyJ9e2# z_sKTj9S^_1&(c$*0VmpKS{A#k?uoFn+GRz|?MpAj3ABl=>6GR_h2Fcejny4X+=Z@= zZa9`K*YSsfq44I&sB*fFzuzzgC|klRSSXH}Fbfu>ErTa1N5L-Hu!=UEk_~A~FFomz zmZTt+!t{>mc>9&_fPpl=`t7gdgDizfF$pwv7r&&UELZ$8^}Q$wNXp{EIF#&5GD#G;C_zou4yO^lwgfp6`0^C7swC`^M!6rfm3o& z8nD&OW%qk4Hg2#q=D- z=stL3~2~6WCStg{P zHzxukcb?yh1uJpU(u;BDeRt#emv)A#jj1Ah2%pE^88gw{)m=wKSI+M0L8{i|G9l1e zLwh|S09!d;qk=o6PbvpeIWQd?mh|+*r2D%f&%!H(Y+VMO(^~QT^E+T!)&yDEaC$5h zA1k+i*)K~~4uKpBP5BIwRRIg`K2JHyjl*q!Q$R#!*?ldm8e@m8cT$OH5MwhQim6$Z z&?Clv$3`-REBYpqf|`iW3{Q1t%&k&nm>|8zTu-T^y$g*E&9Dnj@>TIST3f*>+9-{g zD2KX`U1kupWGq6m|QByBjVf~yKhM-#46jCjh#>J!P-^p(Ad-zl9~#o z=_ov!xIAQu2(J6>P(=|+xvi8{RICNed{qhMN-{7hc8-fTgmc^#n^Z`nygF#vq^Yn( z_c@pgUn!_LSy4>lZV=wlH3OOuc;=}m(KxRWT1r6L5>Cm1RdAVdX_YOsukR);muQog zOR|BgS3R&Q^1F;N6i*g`A%@=e-jMb^i*){KTwq4`Oq9$L?!5m_965Fb?X7LdX0y2E1bW%xp>QXYW{MS}5>Z_bqGogD8ROsnd(`ru!JFjR7KR1oI(76sl zl87*?e;zWF!SKFeG|z2x%T#@x^zcv%--25%-$7I8`L6iPhz`fFOA<}lX6Tv$Mak(y z<%vx1~WFa0~ZJG(Gr+6)+}6im~^(C{GkA3T7*o_=gvy#?1yn%!zH)uKYmwc878Y~uDJBh1vADZhjLQ=1RjSW5Lsd{l zbJA0@5<$9d5^z?Xz5Z$(EY9#tC@G-}foYx7v3L7!WIEDdBD_g5R|DRbkhT-lBTN`- zu$U!J;0t|MUYZhyW}sXMMH5^fhWY)AFs*Ysj+{7*BPS2z#TR!WU(AC@p`or37cJd@ zrE`}fol2vB`dmD{q>EAus!CR!2##Y(+M-d z8An=6A)^`4n1Ia~xa2TP7D^=(qoZT6N-i_+Phs^FuJO1!;)YW^rmeK7jD>q3SVjIl zTn!Q*7*SnY4xkC*?&>X~l@)#!Ag8j9d3bW{)Q~z^EFa#aVw?agv-yr~dKzp6IF60k zeRJ^q-P>Ufo5-}K-F95*R*rad7Cb5q#X_T%DHcG6!N5WpzAEO3#Vrqu zm<;2DGX$R1|bPm9_r7;eW$t_@9%3tqKw6XCYqo zsh`#8?XY_;6>P_H1szHSSY{DQ%E;%G(m^(zMt5fq_V3$=Y;OO9yAy`E# zM2bX9C4GfcsT3UV=2xfril0TYpx5g-dh{>~g%XrxUdI=MQYb$S7foh6zD_{guSqtjZmc+&zm_k2#KwQX!Ag zk+T>cIEj&=vnb}r+=;K=iB-~pWfoA(kD)L=ir(&Num&vT&lD?)bP{9dKua!EjUK8F zjL(HD59f5VDb}!q_Qno(p8O;heJVm5{=bFLp$Q#a2rQbj40YMMexdR8x~`+nFly+I zucS?>@j^g2AD{g$w%7g3?mvwesbN9InoCrKEP%4#RnHJLN902Zhy&+)98H=X9 zl9=;2xWj}Th101OppHvQg@Hm9ERsI~H9iP3VnL~rv7@TpX|F+AC&HjJZ zq(@?OQfF<;wxpD43aTAEYw9Vo_^}pa2x21@$x(Z9{{m1XA%md~-uF0b&@3F2#|vI2$aRO)M7+wt!(h96tpJW-jy!oIjiqD5v0Z>$Rtb)6 zL3ybRe^$FB1?gC@EfcnF!m({vb=50ODVY|2aqpcN92kV2)=@ZFMBVf(k|f(${Ii6~ zwkn{FUO|F6Xo1@T*-Wmyu}%^KOeJffX*zV>fZzhUo>T*()F!%AXXXMx-F^_%p=Bv<_Gd!S{JOToB`4$G+&uB=x?k93rzt2 z>VfG54+qteELP4+75UvVX~%%r;w!s`WeYlC%vzDNo~nar}55bw(YsMkZN_V1mM-WN*n8o-p(@xDXIRhhby@#xSdQ9@<+v z`;MGA_|92f-G8?K)Jf!PW1C!{XET}8PRTBfo*6@1e+v|=IIo_iAOO2}H%-DqRjCC}5E_qy6d_igqA@hVBO85JrLyfNP*JI98I8vE%-hJS zX}Tq+;zDJvfIAOGg=pUvuxpG1Y7`I&hgmekK(R-@4~ue z8?b2hVhoNA;>lf)zY<3DqkUi z!5D+C8_;weoC_F68oHhW2xx8Uz~Z?paP-8XH}5@p{NDj~ss?eNCY7K3!MYqX021U=D*?VTLRj^=Wjp`$oV*MR18xJr> zP{d%{4h-FZrs+Zbd1bLl$Wn()sV@f=xDavGmV_9N;v`yP%BO5id8pSqaAzr;E@J_k ze{K^?rxEt=D}5VL2_Gj{IT@u8w+|Clp< z5U9EDLKi|RMT&@Sp1ppSmT5>wT{fTP3<0kU(5SUK`{DrFco#NYe3{pPP#J@U8#c-e zDo0snG%AUNNi0Yb5frwhVM`oXeil+QMO3#v4)Em95nKJJtX+3K6$Qs}g6gzVVH}10 zDDwGHH`i^Iyfm1Kg$C{pq#Oy$Dxp*uN3k%5QnBDlB`fK@hDA2b@TU}lqgX8B=Xd`c zcieRc`lrpp^_Sj+#=53RIHGZZx=cL=Mg}l+bQpS0gVAVAI^=4yV_?T1vSu9?&0GY| zMRjL92I%s6WEF-+*A1l8IcP$IuBVXA)I-yvos#KP4vh^h*tYY@F4H!5>YCWWz}>m< zZ)A(^I0{m#=L*BcQ>XWwnVD@&gKGjp7hr;w38@fT%TZ?(5L!xuq3eNMQpGl1?l4TS z)Zv&Fh!tW@$kfIycyebMi>Tg^SKCb!w2{U)q&TY_`v#tXgoJb)&tjW!Y%2t2cP6-0 z3Z+s3Qc5UA5JJE(3}`|FkqRo?EVJYe%uuRwTv2GYdl=&WB%RY|Pvf>9{}4M~cpht( zT!alPFG1SK1X&aRJ1Gzvb4^$|dlk0sc^U&dhM?zkq*_xTMPO6lLF4ExohiXOYh(Vj zMKCnOEme&WxK&adA=jNEsXahwI#Q`DG@*fW;r_1as7%yI%%8OcbNd&hwm$#l$85*B zhqGF&t|`Nmv6(#!y8zhW8iz162t&AvDuP90(hvz3Sdo;#@aQm1vxH10 z7X=PWZZt_styFXC;;wp+bGa%9|mkq=aMJ9y{*2){YG#1;#j( zlsI<$2zI`(1N-*x!PwX+&J3J^Fr}v_>qZ64-27>c) z5mQ9JF6!BkQaE$=G`8*7hKC=26vHDUxNO}OSiNLj)nSZ&9=ti%f+c-R@${ajG5FFj zI##wqWCbuKLs$+SWJzLR=MdU5?U>fu6Pox_CNcdwgye$1vVNaOqk{RQn`VG94qZ>f zFw%)6C?ke+DvRs4yd4J)?^!=GHvHZh9o>I_;KWgs-oOJHHNhF0(y8&$eCe5?W5bu* zB?rO~kfwxVNifbJbOE7r2+g(foHHm^Sx7^YFf=@fQmKG!w(gv}xT@{*L`Vd9nfXt) zG2vl=glM{~TzErBs(3Gxgx=%IEmToTK}jcI$Q{Rq<2aFY7RVLLP*P&|-krGTzPqsX z*{3izI*Nw+CbTxSp{2eJ?JeyvEfcn5A)BegSbh{c_q>3u_Ok#fw6(RNe`Y_XPn(Wu z-92b*Xhb%Xh48e{0YEwu`9dBiPo2cp?ayNS&K=0-3+SId3s{!CInK;Z@ z+0TkqLo;Za0bS2{sxlf9m#yRyc8jP}zevv=623QYkgawIZ&}d2UeS)B2|sP>OlE3X`1db>wsmejS2K%7X-EzMvJEgj}CR~8Qrx?A_Qu|0nQ*9 z09%%8pSd@dSLYx{VR&>H_uTh$%$u_ijCpQ^$v&KS~JJjG- zR*j8mx+xFT9(bi=!|{H)v9okp@>tz}Bu^Bp#NkY!R4U+shwjA>fAl?^IeQvQ=dHk+ zW$V$^+6_(9Af*G_E=4w)^2}NwWu%Zc(rCyvVCJ-bEMK@9`C=YJBWE!55_e-KDx>}mQe(23eS`89gFeI3&-HdS^VRd{}lTU?%Jgky`3@keBQC&m_XMUpzAuMR3B<+ zt^dzWAK1X_+w01#D~nd2G45LUvg^*lIB@iVqDzdy7nxr>B&7U%pq>-*FT=uAUp%5vbB^LB%lUEI- zq;wT>z1WQu(oJ*c&O+P|;YmDis#{ z9#hT#C)FP$g-%7Qh@)qZ;Pmim437^%GU;YdI0HEfb*XwRoUstyE!`-0M#ZZXLm7^U zHK)i=e+g)M3h8tXLNlOo4e4|pGMV~Fs*WZcvF&Fe1fG2EL44`fe?&e%_CrUik8sA$ zjK9Iat^t5U09OPsJX#no96#~W$>|O4bIbF2!d`1IE{VWw=~{b@y8@BpHkzASFl*Xu z+EGw!bB0>!aTe*pnI)NqkrRx;HjlNI>Hn?;hl#Hivt69^e2gSkEPFso}8hV#QHT16Dif*We+X|y-C zA(zTVhF$odj6!w0(Q+V`_>+L3eq9J1+_UUumz@$*r`5o&NMZHTjW|1S3g5lsD>o^! zju##0cMTy5mVD!A%LUsbXAHKK;|$nL4$YgkxCdMpiSw``LMY@)5jm#B*ugxe*G)%P zYbPFm?lI&tY4lB>;niW=0l`J2g7!CpZ)KI2*H&e~`6aUmrQfaRxZ#&a==a z1#cRP^5b&bg6-w3Ewd2FE?K1_N~HqKViA^Egk_m<9G7MHV|>mT4jnm&Z+!QgC>2b+ z>GC&Y-pu&{Abso1kX+Wu7{D3D=8RWbX5XccSY76C5|sr=j8#{WohaK8FOUgKRWT3* zXUL^dwk2)e9#CTLpG^)xc+dbge(FRxmW zGmhSAvv79kBs+Y3|5CyEK*@2Q));%kMC)2P|42w1MoCF|+sLVrtIr-dYxFGYo}@^` z!x9HdLnd^~KwUbEY$}7bi`L?SM<2kdWy?{Qb+y8n@45@_)hBb0QIFZ}$YSN5+wbR& znJf10$E#la9p2boUPeVMwLb#dC)nI6pWbVImp)FoRm~c^MJ^{!oy6C^{dJfn8*jeq zZRl>BR$1!F%0P*xlRP3THX~&sFvbNGC)2p7Mtmm6aFm=o3w>5sAy!p%uTgB92s!Q` zO!^@sF}1FzpzA3x?slf7Q#t5*s_flNDJ0>s73=2K-}$Bw!!%3jC$~TH|K&8}Fob@4 zN}6v7eYwD*OJ9wI=ny2WEsmCEcQ5FIZfF%C_dB-A%^?i=69r_(GML%X3(h!l**a`} z;aRjaHDTto8EzWMv)EEfFaK=2omvSu%W^Br!apsuwetmLkPJiK?a{x0iE{vx5Wp`mJBb;NURcblJ_A-qq`YJh><( zY$-X5$KF)w!Y0&!qRpWI06l0)L_t&_Ojegrt^U7STt9gY1A!-GyW{YuYQr<*nt+ph zez(Lm15MK*xQ28phg3Q{!D}kZZCu^=uvdhDyvt;Am^W)Nj-EJ>Jv(^vVy5J&f@8mE za84Jx7JQ@#`SRYmI93=f5inF5GjB4|hSAp7T6u{*l@fQzpnE}w_l%-DH4W_zZBQW8 zWpWtJk74_+=dgV7GNe-J#KkuGEy|cXem>iAAe9X%RX~)LMM{U-M9+mEX@U59yn3qpe@Sb`Hw6|@t@#vKPc4V!$x!=zT+Bg87} z4OoI9jrBFeEO;5zJjR%W>(^Lv05G9P5_2sz9qDuyn&yg07)Hh=NLoYTBj|^_4NcmgykYGr-xG0|UrkI3S)X`7o7AC5OkIOnUZ-!bbm4U9O+}2^;Ky|%y zaHL<@Q{?XN4-TT>f&Uv0b z*n91@c=V3bx*Ora^4SW>jPwm&KGQ_?YSDW5KUZB&$~MPW=NFSx6Hc?a{*FiCejvh} z=##{y4lqE7=O+7=B(Wu~{^Rzx+T6JE)Z1)@) zRqTwQ-MZ3@m4)wvEr_7JLapWys9N_RN9Z$n$i06tHs3?ykcq6*n#Kfh@~Ra;XArm# zPY5%1yQ>UQ?64V;y6JO(TWW#}=){(6q2Vk51SQ zR#@4K>w|nf&`SneZ+nYg8v8p{IG;RNvGRVr>YG`-zP$k!jX0?qw3qE}Fd5;d-?d)* z{dQM_^{uw8ZVPwOXCu!mrrGoXMG^f8VS%-`Ez5Hc5-oyodXe%G24<)>g-kx*Lz0@( z=dZWT)xJ+gwjs$7CvZ7S$%;nFvPM*qVdLu)N@gSEykE*TsA(ZQ>)M@6z-nxtr|XNU z<1sv(gXdEA84iF@eM}Xin4?rbt`*Npim2X7H*y;f;{~mY;fE#on-Ic%1w-Jd==2sD zPIl08IR{_Mfz=`6L8hROzU8<+3l6#t3t17M8sXs(nhzQf+z^VI0=*XePSlAa*mZua z+2l&dsMRxKLsOQhW`ybXY2=vxzN-b{gf&S`4%UjNm>kL3mYONDK&QraNRRe|*>P-9 z->5A&nQdR>t~<)@q2Ydz`&lR-96OtiJZbVrUTw@{CY9ZW6qyOlLXHf9E7}`9A#m%z zFc5!)z9w5XG56Zm_MK~k;b2EUI!Mk!MRYzi5RzvSS0)Z6)w6XQH@LPI@N zz^|bi5Ervcx)6FJLf{zu{oxDODX)g4n?mtizO)&LF26r4$DI9vZSmCGvXkhorl#`` zaxr6eY8`b~$OOKs#=C22Z0gfszTFh8g!q$m(e)qULtPwDai*}T5S zrVX>o^O7NKnA1x5KfA=4HY;ai=8o!Zvs39AX?B2D22*RR79fHzrHVCA!ol-dfM`f#)wNoS)Gv5!R-3rxt zt2w7JU36o5a82`i_yhE~@v63Etf{gFKXvJ-6-#H1|DhtOii@1Qrw$)x5my5_niZxco;rhk%y2&l!?VlYU8)RexO&DlYYwyAYyD+CeVLW8 zrq^V2G8*b*vHHrw2FXvjRPQn;Z|mcaU+(r?*il9?x*e`RhEC81)f(3TuPT<(9SpU? z?@Me!P-0Tj{&!g?k(h2*E~5|nl7WzPO6hb|eTp(yrUX8Q?J2Z|KPK%7#;nEZE;!=e z8x4;!J6U@E(4?j+Mu0t$jLk;i)lI}w(gGyW2g3ykwUWfLS)3WzMw%@Omdi(mdTEQ~ zfV7Ye9c{S;U6B#7QK&`Yuq@~z(8=RH95mFG9{*PY&`4;}73|)vZ^C3SHi(%5q34Zn zGFym|{xgDpX?<~NS*7n+02{^UEAV9Knaxrg8r;dabeffoU&BIV@lg!X!! zS%c?la7>t2DV^PU;HL*m)uzzL-w|$!3Hm)B!4D$$>+LujKnFOh&l|*u8k9|_-1jF5 zNe)!G8&5ZLJPg%ZF+m@;IwU5AytdBn16AA)uC?@uS(Dhrj_)z`JD1n}-QSWfwQ||UwM1K6~YJlfTtgn$RtHs%B`{l*L%^NTd zTg59`86o}Ks`4dFB^lKmQD1XqFZasYGN!DioVGk#cI+gk5$IUX>SMlt5=G|edwu|d z#|dj#c&uepb?o1A;V%?b3|B#tI{KNog#RewF+tTeAcJm&eAa1B*E>=e@kiak2 z#fAr14xkgM8ml%OwVU>O3a2W9Zf`Idp`Jv9NN%Pvoc7^|*-xWH`T7O&Km7$EVixf1 z=P5Ckou9iPMpGIx3|pkmd~w>ekXl^fAWS*K8M2+YWVfU0TMTfW@3i2i^tJ<2hm_bz zB94|k5%W0f8=dv$Yu<-3CTk%QPj-vAfE0l+`AJ2adXod zcXY>(vk~Q1n1_i!)boUH{a4r_d-z$C0Ef5ZDkuja-dtBV*P@1^q8cK+ZLX>$8`9BS z^bZd#3@UmZN@V0VsQZVtrI)j|-teR%rA^TBlDW?Td{%5GH;nEW1LqW>nqMt3;(keu z!3(`zD>f;f2tP-S@Nkp+TX=tuy@@QRXt^((v zDLMTcwpTDO!Ud+N<4h`>k&pTNbJm(I^1V63VA27sGnG7Hhbp!k(*bBAYH$I+iLF>2+4RrFYLmM1v^h%{tjK;Ha;dw@WKEM?5> zle}d%b;V9q`(4seinW}oQ&QNjNY~*XmpO+qVA~c#wc*|y17}f%iFU`MTe2s!y#4|? z<9$Z~NaqnzksF&9D?z0(T8?YnFw@%!xg0fJ6~umQW}5f}MYeelBu$(BVJ1qqQ#EqD zfFzic=m}-7_F&oS3+y;{HSq9~l;e>j1u>yg0_?|F=lDaCwM2OGgc)<(enP2t zd?dRpl1i)uD6}(Y+HH8A+)6l}qx6O>>^bRn9y#kazA3XE;#D{G)$lZ6)ghTg9=lT2 z2d4xE>^BoogrlSt(h8@nR8dZ=XrJjR1XoDq{H~*)m-BXcsiL=X3y*xF0U9p zYiF>x@7=cgr>_Ja<}%}MZ<+b-HCv zKd9=hGp$kH$=8C(6RE7)aKq`&ex2rB-nmK&39W-xth80x9+rg{freha1cD2(<6y5;9|M{ zeX6o@T3h-W6OKyp&NtH%qj6{aBiK-p<0e*(HebN?qyH?tbM)=%DPMyvDphFQ%sF$3 z7p19u4#tE4q%u9aY&W;NcDYgS@J~Nizy&WbCj(SQLJ0-s;qVnNFA7S99GIAJIbTp; z`Q7M$TwECxCISrav#094Z^f7%ewP+UM>6D_I-(YfQDSs;-n#$!*VhAxOFHjde4p)k zW>D+l?3%E5OG%YXDyEh$7EMb2rFUR?(JwO^f|O_)D2z%j48n;(97-f21(UF9B|*U_ z4rjsdH;mm$wpx&HG?pc?B?BACZJOB1foa9TAs6>g{6m zQse3*;oCBW1H}%VC|kacRo(8xS_+rj)A!lwxxLL-7fma6#kzM*PUfh}iElXggpeT( z-QBUQ$Fs#-r@NbLOPad+B28<9zlSl~A4fNs`Msde{I`_DPUC4*b=ZzM+igv|He{}j z$UKZ3v`56Xi5F)^`Y$Eys|t2F5$^DO1!30q{WU8yhpyfz{&dquP>Bq1^D>-Q#(vkV z?OG@>>&Hwlsz`)bjOx|rhKL6o2w^pB;gmI6W??vfC7PJt?Ng4Xr{l|bzO7N+jP3a2 zTod!Wn0GC`+EM%|nI`bfeKuT*qq8$n2q10axae{Wz4wlwd)8`Y;THQ(ABoX;H;(1!g6epr$-;iH6%;9u zNMR;#xC9i@A$px{!#a|m^Gky>K&Rhk8!mrkUUjIDc{PnEfeNpzJrv9%$obfs+xjOK zu=H>=X?PqXN-I`N9AhsJWDjPNl;BhVre&n9Y2befztmxo4g; zyv8l{L&4(w2*gUQ`+X|o1mAPZdh7ajtp|Hin z&dnfh{6t_73`ZRw$dW3Uj+l;Ydht~p8XGJytL!SgAdb}smBv`qat|blbfhy3Yu3w2qwbIM*tnaM zU3Guj+io@5$)4ZjFI61-r{yq=VeWtCkuAlk0Lu)%gkS^vnMzSfS@m`7>Fs#Ej)w9u zOj2-g33^Jww;i~Xb=oyCtilvq;H1N*JG0f4F**6h5QSRre*P*BJEU-@e&&>yBajB4 z^vd_>h%S=!??NH(r5)E>Nzj!Ki*@*rOzF`l4nBA*)Vvr>A1_Y6acjtP**j=?Fvvh??p<%*dnYcJ2 z_uPhVV14_UTz@U;eSNF2t)2f}SF*c{E~XXmdmg#@h|QrtA9#~NrO?fsz!5JL_-r*+S! z*NYORYHuM8d|eeMPmAr5i8jPY^QW1`dmBIl+_~LSZ9cc*@0mAl<^LANbVF5N&)%a} zQBVJV=UFvjYScXzll8$;DwGh$GxH=B4Ifb?<_nl5qtpk@k;H22FSvb=oAE5lLAowRQ zkSIz|E$`zwj!wfyUKuK8^H&A6rKoCTR~DP)=J}e8Ur3*+y%gJ{k7MQth*CO2M6AEBuo=k zNEp~6H5N50D(GRn1!ce8gYDz6EmJ~f0x7(@*3sVl!VP?cj7QCZ9#>LshAXBCWjR7m zwE1f$sXpHjRCN8z3#PBVx!H4OAtj>Doe=h%s$2*fSTCJbGC1G)c2rhtX3-}+npS2Q zRG6H&idY;sQmBm>tw)dMvZ&4favJrQ-XQpAd86uc32sL!?W`wy?VVyZ%7~6-mCPCe z@vbZ;SyQ)`c`r(xcSp~QOV9Bal#b$$?2?e;#*KS5*K0Iq!5yMM6rC`(bOoBbc?&Rk z=Df};Y3L#d^}@0(m`c~PNEq3J?ePuvwh(O>YY|;n?by5?x)m^IkQ&o-1zpukRsl&Z zufgOOm_jpX&9b3p8gMQ}lg$|v^Q@xVLI@3oSploowXww9PA}d&_ana#T|1A~A4hdZ zb`61H9_(*3=~z0q<;5|x@t+;p<#AS|OKt&-y-m#4S*+ zWDRFYW*KJ_i*Q=39y<7jZWs*bCvm{mcf2lgFnlo+u_CC{WJkR;=dH_?{B1fK7Io`82Lpmd$LN>ui8);DLJ zCin0Pr}n(t*}|8n#&er(mAge}I9q({tX_-#e%rF;t!rHEsKD=0rHCi@awUTPksYkz zvAaSz?x_V`sbW83H2HKsDcK=Qo#`na@w55%Xz+3C7rP;eC9I~Fb`Y}b@;Z5#(IyND z<#uAEcmd+^@$FJUPf!7oC#0a)C#J9Cq2lq!>pfNGEncYSBA7xLDYBHXkxZMQ051R3 z1(LydI`c;-$I+E}HFL{n6`^D49FMQyvGy8Y&Ofh%OM> zHFe7bY(9`I;T0ic=g=rNinS+!j?-a)f%AIE@7W*0$9|ozF04?cec*+h1{m7TS~T<#Wl987cUzbL>5FX<55}4EKl~c~?mWDeEt>*2LVeu>V=fpjg zZC`Aw{>kfz>8*XxnnSrhUABSUI^60Z_S{sXr*c(SJjz@`EM}_WmdAjdklgoFJ$2~i z)keM}>yR1yIUzI0*n723U~?KwUhMHnmYGZU_~5vv-8db(66wHq`JlVBQ{k3glDhZe zOz{t6IbFZsA3Ww39L77_8x8-Kd6}6&HP`lE7kN`tQ$CruPkrx$4nzU_mn(vuLeH23 zNywQ_8a?{|;x;^XXhy?F2W&fMr|(-koD9UEXw8BKjYI4TRL{U;cJ)v=Q`pT9^n<$9 z3mYuMy4Tr?yfN7kP5*nuJ|jo7Cv9mw?fDxe@4AD}?X-TyIe)gDKpHj$Z?tkSauq2T zRTd8->mq~>Xwx+o^FBYCO36}aJHqS!jLdXOH7JrB^L48JA=<01(E0;h2QJ1XLfC3< zU^_vgJTR4zI<@3hJt~6Slu$=tM&6l>tfbxSS%1^%U2k}|dfV^cmJbo{&7DFjs)Rr% zQ67OVXBRTn5q5yh)M)kf%kQr~WOOK#hbn#ww+X;gB7GmLTDx24q=Hdg4B*r35RsqB zJ77*bKS9PYM^&EIie9o*nyD9?Za7ggjB5=-M42>#tG(nahqeN54SYy_4ey^6CX+7O zrpQRPwGpr))mFthJ}j0BmstQMx#yv=#_gjfcnLCSUohp8!}w5^yi>hk8F9jHeGR~3 zgi#hDw2j7A0;e)t5a=?+m-_jy{U0$d(MW#IQ}LEP(C7TJz`@QVm`bowNF&(M*~n`> z>8$O#{WZVRrtJzsXkPm`cxxGF3aEAD?5gEdwo_QM2%O4G<%Z6(Uw3S__UgkTv3q23 z_$DkLsEiCc>FiYh1`rt9M8F!37qL?QZ#(qjYGr?dDon&h9kGj)My z%tP)!o4$07t;}S{^R7G9CHnaBnzqtqu-WJcy*gt;eo!rMOay<$0`Vm%qg!2RH;`wm;@6fJe2%qP6vc-d7qr^eI@?3O9x=b)A5>c z>8-He?xm(b-GV!;&~sp^dYxAL!l5_U6{_ShU2!FNAIeEa3lsIZ;)jfHRoq4g8I6vQ zNGSqf>8?bFshyuEm@V*{ZT6(Rm%cm zi}Yrr8mrB1UkaVT5Ulb4(Kc<2=G@m-dO#P&s_yozB_=&eUEsrD;9LO?xcNz*K1^Up zx~|!x#z_m|DaA%G)$lgi7O9D#H2y2a6kfNpz#fB8=VsJUYHX)X|ERYs$ShQ<>ElA2)M}x`hy?lt~xwAP9sUFqpVVl*k zL3|TVoWgBypLQ~W1F9nA>%{oZ7~hBf62(en`O)WTPblqG$$~_Cm=Uf07$|lpsbCm? zJYO%l_v&OmVO(L2uI89kY|2XSGJI`vDo3(D>PxY=L`FtL5pxk96EKk!wZmNzh#lP80&K((y0~JG# zn@?~{j3038PVfehV?Po#Rpe`s5C4oRau1BNH!d+E8td!3p7cX#@0kkw``^}@j7wqHKi4`qkiZrpMg7b@G+a_r_Vc?&u}Z3 zVe+ftO_fLYEE~%})QhoNHJ$*KuH`{A|B>G~mJGTaY16AjTSWntG9St#|LCDS1|B?S zECg78B1D-G6AhRo1i%X85OmiB>3it@CV-u~T&`14kag&D*{Lh7TU8?R^#HR)5`l8m z6yoQ`@-COi~HjhE%zX#5#Zd!6;*cR9epsAn-t;IC4cH>H*5lNI{_IYR=I$;Y*RKKHg{HMj~X?pEArXI^$jSvpJO??;~M_rU@ zm`iuoh+z-jv*;|Z7J;@5EN{W)l^7cgdM!@v8K<5LAI37o6(_Rq{CQzI1=z?0D-q{! zj;R^a%o!0$t>M;1&=be&A}ssA(RmHt*=Jc zn;*D~V@IMrUr30mzzkO}-YQGmcH#sDW41K9DTT)2t`X_-voJdmB~Fc+KW+B;RAlTC z>i!xo?xU%^IatvjJW%jQnf`zZga!DV*1CC4y_|IBTy@=px7UWalgaKF()?&mXC_^( z0TUT?`{Y{H(F^YJ5NGs{U;Y)~uN2S9@Ao_TVg&QTiI;5svnx`@6tflzlYI#Cd)XImMbFS)F2h)u@%%Oe?yrT3xigX?>?Q}$nYMm5dC#Vi)R*!7cy4{ovH1sw!g$<%{dQQ@b`8#-T z3det33$M0$4s^#z@IBVaG{_7<>lefpnbvC+s*{QOOG1M3@@P}H#@%_pt_PPrdbU-J zSX2r*S3QIiM`BrK96BvjfdTDvMO5-f4))EBKxXgwfPe(pOcm3P0Zh$u04*XsSq6w*{$hWY!ChFj| zk%2~wTk&OGf^q4qnvdCF=}~v-jtcBGXBm-vsTph&HBIw)Z?DNVJlo3Y(rc>Y^ZaIQ zBN^MpGd4D(rV z`Kb7OV;$%Dyw_vnt4y=aSW68d{2p$phzHAtu`n*M%F>?t-@wS=)|Kj;*b%fSR^PS= z`@VzctN7DEWe_64CyMEbk`>?ao;H*qs zBCpOi(QFi>5IqzB-ulY5zf))|?kcN11?cXXOysohl* zYOAtRR70#HfTaSVcK&_!eIb5btW^})w5fk3)g9*W{Fcn#nnFJrs)cnXk6rfAZSso{ zWNkvz&KW17%D)LC%)9@ILB8kZ7Wi%b5=Juu)ybUdM>8)S)4FaVmzaVOO72o=6Q;S3 zch$(XvHfLUjP|82gnROCy7H(A6Rb$pI3`Dj5)cg)J~$aU^*~H0=U@ak*V#O9vH15bLj*3y0YHc2s#b_>auhd3P zQ?5Bd=^B)&%W;>W)aVUZv^aU%7Z7^=Ypt40btW4;d)I&qGH;3^=KlxD_W*WEC0k9v;gF$JJGXX)pB?K1n+RY`Mb#8HP#%crO<(n|Jnrp%E!I{WTPB!_=LZP~Y zPDGmV=0WtUE7d`vLO8Cd;ljH6&)7E<|C|}~hd+Ud>Sm80x;zTkZLDZYuBcp-VdpQm)|F`kSzVxb2_~yk>JzWs&YiJRR+gkY_)ofjX^C!C$P*X$ z975?ap_}orWzI8|3fe54B^NFe=gHC{)Je~+2{PWN3mDT7ZxzR!z-Sq65ze``zuQo&eeGh!uK8R?z$K}1dk%sj0+ zCYR?BSfF@&)dOk0YM75yf)tIDy%ABs-3jN-*0tay2(#qHjr7=O&6@8V#zY7VGS?Ek zYJ}=E5{HvqdCZM+!#K74$sNmtYG_qR01l)OL6yy%yHFk;hz}LQ5XJt2Pm~>7JuV_@qd#e~TDg>cSO?|3~yCa1XFFM4> zaG43z&T%f$brg^}9oub=lS|4LnFBU zo*jMPBRm`iCE^%+;dF1-H>;luCNL2SI{u(^O_zDMT?va5U6B@^GU?3lnDyO|kIGi) zoC$rO3W5fj6sCv(MYw`61#*U$a-Gw_+M!om;M0B{!4Qp4b6$_P|A#I@;=y1eJ z85$bf)TW3a&2^f~=Yr7Ufi zq?4Jlqnt9{cvOHk+dnMsm@?gK+LF6mQGpkLhoXm`H|@60$fLTAd;!7Nb@wwC(bqxU zK^8Gz-2E~3w)yT(TeH6;-jZ#uf$pP6muwKx-_$~k%-2^J)L=s>5(02+1Y0ou(?CMB zwH3HvtWc)N{?%J(5kXnvY29%Eaz=mG$Fdee;>f){ zDcLpKSlaC|wb+UhPDoOu>qg3P`)XIK&Q+UEy#Da7ZZlP-vD(;Ksv557y3?$tirZn8 zogvPzmjuU$A(IMlKFh#=Ye+*LXVOMx3UiO3S%_t^QXhWM@C)d%Gx+(;pZL_Zm~;aR zP8#IS`c@`4p5$0Cf71N3-&Bi!y@4q3I|9%h6j%;s2F*!|%_~GDt2H>ImN*<%Qgf6D zZ)d@2z*`{U=Gtn4CeTV%&bmy$QI%DctldN6?7aGnCfICN>NdzG9*_raB2x5S}S-# z^PK|I0Mz1Zr3}iDd%Px3CnR<8X}WM6Op~9a6xlPB`L6>ho-aBEV;k4KE$C1K7)T#0 z^C#F~pJR_RuG6LwxpVJB#a!}aH6Ae1p{zQ zaRrg>i}vxg%p1ix?&dK4SV*CB7n>rv+Y+X$|0wf+*|92zC4-1izdmpY1il3P-4IQtcbJ-s%uaZ>f8?7lK}x`WULhx zi0<5GLeYhM6GNkF)yaQrt zRDCyNfy#!vSi%qEaVtA)_g(*v1dTq2VM4W!pK{lj2IomGEJK6Dad6l&cutxjaR{q} z9KYgBIpBuCjBp;0i;xQsi1^#c(h^aU4Gk#htAeSM@TDhhqTg?R5o0^O0{3O@ECLF1 zv4swF2*0 zc>lT)x)T7cy*^)m{E0z29N@Y8rLgkv%Hb1ode%02(l$md-8VC_2r^EdPSl1%XqB01 zT_^%ZxDXA76mNziHv#;;hO<973WYAv?J9Q7UE*ws3Dd zFzJr9IT_Ip7Z%a1c-=|O5_0^pDO8aow`n7vn7=X?`|=zb_io1hQsT|i-#w+J7fbab z52IQ*ZVQl>bJYP+^$_?%HjsqYIC0zY5BnD053o7>|q(CCXFEMSrCt^KEvhST9(|( z#a2_o(~dj#a$Ma{pnAl4r{ZK3SPMzuGTx;+>@oK2!NVylsGu8(M>w!Uh3fU9gY{CS zLXa;2RM)DG<1SmV#Eo&{s3e*oJj6#IB_3(1DXmrQ#SWU920ItvWgS*S8SvYTtc_tn zw9&ubAyLU$7(LK8E7dz21bm8M$a2Q#7k|Q_= zt&%ezP)Y{L=J3-t(L&~RD!Sj*L|lpFbAOc7>t+0$c&ENC2?fi|<^@s5zML z6z{5wtsMaulK8EOS-g!mZ?;3d%dh#5J)!YY6KT$~$S5yZe3z)41RMqqD=|wO|6f#$ z)MfMW6zktO{P4n@aE6>{dK1$s(<@98sR{x?^oCsRxo>bH2=QZ1bUho-+fh2t7h|JwIeVSPXMteCSTeDeq#ndIY*(WT@Eb zK_#DGN>RM3>k9x$*}rc$FD?*DIUY|JR(xN-ODZ+gbaG zqdARde60tN+gE`pY9NQA!ntu#3+1ex$W8N23dKc9qLPZAYm@Lmlg2kU=aUr<1nQs9 z>0DFOhiTW7B$VQi&C@e)k;3_~-O~qNLi+oCf*wt;%Rij^;WiEf)4$DY@O4mVObHar z?`kWH!?3@_B%>Lk*NdR)8VuBRF(32bz{53jzvzC2p+w*w4j+;FmzUoY9DggtJ!8O|f9f?KqQj4JR|`XSfoCt_~uXbDCc z_*0%&5_9|KC;?$RUe|eT8<$VSEGIg4yM)FZ;WL1Tb@Z=jfn-gflmrgOGEx*nuwx9A z07c}}Ykr@Tt?OWy(HPOiW-C6cN)9t~FG$Vepu;x}&9K!}7+Si#UV}O<@LZ<77vp)) ztAiZfsV}N~NFtwTV%c4VeM15P-h>S+1N-(&L4R;)#~T&a-``N|{00+-2r2Fr*~$+h zxZUi<X)f>C=qXwblsz8JwDe~b`w{}; zxIIoC(s4@_YVQN9ArxZQrUAJ_Hg$cm62v}GAmC9;iOf`tK?Zq%!|%*zEOOLR^nFgBFag)}7euy7j1u+s7L}L6PV%;H0tE z+oA77F*H%7C=Z6brUCgRk@GLtH%W-@m%ju<(ra_JwKcmpd(XEPg1+d0-VeTbLf+2i z?oCf3(LRY`1>762#eRhIgwJ;t5=^#LGm~1%VgPlezuo8IVXaN;WsToiufa(E);ow_ z0Oph$r^E&OI#9;y1dx ztJusNUpjZd#v4Okt@0a@av%@Q-q0-PgHUY5ysuCyo$2uhbUt$S3=Al498~wYK)gE! z5S%;4o+Cyax?%qDR&L}yLDA6si?=WJItl_@M0l`<)z%&(w2xhr_+@&zx;5^)?~-w| z)kCn=ek(jECvC`LKS}Ik17GC2p06qa=ZkUJJok4r z@VDsHt2wZejKPGX^#Jq}KWKho{B-s*bGY^eoF)y_OBLx$JUkrjKBLdnCaVK1-3}|n zR=chExTYKsVR^jvOoX#42f9oq9|a<@_;rwNd9q0Qlh*v{?)2J{=RL4s?-ONv$Om?3 zB!WuNc5beK*TwqkP-pZe1@$411a1dQv~%VNFypgN4XP7_dTQ94qoKJbCMN8<%D&|N z%<I24i3C$gZ{ zmGj3qvY`@475s9m`*J#F-X{2^^9m;J4)BnlLm)zm|5n-qu1Y?aSs<&w&X00S(T#6I zsCn|RU?x^pXvFzk;UU+35q(@YJlkH^47prhji4N}Jd}2T0;?b;JZxCvSZR?sTu7fR zxW4a;(qA#FyoBoZ0TrNT-; zVC6GKsBiUa!G%m!XXx9IV{qtdZCtN7zDr)}ojT3mKk>>#?0x0Bb3?7HM*GYbp&gN$gIh){uQni@{g0L_LAFt54+#VdZ>^X=*$N}>G zDliXtXxl8K1eBzM>NsC%zJOH4z(i3>9MtJ9FyD2hGjLEIM^?U;xWjw{xxwooEi=0l z0^fqu$k-R6_j>4_4-|`iFcrapvTWPH!NCz~S{v?y-5EF!xW)7L-u(tb;b+bP=;>S6 zfo%{#1H+qhupWd#AJcgRv0;Z7uHd->K1R26Qju}l-t%}XlUfMR81jZF9Gzz7CR8@E z$nXI^xOoz|Xlh)XvQHjJ0x(VEQ36(C*n6uVPMPoy!LN3So&gj{ScDJ|Ux%F=3Bq&G z9q8T^IPA8qA(m9J9hjn=?I4`2M~@pMWC;7t{rIzuVmyY;qtsRNhEes}@09bEhJX(&eL0@aak4A(7`V4jj7 zd;lp>7_2t(+msX-0015y9*m9-HfA1HHdc(LW&lwmS2HUf z6*mhjI|pYg15PG3Mn`)KxPNxJAa@l1xibY>@R&H8f!@Gan3%a4nAjLtI8~XMc$m0( zn3(C9Sa_J2yf&OR|34SlIhb0Rd;R}k02e-C`2RN8#lhUw!^qhT%pBBWP#XbmF3tcK zOVBp}QwI}(m7S4=8R%tYV#C0}@L%s7>;aapcD4X3ds8z{#{WK|to-Eyxx@Ld!K#*S zcE&tBq7Ei*|BV9=k0R)L7cl0Ee_eq8%SP%y*E~FuW>yxKu3(&89NOhCeIOg`|K;cZ zvC*(Hb+rWJ^ot=Y~ uorRr^dC$T7H^>D2fB8|d@-_owW#N($5%FP3^#uJ2CM6~>S}S50{C@zhEz)rS diff --git a/.github/workflows/reusable-docker-build.yml b/.github/workflows/reusable-docker-build.yml index a4151d3..3f2f302 100644 --- a/.github/workflows/reusable-docker-build.yml +++ b/.github/workflows/reusable-docker-build.yml @@ -97,4 +97,4 @@ jobs: push: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'astriaorg/spamooor' }} tags: ${{ steps.metadata.outputs.tags }} labels: ${{ steps.metadata.outputs.labels }} - project: ${{ inputs.depot-project-id }} + project: ${{ inputs.depot-project-id }} \ No newline at end of file diff --git a/charts/spamoor-cronjobs/Chart.yaml b/charts/spamoor-cronjobs/Chart.yaml index 6617cfe..7ca69ac 100644 --- a/charts/spamoor-cronjobs/Chart.yaml +++ b/charts/spamoor-cronjobs/Chart.yaml @@ -4,3 +4,11 @@ description: A Helm chart for Kubernetes name: spamoor-cronjobs type: application version: 0.1.0 + +maintainers: + - name: bharath-123 + url: astria.org + - name: aajimal + url: astria.org + - name: joroshiba + url: astria.org From 51b6fbab531ed8cc15a5bcc57cbec4069e16cb1c Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:53:06 +0530 Subject: [PATCH 08/18] Fix typos --- charts/spamoor-cronjobs/.helmignore | 1 - charts/spamoor-cronjobs/Chart.yaml | 14 -- charts/spamoor-cronjobs/LICENSE | 201 ------------------ charts/spamoor-cronjobs/README.md | 135 ------------ .../spamoor-cronjobs/templates/_helpers.tpl | 55 ----- .../spamoor-cronjobs/templates/cronjob.yaml | 89 -------- .../templates/image-pull-secret.yaml | 13 -- .../templates/serviceaccount.yaml | 21 -- charts/spamoor-cronjobs/values.yaml | 34 --- 9 files changed, 563 deletions(-) delete mode 100644 charts/spamoor-cronjobs/.helmignore delete mode 100644 charts/spamoor-cronjobs/Chart.yaml delete mode 100644 charts/spamoor-cronjobs/LICENSE delete mode 100644 charts/spamoor-cronjobs/README.md delete mode 100644 charts/spamoor-cronjobs/templates/_helpers.tpl delete mode 100644 charts/spamoor-cronjobs/templates/cronjob.yaml delete mode 100644 charts/spamoor-cronjobs/templates/image-pull-secret.yaml delete mode 100644 charts/spamoor-cronjobs/templates/serviceaccount.yaml delete mode 100644 charts/spamoor-cronjobs/values.yaml diff --git a/charts/spamoor-cronjobs/.helmignore b/charts/spamoor-cronjobs/.helmignore deleted file mode 100644 index 4032ec6..0000000 --- a/charts/spamoor-cronjobs/.helmignore +++ /dev/null @@ -1 +0,0 @@ -.git/ \ No newline at end of file diff --git a/charts/spamoor-cronjobs/Chart.yaml b/charts/spamoor-cronjobs/Chart.yaml deleted file mode 100644 index 7ca69ac..0000000 --- a/charts/spamoor-cronjobs/Chart.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: v2 -appVersion: 0.1.0 -description: A Helm chart for Kubernetes -name: spamoor-cronjobs -type: application -version: 0.1.0 - -maintainers: - - name: bharath-123 - url: astria.org - - name: aajimal - url: astria.org - - name: joroshiba - url: astria.org diff --git a/charts/spamoor-cronjobs/LICENSE b/charts/spamoor-cronjobs/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/charts/spamoor-cronjobs/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/charts/spamoor-cronjobs/README.md b/charts/spamoor-cronjobs/README.md deleted file mode 100644 index 925be1b..0000000 --- a/charts/spamoor-cronjobs/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# spamoor-cronjobs -You can define an array of jobs in values.yaml helm will take care of creating all of the CronJobs. - -Credit: [helm-cronjobs](https://github.com/bambash/helm-cronjobs) used as scafolding for this chart. - -## Getting started - -`helm create -p ` - - ``` - helm create -p helm-cronjobs spamoor-cronjobs - ``` - -## For debugging -`helm template --dry-run --debug -name ` -``` -helm template --dry-run --debug -name cronjobs spamoor-cronjobs -``` - - -## Configuration - -Via `values.yaml` - -### Overview - -```yaml -jobs: - jobname-1: - # job definition - jobname-2: - # job definition - jobname-n: - # job definition -``` - -### Details - -```yaml -jobs: - ### REQUIRED ### - : - image: - repository: - tag: - imagePullPolicy: - schedule: "" - failedJobsHistoryLimit: - successfulJobsHistoryLimit: - concurrencyPolicy: - restartPolicy: - ### OPTIONAL ### - imagePullSecrets: - - username: - password: - email: - registry: - env: - - name: ENV_VAR - value: ENV_VALUE - envFrom: - - secretRef: - name: - - configMapRef: - name: - command: [""] - args: - - "" - - "" - resources: - limits: - cpu: - memory: - requests: - cpu: - memory: - serviceAccount: - name: - annotations: # Optional - my-annotation-1: - my-annotation-2: - nodeSelector: - key: - tolerations: - - effect: NoSchedule - operator: Exists - volumes: - - name: config-mount - configMap: - name: configmap-name - items: - - key: configuration.yml - path: configuration.yml - volumeMounts: - - name: config-mount - mountPath: /etc/config - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/e2e-az-name - operator: In - values: - - e2e-az1 - - e2e-az2 -``` - -## Examples -``` -$ helm install test-cron-job . -NAME: test-cron-job -LAST DEPLOYED: Tue Jun 4 12:27:32 2024 -NAMESPACE: spamoor-cronjobs -STATUS: deployed -REVISION: 1 -TEST SUITE: None - -RESOURCES: -==> v1/CronJob -NAME AGE -test-cronjob-curl 1s -``` -list cronjobs: -``` -$ kubectl get cronjob -NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE -test-cron-job-curl * * * * * False 1 5m23s 5m49s -``` -list jobs: -``` -$ kubectl get jobs -NAME DESIRED SUCCESSFUL AGE -test-cron-job-curl-28625488 0/1 6m6s 6m6s -``` diff --git a/charts/spamoor-cronjobs/templates/_helpers.tpl b/charts/spamoor-cronjobs/templates/_helpers.tpl deleted file mode 100644 index 9356ff5..0000000 --- a/charts/spamoor-cronjobs/templates/_helpers.tpl +++ /dev/null @@ -1,55 +0,0 @@ -{{/* vim: set filetype=mustache: */}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "cronjobs.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "cronjobs.labels" -}} -helm.sh/chart: {{ include "cronjobs.chart" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Expand the release name of the chart. -*/}} -{{- define "cronjobs.releaseName" -}} -{{- default .Release.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - - -{{/* -Create payload for any image pull secret. -One kube secret will be created containing all the auths -and will be shared by all the job pods requiring it. -*/}} -{{- define "cronjobs.imageSecrets" -}} - {{- $secrets := dict -}} - {{- range $jobname, $job := .Values.jobs -}} - {{- if hasKey $job "imagePullSecrets" -}} - {{- range $ips := $job.imagePullSecrets -}} - {{- $userInfo := dict "username" $ips.username "password" $ips.password "auth" (printf "%s:%s" $ips.username $ips.password | b64enc) -}} - {{- if hasKey $ips "email" -}} - {{ $_ := set $userInfo "email" $ips.email -}} - {{- end -}} - {{- $_ := set $secrets $ips.registry $userInfo -}} - {{- end -}} - {{- end -}} - {{- end -}} - {{- if gt (len $secrets) 0 -}} - {{- $auth := dict "auths" $secrets -}} - {{/* Emit secret content as base64 */}} - {{- print ($auth | toJson | b64enc) -}} - {{- else -}} - {{/* There are no secrets*/}} - {{- print "" -}} - {{- end -}} -{{- end -}} \ No newline at end of file diff --git a/charts/spamoor-cronjobs/templates/cronjob.yaml b/charts/spamoor-cronjobs/templates/cronjob.yaml deleted file mode 100644 index 71a6339..0000000 --- a/charts/spamoor-cronjobs/templates/cronjob.yaml +++ /dev/null @@ -1,89 +0,0 @@ -{{- range $jobname, $job := .Values.jobs }} ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: {{ include "cronjobs.releaseName" $ }}-{{ $jobname }} - namespace: {{ $.Chart.Name }} - labels: - {{- include "cronjobs.labels" $ | nindent 4 }} -spec: - concurrencyPolicy: {{ $job.concurrencyPolicy }} - failedJobsHistoryLimit: {{ $job.failedJobsHistoryLimit }} - jobTemplate: - spec: - template: - metadata: - labels: - app: {{ include "cronjobs.releaseName" $ }} - cron: {{ $jobname }} - spec: - {{- if hasKey $job "imagePullSecrets" }} - imagePullSecrets: - - name: {{ $.Release.Name }}-docker - {{- end }} - {{- if and (hasKey $job "serviceAccount") (hasKey $job.serviceAccount "name") }} - serviceAccountName: {{ $job.serviceAccount.name }} - {{- else }} - serviceAccountName: {{ $.Release.Name}}-{{ $jobname }} - {{- end }} - {{- if hasKey $job "securityContext" }} - {{- if $job.securityContext.runAsUser }} - securityContext: - runAsUser: {{ $job.securityContext.runAsUser }} - {{- if $job.securityContext.runAsGroup }} - runAsGroup: {{ $job.securityContext.runAsGroup }} - {{- end }} - {{- if $job.securityContext.fsGroup }} - fsGroup: {{ $job.securityContext.fsGroup }} - {{- end }} - {{- end }} - {{- end }} - containers: - - image: {{ $job.image.repository }}:{{ $job.image.tag }} - imagePullPolicy: {{ $job.image.imagePullPolicy }} - name: {{ $jobname }} - {{- with $job.env }} - env: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.envFrom }} - envFrom: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.command }} - command: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.args }} - args: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.resources }} - resources: -{{ toYaml . | indent 14 }} - {{- end }} - {{- with $job.volumeMounts }} - volumeMounts: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.nodeSelector }} - nodeSelector: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.affinity }} - affinity: -{{ toYaml . | indent 12 }} - {{- end }} - {{- with $job.tolerations }} - tolerations: -{{ toYaml . | indent 12 }} - {{- end }} - restartPolicy: {{ $job.restartPolicy }} - {{- with $job.volumes }} - volumes: -{{ toYaml . | indent 12 }} - {{- end }} - schedule: {{ $job.schedule | quote }} - successfulJobsHistoryLimit: {{ $job.successfulJobsHistoryLimit }} -{{- end }} diff --git a/charts/spamoor-cronjobs/templates/image-pull-secret.yaml b/charts/spamoor-cronjobs/templates/image-pull-secret.yaml deleted file mode 100644 index a7d984f..0000000 --- a/charts/spamoor-cronjobs/templates/image-pull-secret.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- $secret := (include "cronjobs.imageSecrets" .) -}} -{{- if gt (len $secret) 0 }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ .Release.Name }}-docker - namespace: {{ $.Chart.Name }} - labels: - {{- include "cronjobs.labels" . | nindent 4 }} -type: kubernetes.io/dockerconfigjson -data: - .dockerconfigjson: {{ $secret }} -{{- end -}} diff --git a/charts/spamoor-cronjobs/templates/serviceaccount.yaml b/charts/spamoor-cronjobs/templates/serviceaccount.yaml deleted file mode 100644 index 334ddad..0000000 --- a/charts/spamoor-cronjobs/templates/serviceaccount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -{{- range $jobname, $job := .Values.jobs }} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - {{- if and (hasKey $job "serviceAccount") (hasKey $job "serviceAccount.name") }} - name: {{ $job.serviceAccount.name }} - {{- else }} - name: {{ $.Release.Name}}-{{ $jobname }} - {{- end }} - namespace: {{ $.Chart.Name }} - labels: - {{- include "cronjobs.labels" $ | nindent 4 }} - cron: {{ $jobname }} - {{- if and (hasKey $job "serviceAccount") (hasKey $job "serviceAccount.annotations") }} - {{- with $job.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} - {{- end }} -{{- end }} diff --git a/charts/spamoor-cronjobs/values.yaml b/charts/spamoor-cronjobs/values.yaml deleted file mode 100644 index 723c688..0000000 --- a/charts/spamoor-cronjobs/values.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. -jobs: - curl: - securityContext: - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 2000 - image: - repository: spamooor - tag: latest - imagePullPolicy: Always - schedule: "*/10 * * * *" # run every 10mins - args: - - "spamooor" - - "--privkey 70bce70f9c770c8e79f999f86bd76dcab8e2ac0c349622e15c85b9a1a5bede9e" - - "--rpchost https://rpc-evm.dev.astria.org" - - "erctx" - - "--max-wallets 10" - - "--throughput 10" - - "--max-pending 10" - - "--count 50" - - "--timeout 60" - resources: - limits: - cpu: 50m - memory: 256Mi - requests: - cpu: 50m - memory: 256Mi - failedJobsHistoryLimit: 1 - successfulJobsHistoryLimit: 3 - concurrencyPolicy: Forbid - restartPolicy: Never From 051b711f2361ec3a4bee5576e3143eb30ffaf74b Mon Sep 17 00:00:00 2001 From: aajimal Date: Wed, 5 Jun 2024 23:42:41 -0700 Subject: [PATCH 09/18] Add argocd app --- argocd/app-spamooor-cronjobs.yaml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 argocd/app-spamooor-cronjobs.yaml diff --git a/argocd/app-spamooor-cronjobs.yaml b/argocd/app-spamooor-cronjobs.yaml new file mode 100644 index 0000000..43071e9 --- /dev/null +++ b/argocd/app-spamooor-cronjobs.yaml @@ -0,0 +1,16 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: spamooor-cronjobs +spec: + project: default + destination: + server: https://kubernetes.default.svc + namespace: spamooor-cronjobs + sources: + - repoURL: https://github.com/astriaorg/spamooor.git + targetRevision: helm-chart + path: charts/spamooor-cronjobs + helm: + valueFiles: + - values.yaml \ No newline at end of file From 667c08518c8556b403d80ab2caab15248190cf71 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:54:33 +0530 Subject: [PATCH 10/18] Add argocd appset --- argocd/app-spamooor-cronjobs.yaml | 16 ---------------- argocd/app/app-spamooor.yaml | 2 +- 2 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 argocd/app-spamooor-cronjobs.yaml diff --git a/argocd/app-spamooor-cronjobs.yaml b/argocd/app-spamooor-cronjobs.yaml deleted file mode 100644 index 43071e9..0000000 --- a/argocd/app-spamooor-cronjobs.yaml +++ /dev/null @@ -1,16 +0,0 @@ -apiVersion: argoproj.io/v1alpha1 -kind: Application -metadata: - name: spamooor-cronjobs -spec: - project: default - destination: - server: https://kubernetes.default.svc - namespace: spamooor-cronjobs - sources: - - repoURL: https://github.com/astriaorg/spamooor.git - targetRevision: helm-chart - path: charts/spamooor-cronjobs - helm: - valueFiles: - - values.yaml \ No newline at end of file diff --git a/argocd/app/app-spamooor.yaml b/argocd/app/app-spamooor.yaml index d9c4446..59ec6d4 100644 --- a/argocd/app/app-spamooor.yaml +++ b/argocd/app/app-spamooor.yaml @@ -35,4 +35,4 @@ spec: labels: argocd.argoproj.io/instance: spamooor annotations: - argocd.argoproj.io/tracking-id: spamooor/Namespace:spamooor-cronjobs + argocd.argoproj.io/tracking-id: spamooor/Namespace:spamooor-cronjobs \ No newline at end of file From 1dfdb4f47551a6ea3f1f2ccec0befb0d2ff15aa5 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:56:02 +0530 Subject: [PATCH 11/18] Add configs for 4 spamooor jobs (#16) * update values of 4 jobs * add initial set of timings * fix linting issues --- charts/spamooor-cronjobs/values.yaml | 42 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/charts/spamooor-cronjobs/values.yaml b/charts/spamooor-cronjobs/values.yaml index 514f456..d172cc8 100644 --- a/charts/spamooor-cronjobs/values.yaml +++ b/charts/spamooor-cronjobs/values.yaml @@ -77,7 +77,7 @@ jobs: successfulJobsHistoryLimit: 1 concurrencyPolicy: Forbid restartPolicy: Never - univ2txsjob: + gasburnertxsjob: securityContext: runAsUser: 1000 runAsGroup: 1000 @@ -86,23 +86,24 @@ jobs: repository: ghcr.io/astriaorg/spamooor tag: latest imagePullPolicy: Always - # run every 10mins - schedule: "*/25 * * * *" + schedule: "*/30 * * * *" command: ["/app/spamooor"] args: - "--privkey" - - "64b947d57a7e2633b109875ca71acf13fe8c11237b55616ef87d4a1b907133c8" + - "57b5fb1ad7f7e0d6e2a085ef7cc761c0576d23760d0bc0db7f1368bd14836e0e" - "--rpchost" - "https://rpc.evm.dusk-7.devnet.astria.org" # Alternatively: ..svc.cluster.local: - - "univ2tx" + - "gasburnertx" - "--max-wallets" - "10" - "--throughput" - - "100" + - "5" - "--max-pending" - - "100" + - "5" - "--count" - - "1000" + - "5" + - "--gas-units-to-burn" + - "5000000" - "--timeout" - "60" resources: @@ -116,33 +117,32 @@ jobs: successfulJobsHistoryLimit: 1 concurrencyPolicy: Forbid restartPolicy: Never - gasburnertxsjob: + univ2txsjob: securityContext: runAsUser: 1000 runAsGroup: 1000 fsGroup: 2000 image: repository: ghcr.io/astriaorg/spamooor - tag: latest + tag: pr-12 imagePullPolicy: Always - schedule: "*/30 * * * *" + # run every 10mins + schedule: "*/10 * * * *" command: ["/app/spamooor"] args: - "--privkey" - - "57b5fb1ad7f7e0d6e2a085ef7cc761c0576d23760d0bc0db7f1368bd14836e0e" + - "6468598bfbfe5214ef262c8631dc56cff239551cd19f04da3a215ba251832a50" - "--rpchost" - - "https://rpc.evm.dusk-7.devnet.astria.org" # Alternatively: ..svc.cluster.local: - - "gasburnertx" + - "https://rpc-evm.dev.astria.org" # Alternatively: ..svc.cluster.local: + - "univ2tx" - "--max-wallets" - "10" - "--throughput" - - "5" + - "100" - "--max-pending" - - "5" + - "100" - "--count" - - "5" - - "--gas-units-to-burn" - - "5000000" + - "1000" - "--timeout" - "60" resources: @@ -153,6 +153,6 @@ jobs: cpu: 50m memory: 256Mi failedJobsHistoryLimit: 1 - successfulJobsHistoryLimit: 1 + successfulJobsHistoryLimit: 3 concurrencyPolicy: Forbid - restartPolicy: Never + restartPolicy: Never \ No newline at end of file From 684812e5eaca0cf27d17b1132f4ab0f297c2bfce Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:56:28 +0530 Subject: [PATCH 12/18] Fix lints --- charts/spamooor-cronjobs/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/spamooor-cronjobs/values.yaml b/charts/spamooor-cronjobs/values.yaml index d172cc8..0f0ebdd 100644 --- a/charts/spamooor-cronjobs/values.yaml +++ b/charts/spamooor-cronjobs/values.yaml @@ -133,7 +133,7 @@ jobs: - "--privkey" - "6468598bfbfe5214ef262c8631dc56cff239551cd19f04da3a215ba251832a50" - "--rpchost" - - "https://rpc-evm.dev.astria.org" # Alternatively: ..svc.cluster.local: + - "https://rpc-evm.dev.astria.org" - "univ2tx" - "--max-wallets" - "10" From f299f03230d02cbcdbf1b58f6990c77b5c720015 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:57:14 +0530 Subject: [PATCH 13/18] update private keys --- charts/spamooor-cronjobs/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/spamooor-cronjobs/values.yaml b/charts/spamooor-cronjobs/values.yaml index 0f0ebdd..b4b7cd1 100644 --- a/charts/spamooor-cronjobs/values.yaml +++ b/charts/spamooor-cronjobs/values.yaml @@ -131,9 +131,9 @@ jobs: command: ["/app/spamooor"] args: - "--privkey" - - "6468598bfbfe5214ef262c8631dc56cff239551cd19f04da3a215ba251832a50" + - "64b947d57a7e2633b109875ca71acf13fe8c11237b55616ef87d4a1b907133c8" - "--rpchost" - - "https://rpc-evm.dev.astria.org" + - "https://rpc.evm.dusk-7.devnet.astria.org" # Alternatively: ..svc.cluster.local: - "univ2tx" - "--max-wallets" - "10" From 688cc373170efacbb4fa9ddc3b57e637c00abd3c Mon Sep 17 00:00:00 2001 From: Bharath Date: Thu, 6 Jun 2024 22:58:47 +0530 Subject: [PATCH 14/18] give jobs more time to complete --- charts/spamooor-cronjobs/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/spamooor-cronjobs/values.yaml b/charts/spamooor-cronjobs/values.yaml index b4b7cd1..dd72fdb 100644 --- a/charts/spamooor-cronjobs/values.yaml +++ b/charts/spamooor-cronjobs/values.yaml @@ -127,7 +127,7 @@ jobs: tag: pr-12 imagePullPolicy: Always # run every 10mins - schedule: "*/10 * * * *" + schedule: "*/25 * * * *" command: ["/app/spamooor"] args: - "--privkey" From 0e500b6b4a3a7755752d233518a9a824ca31869c Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:57:46 +0530 Subject: [PATCH 15/18] intensify spam --- charts/spamooor-cronjobs/values.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/charts/spamooor-cronjobs/values.yaml b/charts/spamooor-cronjobs/values.yaml index dd72fdb..4c627a1 100644 --- a/charts/spamooor-cronjobs/values.yaml +++ b/charts/spamooor-cronjobs/values.yaml @@ -25,7 +25,7 @@ jobs: - "--max-pending" - "100" - "--count" - - "1000" + - "10000" - "--timeout" - "60" resources: @@ -63,7 +63,7 @@ jobs: - "--max-pending" - "100" - "--count" - - "1000" + - "10000" - "--timeout" - "60" resources: @@ -101,7 +101,7 @@ jobs: - "--max-pending" - "5" - "--count" - - "5" + - "100" - "--gas-units-to-burn" - "5000000" - "--timeout" @@ -142,7 +142,7 @@ jobs: - "--max-pending" - "100" - "--count" - - "1000" + - "10000" - "--timeout" - "60" resources: From 6b1d134fe8e83d22af87c02c31363b607c37ed7b Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 20:58:02 +0530 Subject: [PATCH 16/18] update image tags --- charts/spamooor-cronjobs/values.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/spamooor-cronjobs/values.yaml b/charts/spamooor-cronjobs/values.yaml index 4c627a1..5a24598 100644 --- a/charts/spamooor-cronjobs/values.yaml +++ b/charts/spamooor-cronjobs/values.yaml @@ -124,7 +124,7 @@ jobs: fsGroup: 2000 image: repository: ghcr.io/astriaorg/spamooor - tag: pr-12 + tag: latest imagePullPolicy: Always # run every 10mins schedule: "*/25 * * * *" From 58712bc0ba9a67a52cde956b174db88da20465f0 Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 21:02:05 +0530 Subject: [PATCH 17/18] bump version --- charts/spamooor-cronjobs/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charts/spamooor-cronjobs/Chart.yaml b/charts/spamooor-cronjobs/Chart.yaml index 4211ea5..4390dc6 100644 --- a/charts/spamooor-cronjobs/Chart.yaml +++ b/charts/spamooor-cronjobs/Chart.yaml @@ -3,7 +3,7 @@ appVersion: 0.1.0 description: A Helm chart for Kubernetes name: spamooor-cronjobs type: application -version: 0.1.3 +version: 0.1.4 maintainers: - name: bharath-123 From 095bbe52ccfcffbf3ae30df454bd32cada75af1d Mon Sep 17 00:00:00 2001 From: Bharath Date: Fri, 7 Jun 2024 21:09:30 +0530 Subject: [PATCH 18/18] fix lint errors --- charts/spamooor-cronjobs/values.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/spamooor-cronjobs/values.yaml b/charts/spamooor-cronjobs/values.yaml index 5a24598..9fce617 100644 --- a/charts/spamooor-cronjobs/values.yaml +++ b/charts/spamooor-cronjobs/values.yaml @@ -133,7 +133,7 @@ jobs: - "--privkey" - "64b947d57a7e2633b109875ca71acf13fe8c11237b55616ef87d4a1b907133c8" - "--rpchost" - - "https://rpc.evm.dusk-7.devnet.astria.org" # Alternatively: ..svc.cluster.local: + - "https://rpc.evm.dusk-7.devnet.astria.org" # Alternatively: ..svc.cluster.local: - "univ2tx" - "--max-wallets" - "10" @@ -155,4 +155,4 @@ jobs: failedJobsHistoryLimit: 1 successfulJobsHistoryLimit: 3 concurrencyPolicy: Forbid - restartPolicy: Never \ No newline at end of file + restartPolicy: Never