From e2581866bcd6c5a24be19ff3e424a0e15a65af5d Mon Sep 17 00:00:00 2001 From: JenTing Hsiao Date: Fri, 9 Jul 2021 13:23:19 +0800 Subject: [PATCH] Support both v1beta1 and v1 CRDs for velero Signed-off-by: JenTing Hsiao --- .github/workflows/crds-verify-kind.yaml | 2 + .github/workflows/pr-codespell.yml | 2 +- Tiltfile | 22 +- changelogs/unreleased/3999-jenting | 1 + config/crd/v1/bases/velero.io_backups.yaml | 433 +++++ .../velero.io_backupstoragelocations.yaml | 178 ++ .../bases/velero.io_deletebackuprequests.yaml | 71 + .../v1/bases/velero.io_downloadrequests.yaml | 94 + .../v1/bases/velero.io_podvolumebackups.yaml | 161 ++ .../v1/bases/velero.io_podvolumerestores.yaml | 144 ++ .../bases/velero.io_resticrepositories.yaml | 89 + config/crd/v1/bases/velero.io_restores.yaml | 1699 +++++++++++++++++ config/crd/v1/bases/velero.io_schedules.yaml | 394 ++++ .../bases/velero.io_serverstatusrequests.yaml | 87 + .../velero.io_volumesnapshotlocations.yaml | 72 + config/crd/v1/crds/crds.go | 69 + config/crd/{ => v1}/crds/doc.go | 2 +- .../bases/velero.io_backups.yaml | 0 .../velero.io_backupstoragelocations.yaml | 0 .../bases/velero.io_deletebackuprequests.yaml | 0 .../bases/velero.io_downloadrequests.yaml | 0 .../bases/velero.io_podvolumebackups.yaml | 0 .../bases/velero.io_podvolumerestores.yaml | 0 .../bases/velero.io_resticrepositories.yaml | 0 .../bases/velero.io_restores.yaml | 0 .../bases/velero.io_schedules.yaml | 0 .../bases/velero.io_serverstatusrequests.yaml | 0 .../velero.io_volumesnapshotlocations.yaml | 0 config/crd/{ => v1beta1}/crds/crds.go | 0 config/crd/v1beta1/crds/doc.go | 4 + hack/crd-gen/v1/main.go | 136 ++ hack/crd-gen/{ => v1beta1}/main.go | 8 +- hack/restore-crd-patch-v1.json | 3 + ...ch.json => restore-crd-patch-v1beta1.json} | 0 hack/update-generated-crd-code.sh | 36 +- hack/verify-generated-crd-code.sh | 19 +- pkg/cmd/cli/install/install.go | 35 +- pkg/install/resources.go | 25 +- site/content/docs/main/development.md | 10 + site/content/docs/main/upgrade-to-1.6.md | 2 + 40 files changed, 3748 insertions(+), 50 deletions(-) create mode 100644 changelogs/unreleased/3999-jenting create mode 100644 config/crd/v1/bases/velero.io_backups.yaml create mode 100644 config/crd/v1/bases/velero.io_backupstoragelocations.yaml create mode 100644 config/crd/v1/bases/velero.io_deletebackuprequests.yaml create mode 100644 config/crd/v1/bases/velero.io_downloadrequests.yaml create mode 100644 config/crd/v1/bases/velero.io_podvolumebackups.yaml create mode 100644 config/crd/v1/bases/velero.io_podvolumerestores.yaml create mode 100644 config/crd/v1/bases/velero.io_resticrepositories.yaml create mode 100644 config/crd/v1/bases/velero.io_restores.yaml create mode 100644 config/crd/v1/bases/velero.io_schedules.yaml create mode 100644 config/crd/v1/bases/velero.io_serverstatusrequests.yaml create mode 100644 config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml create mode 100644 config/crd/v1/crds/crds.go rename config/crd/{ => v1}/crds/doc.go (58%) rename config/crd/{ => v1beta1}/bases/velero.io_backups.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_backupstoragelocations.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_deletebackuprequests.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_downloadrequests.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_podvolumebackups.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_podvolumerestores.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_resticrepositories.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_restores.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_schedules.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_serverstatusrequests.yaml (100%) rename config/crd/{ => v1beta1}/bases/velero.io_volumesnapshotlocations.yaml (100%) rename config/crd/{ => v1beta1}/crds/crds.go (100%) create mode 100644 config/crd/v1beta1/crds/doc.go create mode 100644 hack/crd-gen/v1/main.go rename hack/crd-gen/{ => v1beta1}/main.go (93%) create mode 100644 hack/restore-crd-patch-v1.json rename hack/{restore-crd-patch.json => restore-crd-patch-v1beta1.json} (100%) diff --git a/.github/workflows/crds-verify-kind.yaml b/.github/workflows/crds-verify-kind.yaml index 40e3baa9b..a12029fe0 100644 --- a/.github/workflows/crds-verify-kind.yaml +++ b/.github/workflows/crds-verify-kind.yaml @@ -58,6 +58,7 @@ jobs: - 1.18.15 - 1.19.7 - 1.20.2 + - 1.21.1 # All steps run in parallel unless otherwise specified. # See https://docs.github.com/en/actions/learn-github-actions/managing-complex-workflows#creating-dependent-jobs steps: @@ -75,6 +76,7 @@ jobs: velero-${{ github.event.pull_request.number }}- - uses: engineerd/setup-kind@v0.5.0 with: + version: "v0.11.1" image: "kindest/node:v${{ matrix.k8s }}" - name: Install CRDs run: | diff --git a/.github/workflows/pr-codespell.yml b/.github/workflows/pr-codespell.yml index 83dbf07f9..169535a07 100644 --- a/.github/workflows/pr-codespell.yml +++ b/.github/workflows/pr-codespell.yml @@ -14,7 +14,7 @@ jobs: uses: codespell-project/actions-codespell@master with: # ignore the config/.../crd.go file as it's generated binary data that is edited elswhere. - skip: .git,*.png,*.jpg,*.woff,*.ttf,*.gif,*.ico,./config/crd/crds/crds.go + skip: .git,*.png,*.jpg,*.woff,*.ttf,*.gif,*.ico,./config/crd/v1beta1/crds/crds.go,./config/crd/v1/crds/crds.go ignore_words_list: iam,aks,ist,bridget,ue check_filenames: true check_hidden: true diff --git a/Tiltfile b/Tiltfile index d9c30bd42..f951d2b5b 100644 --- a/Tiltfile +++ b/Tiltfile @@ -1,17 +1,17 @@ # -*- mode: Python -*- k8s_yaml([ - 'config/crd/bases/velero.io_backups.yaml', - 'config/crd/bases/velero.io_backupstoragelocations.yaml', - 'config/crd/bases/velero.io_deletebackuprequests.yaml', - 'config/crd/bases/velero.io_downloadrequests.yaml', - 'config/crd/bases/velero.io_podvolumebackups.yaml', - 'config/crd/bases/velero.io_podvolumerestores.yaml', - 'config/crd/bases/velero.io_resticrepositories.yaml', - 'config/crd/bases/velero.io_restores.yaml', - 'config/crd/bases/velero.io_schedules.yaml', - 'config/crd/bases/velero.io_serverstatusrequests.yaml', - 'config/crd/bases/velero.io_volumesnapshotlocations.yaml', + 'config/crd/v1/bases/velero.io_backups.yaml', + 'config/crd/v1/bases/velero.io_backupstoragelocations.yaml', + 'config/crd/v1/bases/velero.io_deletebackuprequests.yaml', + 'config/crd/v1/bases/velero.io_downloadrequests.yaml', + 'config/crd/v1/bases/velero.io_podvolumebackups.yaml', + 'config/crd/v1/bases/velero.io_podvolumerestores.yaml', + 'config/crd/v1/bases/velero.io_resticrepositories.yaml', + 'config/crd/v1/bases/velero.io_restores.yaml', + 'config/crd/v1/bases/velero.io_schedules.yaml', + 'config/crd/v1/bases/velero.io_serverstatusrequests.yaml', + 'config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml', ]) # default values diff --git a/changelogs/unreleased/3999-jenting b/changelogs/unreleased/3999-jenting new file mode 100644 index 000000000..a2479943c --- /dev/null +++ b/changelogs/unreleased/3999-jenting @@ -0,0 +1 @@ +Install Kubernetes preferred CRDs API version (v1beta1/v1). \ No newline at end of file diff --git a/config/crd/v1/bases/velero.io_backups.yaml b/config/crd/v1/bases/velero.io_backups.yaml new file mode 100644 index 000000000..f13d9fa62 --- /dev/null +++ b/config/crd/v1/bases/velero.io_backups.yaml @@ -0,0 +1,433 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: backups.velero.io +spec: + group: velero.io + names: + kind: Backup + listKind: BackupList + plural: backups + singular: backup + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Backup is a Velero resource that represents the capture of Kubernetes + cluster state at a point in time (API objects and associated volume state). + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackupSpec defines the specification for a Velero backup. + properties: + defaultVolumesToRestic: + description: DefaultVolumesToRestic specifies whether restic should + be used to take a backup of all pod volumes by default. + type: boolean + excludedNamespaces: + description: ExcludedNamespaces contains a list of namespaces that + are not included in the backup. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources is a slice of resource names that are + not included in the backup. + items: + type: string + nullable: true + type: array + hooks: + description: Hooks represent custom behaviors that should be executed + at different phases of the backup. + properties: + resources: + description: Resources are hooks that should be executed when + backing up individual instances of a resource. + items: + description: BackupResourceHookSpec defines one or more BackupResourceHooks + that should be executed based on the rules defined for namespaces, + resources, and label selector. + properties: + excludedNamespaces: + description: ExcludedNamespaces specifies the namespaces + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources specifies the resources to + which this hook spec does not apply. + items: + type: string + nullable: true + type: array + includedNamespaces: + description: IncludedNamespaces specifies the namespaces + to which this hook spec applies. If empty, it applies + to all namespaces. + items: + type: string + nullable: true + type: array + includedResources: + description: IncludedResources specifies the resources to + which this hook spec applies. If empty, it applies to + all resources. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector, if specified, filters the resources + to which this hook spec applies. + nullable: true + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + name: + description: Name is the name of this hook. + type: string + post: + description: PostHooks is a list of BackupResourceHooks + to execute after storing the item in the backup. These + are executed after all "additional items" from item actions + are processed. + items: + description: BackupResourceHook defines a hook for a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and arguments + to execute. + items: + type: string + minItems: 1 + type: array + container: + description: Container is the container in the + pod where the command should be executed. If + not specified, the pod's first container is + used. + type: string + onError: + description: OnError specifies how Velero should + behave if it encounters an error executing this + hook. + enum: + - Continue + - Fail + type: string + timeout: + description: Timeout defines the maximum amount + of time Velero should wait for the hook to complete + before considering the execution a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + pre: + description: PreHooks is a list of BackupResourceHooks to + execute prior to storing the item in the backup. These + are executed before any "additional items" from item actions + are processed. + items: + description: BackupResourceHook defines a hook for a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and arguments + to execute. + items: + type: string + minItems: 1 + type: array + container: + description: Container is the container in the + pod where the command should be executed. If + not specified, the pod's first container is + used. + type: string + onError: + description: OnError specifies how Velero should + behave if it encounters an error executing this + hook. + enum: + - Continue + - Fail + type: string + timeout: + description: Timeout defines the maximum amount + of time Velero should wait for the hook to complete + before considering the execution a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + required: + - name + type: object + nullable: true + type: array + type: object + includeClusterResources: + description: IncludeClusterResources specifies whether cluster-scoped + resources should be included for consideration in the backup. + nullable: true + type: boolean + includedNamespaces: + description: IncludedNamespaces is a slice of namespace names to include + objects from. If empty, all namespaces are included. + items: + type: string + nullable: true + type: array + includedResources: + description: IncludedResources is a slice of resource names to include + in the backup. If empty, all resources are included. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector is a metav1.LabelSelector to filter with + when adding individual objects to the backup. If empty or nil, all + objects are included. Optional. + nullable: true + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + orderedResources: + additionalProperties: + type: string + description: OrderedResources specifies the backup order of resources + of specific Kind. The map key is the Kind name and value is a list + of resource names separated by commas. Each resource name has format + "namespace/resourcename". For cluster resources, simply use "resourcename". + nullable: true + type: object + snapshotVolumes: + description: SnapshotVolumes specifies whether to take cloud snapshots + of any PV's referenced in the set of objects included in the Backup. + nullable: true + type: boolean + storageLocation: + description: StorageLocation is a string containing the name of a + BackupStorageLocation where the backup should be stored. + type: string + ttl: + description: TTL is a time.Duration-parseable string describing how + long the Backup should be retained for. + type: string + volumeSnapshotLocations: + description: VolumeSnapshotLocations is a list containing names of + VolumeSnapshotLocations associated with this backup. + items: + type: string + type: array + type: object + status: + description: BackupStatus captures the current status of a Velero backup. + properties: + completionTimestamp: + description: CompletionTimestamp records the time a backup was completed. + Completion time is recorded even on failed backups. Completion time + is recorded before uploading the backup object. The server's time + is used for CompletionTimestamps + format: date-time + nullable: true + type: string + errors: + description: Errors is a count of all error messages that were generated + during execution of the backup. The actual errors are in the backup's + log file in object storage. + type: integer + expiration: + description: Expiration is when this Backup is eligible for garbage-collection. + format: date-time + nullable: true + type: string + formatVersion: + description: FormatVersion is the backup format version, including + major, minor, and patch version. + type: string + phase: + description: Phase is the current state of the Backup. + enum: + - New + - FailedValidation + - InProgress + - Completed + - PartiallyFailed + - Failed + - Deleting + type: string + progress: + description: Progress contains information about the backup's execution + progress. Note that this information is best-effort only -- if Velero + fails to update it during a backup for any reason, it may be inaccurate/stale. + nullable: true + properties: + itemsBackedUp: + description: ItemsBackedUp is the number of items that have actually + been written to the backup tarball so far. + type: integer + totalItems: + description: TotalItems is the total number of items to be backed + up. This number may change throughout the execution of the backup + due to plugins that return additional related items to back + up, the velero.io/exclude-from-backup label, and various other + filters that happen as items are processed. + type: integer + type: object + startTimestamp: + description: StartTimestamp records the time a backup was started. + Separate from CreationTimestamp, since that value changes on restores. + The server's time is used for StartTimestamps + format: date-time + nullable: true + type: string + validationErrors: + description: ValidationErrors is a slice of all validation errors + (if applicable). + items: + type: string + nullable: true + type: array + version: + description: 'Version is the backup format major version. Deprecated: + Please see FormatVersion' + type: integer + volumeSnapshotsAttempted: + description: VolumeSnapshotsAttempted is the total number of attempted + volume snapshots for this backup. + type: integer + volumeSnapshotsCompleted: + description: VolumeSnapshotsCompleted is the total number of successfully + completed volume snapshots for this backup. + type: integer + warnings: + description: Warnings is a count of all warning messages that were + generated during execution of the backup. The actual warnings are + in the backup's log file in object storage. + type: integer + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_backupstoragelocations.yaml b/config/crd/v1/bases/velero.io_backupstoragelocations.yaml new file mode 100644 index 000000000..bdef97594 --- /dev/null +++ b/config/crd/v1/bases/velero.io_backupstoragelocations.yaml @@ -0,0 +1,178 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: backupstoragelocations.velero.io +spec: + group: velero.io + names: + kind: BackupStorageLocation + listKind: BackupStorageLocationList + plural: backupstoragelocations + shortNames: + - bsl + singular: backupstoragelocation + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Backup Storage Location status such as Available/Unavailable + jsonPath: .status.phase + name: Phase + type: string + - description: LastValidationTime is the last time the backup store location was + validated + jsonPath: .status.lastValidationTime + name: Last Validated + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Default backup storage location + jsonPath: .spec.default + name: Default + type: boolean + name: v1 + schema: + openAPIV3Schema: + description: BackupStorageLocation is a location where Velero stores backup + objects + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BackupStorageLocationSpec defines the desired state of a + Velero BackupStorageLocation + properties: + accessMode: + description: AccessMode defines the permissions for the backup storage + location. + enum: + - ReadOnly + - ReadWrite + type: string + backupSyncPeriod: + description: BackupSyncPeriod defines how frequently to sync backup + API objects from object storage. A value of 0 disables sync. + nullable: true + type: string + config: + additionalProperties: + type: string + description: Config is for provider-specific configuration fields. + type: object + credential: + description: Credential contains the credential information intended + to be used with this location + properties: + key: + description: The key of the secret to select from. Must be a + valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + required: + - key + type: object + default: + description: Default indicates this location is the default backup + storage location. + type: boolean + objectStorage: + description: ObjectStorageLocation specifies the settings necessary + to connect to a provider's object storage. + properties: + bucket: + description: Bucket is the bucket to use for object storage. + type: string + caCert: + description: CACert defines a CA bundle to use when verifying + TLS connections to the provider. + format: byte + type: string + prefix: + description: Prefix is the path inside a bucket to use for Velero + storage. Optional. + type: string + required: + - bucket + type: object + provider: + description: Provider is the provider of the backup storage. + type: string + validationFrequency: + description: ValidationFrequency defines how frequently to validate + the corresponding object storage. A value of 0 disables validation. + nullable: true + type: string + required: + - objectStorage + - provider + type: object + status: + description: BackupStorageLocationStatus defines the observed state of + BackupStorageLocation + properties: + accessMode: + description: "AccessMode is an unused field. \n Deprecated: there + is now an AccessMode field on the Spec and this field will be removed + entirely as of v2.0." + enum: + - ReadOnly + - ReadWrite + type: string + lastSyncedRevision: + description: "LastSyncedRevision is the value of the `metadata/revision` + file in the backup storage location the last time the BSL's contents + were synced into the cluster. \n Deprecated: this field is no longer + updated or used for detecting changes to the location's contents + and will be removed entirely in v2.0." + type: string + lastSyncedTime: + description: LastSyncedTime is the last time the contents of the location + were synced into the cluster. + format: date-time + nullable: true + type: string + lastValidationTime: + description: LastValidationTime is the last time the backup store + location was validated the cluster. + format: date-time + nullable: true + type: string + phase: + description: Phase is the current state of the BackupStorageLocation. + enum: + - Available + - Unavailable + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_deletebackuprequests.yaml b/config/crd/v1/bases/velero.io_deletebackuprequests.yaml new file mode 100644 index 000000000..d267d7310 --- /dev/null +++ b/config/crd/v1/bases/velero.io_deletebackuprequests.yaml @@ -0,0 +1,71 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: deletebackuprequests.velero.io +spec: + group: velero.io + names: + kind: DeleteBackupRequest + listKind: DeleteBackupRequestList + plural: deletebackuprequests + singular: deletebackuprequest + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: DeleteBackupRequest is a request to delete one or more backups. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DeleteBackupRequestSpec is the specification for which backups + to delete. + properties: + backupName: + type: string + required: + - backupName + type: object + status: + description: DeleteBackupRequestStatus is the current status of a DeleteBackupRequest. + properties: + errors: + description: Errors contains any errors that were encountered during + the deletion process. + items: + type: string + nullable: true + type: array + phase: + description: Phase is the current state of the DeleteBackupRequest. + enum: + - New + - InProgress + - Processed + type: string + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_downloadrequests.yaml b/config/crd/v1/bases/velero.io_downloadrequests.yaml new file mode 100644 index 000000000..ed98240fd --- /dev/null +++ b/config/crd/v1/bases/velero.io_downloadrequests.yaml @@ -0,0 +1,94 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: downloadrequests.velero.io +spec: + group: velero.io + names: + kind: DownloadRequest + listKind: DownloadRequestList + plural: downloadrequests + singular: downloadrequest + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: DownloadRequest is a request to download an artifact from backup + object storage, such as a backup log file. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: DownloadRequestSpec is the specification for a download request. + properties: + target: + description: Target is what to download (e.g. logs for a backup). + properties: + kind: + description: Kind is the type of file to download. + enum: + - BackupLog + - BackupContents + - BackupVolumeSnapshots + - BackupResourceList + - RestoreLog + - RestoreResults + type: string + name: + description: Name is the name of the kubernetes resource with + which the file is associated. + type: string + required: + - kind + - name + type: object + required: + - target + type: object + status: + description: DownloadRequestStatus is the current status of a DownloadRequest. + properties: + downloadURL: + description: DownloadURL contains the pre-signed URL for the target + file. + type: string + expiration: + description: Expiration is when this DownloadRequest expires and can + be deleted by the system. + format: date-time + nullable: true + type: string + phase: + description: Phase is the current state of the DownloadRequest. + enum: + - New + - Processed + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_podvolumebackups.yaml b/config/crd/v1/bases/velero.io_podvolumebackups.yaml new file mode 100644 index 000000000..1e318061b --- /dev/null +++ b/config/crd/v1/bases/velero.io_podvolumebackups.yaml @@ -0,0 +1,161 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: podvolumebackups.velero.io +spec: + group: velero.io + names: + kind: PodVolumeBackup + listKind: PodVolumeBackupList + plural: podvolumebackups + singular: podvolumebackup + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodVolumeBackupSpec is the specification for a PodVolumeBackup. + properties: + backupStorageLocation: + description: BackupStorageLocation is the name of the backup storage + location where the restic repository is stored. + type: string + node: + description: Node is the name of the node that the Pod is running + on. + type: string + pod: + description: Pod is a reference to the pod containing the volume to + be backed up. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + repoIdentifier: + description: RepoIdentifier is the restic repository identifier. + type: string + tags: + additionalProperties: + type: string + description: Tags are a map of key-value pairs that should be applied + to the volume backup as tags. + type: object + volume: + description: Volume is the name of the volume within the Pod to be + backed up. + type: string + required: + - backupStorageLocation + - node + - pod + - repoIdentifier + - volume + type: object + status: + description: PodVolumeBackupStatus is the current status of a PodVolumeBackup. + properties: + completionTimestamp: + description: CompletionTimestamp records the time a backup was completed. + Completion time is recorded even on failed backups. Completion time + is recorded before uploading the backup object. The server's time + is used for CompletionTimestamps + format: date-time + nullable: true + type: string + message: + description: Message is a message about the pod volume backup's status. + type: string + path: + description: Path is the full path within the controller pod being + backed up. + type: string + phase: + description: Phase is the current state of the PodVolumeBackup. + enum: + - New + - InProgress + - Completed + - Failed + type: string + progress: + description: Progress holds the total number of bytes of the volume + and the current number of backed up bytes. This can be used to display + progress information about the backup operation. + properties: + bytesDone: + format: int64 + type: integer + totalBytes: + format: int64 + type: integer + type: object + snapshotID: + description: SnapshotID is the identifier for the snapshot of the + pod volume. + type: string + startTimestamp: + description: StartTimestamp records the time a backup was started. + Separate from CreationTimestamp, since that value changes on restores. + The server's time is used for StartTimestamps + format: date-time + nullable: true + type: string + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_podvolumerestores.yaml b/config/crd/v1/bases/velero.io_podvolumerestores.yaml new file mode 100644 index 000000000..444c1fc98 --- /dev/null +++ b/config/crd/v1/bases/velero.io_podvolumerestores.yaml @@ -0,0 +1,144 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: podvolumerestores.velero.io +spec: + group: velero.io + names: + kind: PodVolumeRestore + listKind: PodVolumeRestoreList + plural: podvolumerestores + singular: podvolumerestore + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: PodVolumeRestoreSpec is the specification for a PodVolumeRestore. + properties: + backupStorageLocation: + description: BackupStorageLocation is the name of the backup storage + location where the restic repository is stored. + type: string + pod: + description: Pod is a reference to the pod containing the volume to + be restored. + properties: + apiVersion: + description: API version of the referent. + type: string + fieldPath: + description: 'If referring to a piece of an object instead of + an entire object, this string should contain a valid JSON/Go + field access statement, such as desiredState.manifest.containers[2]. + For example, if the object reference is to a container within + a pod, this would take on a value like: "spec.containers{name}" + (where "name" refers to the name of the container that triggered + the event) or if no container name is specified "spec.containers[2]" + (container with index 2 in this pod). This syntax is chosen + only to have some well-defined way of referencing a part of + an object. TODO: this design is not final and this field is + subject to change in the future.' + type: string + kind: + description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + namespace: + description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' + type: string + resourceVersion: + description: 'Specific resourceVersion to which this reference + is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' + type: string + uid: + description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + type: string + type: object + repoIdentifier: + description: RepoIdentifier is the restic repository identifier. + type: string + snapshotID: + description: SnapshotID is the ID of the volume snapshot to be restored. + type: string + volume: + description: Volume is the name of the volume within the Pod to be + restored. + type: string + required: + - backupStorageLocation + - pod + - repoIdentifier + - snapshotID + - volume + type: object + status: + description: PodVolumeRestoreStatus is the current status of a PodVolumeRestore. + properties: + completionTimestamp: + description: CompletionTimestamp records the time a restore was completed. + Completion time is recorded even on failed restores. The server's + time is used for CompletionTimestamps + format: date-time + nullable: true + type: string + message: + description: Message is a message about the pod volume restore's status. + type: string + phase: + description: Phase is the current state of the PodVolumeRestore. + enum: + - New + - InProgress + - Completed + - Failed + type: string + progress: + description: Progress holds the total number of bytes of the snapshot + and the current number of restored bytes. This can be used to display + progress information about the restore operation. + properties: + bytesDone: + format: int64 + type: integer + totalBytes: + format: int64 + type: integer + type: object + startTimestamp: + description: StartTimestamp records the time a restore was started. + The server's time is used for StartTimestamps + format: date-time + nullable: true + type: string + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_resticrepositories.yaml b/config/crd/v1/bases/velero.io_resticrepositories.yaml new file mode 100644 index 000000000..4a67f1ee8 --- /dev/null +++ b/config/crd/v1/bases/velero.io_resticrepositories.yaml @@ -0,0 +1,89 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: resticrepositories.velero.io +spec: + group: velero.io + names: + kind: ResticRepository + listKind: ResticRepositoryList + plural: resticrepositories + singular: resticrepository + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ResticRepositorySpec is the specification for a ResticRepository. + properties: + backupStorageLocation: + description: BackupStorageLocation is the name of the BackupStorageLocation + that should contain this repository. + type: string + maintenanceFrequency: + description: MaintenanceFrequency is how often maintenance should + be run. + type: string + resticIdentifier: + description: ResticIdentifier is the full restic-compatible string + for identifying this repository. + type: string + volumeNamespace: + description: VolumeNamespace is the namespace this restic repository + contains pod volume backups for. + type: string + required: + - backupStorageLocation + - maintenanceFrequency + - resticIdentifier + - volumeNamespace + type: object + status: + description: ResticRepositoryStatus is the current status of a ResticRepository. + properties: + lastMaintenanceTime: + description: LastMaintenanceTime is the last time maintenance was + run. + format: date-time + nullable: true + type: string + message: + description: Message is a message about the current status of the + ResticRepository. + type: string + phase: + description: Phase is the current state of the ResticRepository. + enum: + - New + - Ready + - NotReady + type: string + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_restores.yaml b/config/crd/v1/bases/velero.io_restores.yaml new file mode 100644 index 000000000..9d32537da --- /dev/null +++ b/config/crd/v1/bases/velero.io_restores.yaml @@ -0,0 +1,1699 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: restores.velero.io +spec: + group: velero.io + names: + kind: Restore + listKind: RestoreList + plural: restores + singular: restore + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Restore is a Velero resource that represents the application + of resources from a Velero backup to a target Kubernetes cluster. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: RestoreSpec defines the specification for a Velero restore. + properties: + backupName: + description: BackupName is the unique name of the Velero backup to + restore from. + type: string + excludedNamespaces: + description: ExcludedNamespaces contains a list of namespaces that + are not included in the restore. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources is a slice of resource names that are + not included in the restore. + items: + type: string + nullable: true + type: array + hooks: + description: Hooks represent custom behaviors that should be executed + during or post restore. + properties: + resources: + items: + description: RestoreResourceHookSpec defines one or more RestoreResrouceHooks + that should be executed based on the rules defined for namespaces, + resources, and label selector. + properties: + excludedNamespaces: + description: ExcludedNamespaces specifies the namespaces + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources specifies the resources to + which this hook spec does not apply. + items: + type: string + nullable: true + type: array + includedNamespaces: + description: IncludedNamespaces specifies the namespaces + to which this hook spec applies. If empty, it applies + to all namespaces. + items: + type: string + nullable: true + type: array + includedResources: + description: IncludedResources specifies the resources to + which this hook spec applies. If empty, it applies to + all resources. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector, if specified, filters the resources + to which this hook spec applies. + nullable: true + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, + NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists + or DoesNotExist, the values array must be empty. + This array is replaced during a strategic merge + patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field + is "key", the operator is "In", and the values array + contains only "value". The requirements are ANDed. + type: object + type: object + name: + description: Name is the name of this hook. + type: string + postHooks: + description: PostHooks is a list of RestoreResourceHooks + to execute during and after restoring a resource. + items: + description: RestoreResourceHook defines a restore hook + for a resource. + properties: + exec: + description: Exec defines an exec restore hook. + properties: + command: + description: Command is the command and arguments + to execute from within a container after a pod + has been restored. + items: + type: string + minItems: 1 + type: array + container: + description: Container is the container in the + pod where the command should be executed. If + not specified, the pod's first container is + used. + type: string + execTimeout: + description: ExecTimeout defines the maximum amount + of time Velero should wait for the hook to complete + before considering the execution a failure. + type: string + onError: + description: OnError specifies how Velero should + behave if it encounters an error executing this + hook. + enum: + - Continue + - Fail + type: string + waitTimeout: + description: WaitTimeout defines the maximum amount + of time Velero should wait for the container + to be Ready before attempting to run the command. + type: string + required: + - command + type: object + init: + description: Init defines an init restore hook. + properties: + initContainers: + description: InitContainers is list of init containers + to be added to a pod during its restore. + items: + description: A single application container + that you want to run within a pod. + properties: + args: + description: 'Arguments to the entrypoint. + The docker image''s CMD is used if this + is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. + If a variable cannot be resolved, the + reference in the input string will be + unchanged. The $(VAR_NAME) syntax can + be escaped with a double $$, ie: $$(VAR_NAME). + Escaped references will never be expanded, + regardless of whether the variable exists + or not. Cannot be updated. More info: + https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed + within a shell. The docker image''s ENTRYPOINT + is used if this is not provided. Variable + references $(VAR_NAME) are expanded using + the container''s environment. If a variable + cannot be resolved, the reference in the + input string will be unchanged. The $(VAR_NAME) + syntax can be escaped with a double $$, + ie: $$(VAR_NAME). Escaped references will + never be expanded, regardless of whether + the variable exists or not. Cannot be + updated. More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell' + items: + type: string + type: array + env: + description: List of environment variables + to set in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment + variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references + $(VAR_NAME) are expanded using the + previous defined environment variables + in the container and any service + environment variables. If a variable + cannot be resolved, the reference + in the input string will be unchanged. + The $(VAR_NAME) syntax can be escaped + with a double $$, ie: $$(VAR_NAME). + Escaped references will never be + expanded, regardless of whether + the variable exists or not. Defaults + to "".' + type: string + valueFrom: + description: Source for the environment + variable's value. Cannot be used + if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of + a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the + referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether + the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field + of the pod: supports metadata.name, + metadata.namespace, `metadata.labels['''']`, + `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, + status.podIPs.' + properties: + apiVersion: + description: Version of the + schema the FieldPath is + written in terms of, defaults + to "v1". + type: string + fieldPath: + description: Path of the field + to select in the specified + API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, limits.ephemeral-storage, + requests.cpu, requests.memory + and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: + required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the + output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of + a secret in the pod's namespace + properties: + key: + description: The key of the + secret to select from. Must + be a valid secret key. + type: string + name: + description: 'Name of the + referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether + the Secret or its key must + be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate + environment variables in the container. + The keys defined within a source must + be a C_IDENTIFIER. All invalid keys will + be reported as an event when the container + is starting. When a key exists in multiple + sources, the value associated with the + last source will take precedence. Values + defined by an Env with a duplicate key + will take precedence. Cannot be updated. + items: + description: EnvFromSource represents + the source of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select + from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + ConfigMap must be defined + type: boolean + type: object + prefix: + description: An optional identifier + to prepend to each key in the ConfigMap. + Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select + from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + Secret must be defined + type: boolean + type: object + type: object + type: array + image: + description: 'Docker image name. More info: + https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher + level config management to default or + override container images in workload + controllers like Deployments and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of + Always, Never, IfNotPresent. Defaults + to Always if :latest tag is specified, + or IfNotPresent otherwise. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management + system should take in response to container + lifecycle events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the + handler fails, the container is terminated + and restarted according to its restart + policy. Other management of the container + blocks until the hook completes. More + info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: One and only one of + the following should be specified. + Exec specifies the action to take. + properties: + command: + description: Command is the + command line to execute inside + the container, the working + directory for the command is + root ('/') in the container's + filesystem. The command is + simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, + you need to explicitly call + out to that shell. Exit status + of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the + http request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. + You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers + to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes + a custom header to be used + in HTTP probes + properties: + name: + description: The header + field name + type: string + value: + description: The header + field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access + on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number + of the port to access on the + container. Number must be + in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for + connecting to the host. Defaults + to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: 'TCPSocket specifies + an action involving a TCP port. + TCP hooks not yet supported TODO: + implement a realistic TCP lifecycle + hook' + properties: + host: + description: 'Optional: Host + name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name + of the port to access on the + container. Number must be + in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: 'PreStop is called immediately + before a container is terminated due + to an API request or management event + such as liveness/startup probe failure, + preemption, resource contention, etc. + The handler is not called if the container + crashes or exits. The reason for termination + is passed to the handler. The Pod''s + termination grace period countdown + begins before the PreStop hooked is + executed. Regardless of the outcome + of the handler, the container will + eventually terminate within the Pod''s + termination grace period. Other management + of the container blocks until the + hook completes or until the termination + grace period is reached. More info: + https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: One and only one of + the following should be specified. + Exec specifies the action to take. + properties: + command: + description: Command is the + command line to execute inside + the container, the working + directory for the command is + root ('/') in the container's + filesystem. The command is + simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, + you need to explicitly call + out to that shell. Exit status + of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the + http request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. + You probably want to set "Host" + in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers + to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes + a custom header to be used + in HTTP probes + properties: + name: + description: The header + field name + type: string + value: + description: The header + field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access + on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number + of the port to access on the + container. Number must be + in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for + connecting to the host. Defaults + to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: 'TCPSocket specifies + an action involving a TCP port. + TCP hooks not yet supported TODO: + implement a realistic TCP lifecycle + hook' + properties: + host: + description: 'Optional: Host + name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name + of the port to access on the + container. Number must be + in the range 1 to 65535. Name + must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container + liveness. Container will be restarted + if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: One and only one of the + following should be specified. Exec + specifies the action to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to + 3. Minimum value is 1. + format: int32 + type: integer + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after + the container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) + to perform the probe. Default to 10 + seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. + Must be 1 for liveness and startup. + Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: 'TCPSocket specifies an + action involving a TCP port. TCP hooks + not yet supported TODO: implement + a realistic TCP lifecycle hook' + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + description: 'Number of seconds after + which the probe times out. Defaults + to 1 second. Minimum value is 1. More + info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified + as a DNS_LABEL. Each container in a pod + must have a unique name (DNS_LABEL). Cannot + be updated. + type: string + ports: + description: List of ports to expose from + the container. Exposing a port here gives + the system additional information about + the network connections a container uses, + but is primarily informational. Not specifying + a port here DOES NOT prevent that port + from being exposed. Any port which is + listening on the default "0.0.0.0" address + inside a container will be accessible + from the network. Cannot be updated. + items: + description: ContainerPort represents + a network port in a single container. + properties: + containerPort: + description: Number of port to expose + on the pod's IP address. This must + be a valid port number, 0 < x < + 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind + the external port to. + type: string + hostPort: + description: Number of port to expose + on the host. If specified, this + must be a valid port number, 0 < + x < 65536. If HostNetwork is specified, + this must match ContainerPort. Most + containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must + be an IANA_SVC_NAME and unique within + the pod. Each named port in a pod + must have a unique name. Name for + the port that can be referred to + by services. + type: string + protocol: + description: Protocol for port. Must + be UDP, TCP, or SCTP. Defaults to + "TCP". + type: string + required: + - containerPort + - protocol + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container + service readiness. Container will be removed + from service endpoints if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: One and only one of the + following should be specified. Exec + specifies the action to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to + 3. Minimum value is 1. + format: int32 + type: integer + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after + the container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) + to perform the probe. Default to 10 + seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. + Must be 1 for liveness and startup. + Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: 'TCPSocket specifies an + action involving a TCP port. TCP hooks + not yet supported TODO: implement + a realistic TCP lifecycle hook' + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + description: 'Number of seconds after + which the probe times out. Defaults + to 1 second. Minimum value is 1. More + info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resources: + description: 'Compute Resources required + by this container. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the + minimum amount of compute resources + required. If Requests is omitted for + a container, it defaults to Limits + if that is explicitly specified, otherwise + to an implementation-defined value. + More info: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' + type: object + type: object + securityContext: + description: 'Security options the pod should + run with. More info: https://kubernetes.io/docs/concepts/policy/security-context/ + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation + controls whether a process can gain + more privileges than its parent process. + This bool directly controls if the + no_new_privs flag will be set on the + container process. AllowPrivilegeEscalation + is true always when the container + is: 1) run as Privileged 2) has CAP_SYS_ADMIN' + type: boolean + capabilities: + description: The capabilities to add/drop + when running containers. Defaults + to the default set of capabilities + granted by the container runtime. + properties: + add: + description: Added capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent + POSIX capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged + mode. Processes in privileged containers + are essentially equivalent to root + on the host. Defaults to false. + type: boolean + procMount: + description: procMount denotes the type + of proc mount to use for the containers. + The default is DefaultProcMount which + uses the container runtime defaults + for readonly paths and masked paths. + This requires the ProcMountType feature + flag to be enabled. + type: string + readOnlyRootFilesystem: + description: Whether this container + has a read-only root filesystem. Default + is false. + type: boolean + runAsGroup: + description: The GID to run the entrypoint + of the container process. Uses runtime + default if unset. May also be set + in PodSecurityContext. If set in + both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container + must run as a non-root user. If true, + the Kubelet will validate the image + at runtime to ensure that it does + not run as UID 0 (root) and fail to + start the container if it does. If + unset or false, no such validation + will be performed. May also be set + in PodSecurityContext. If set in + both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: boolean + runAsUser: + description: The UID to run the entrypoint + of the container process. Defaults + to user specified in image metadata + if unspecified. May also be set in + PodSecurityContext. If set in both + SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to + be applied to the container. If unspecified, + the container runtime will allocate + a random SELinux context for each + container. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + properties: + level: + description: Level is SELinux level + label that applies to the container. + type: string + role: + description: Role is a SELinux role + label that applies to the container. + type: string + type: + description: Type is a SELinux type + label that applies to the container. + type: string + user: + description: User is a SELinux user + label that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to + use by this container. If seccomp + options are provided at both the pod + & container level, the container options + override the pod options. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on + the node should be used. The profile + must be preconfigured on the node + to work. Must be a descending + path, relative to the kubelet's + configured seccomp profile location. + Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which + kind of seccomp profile will be + applied. Valid options are: \n + Localhost - a profile defined + in a file on the node should be + used. RuntimeDefault - the container + runtime default profile should + be used. Unconfined - no profile + should be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings + applied to all containers. If unspecified, + the options from the PodSecurityContext + will be used. If set in both SecurityContext + and PodSecurityContext, the value + specified in SecurityContext takes + precedence. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec + is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA + credential spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName + is the name of the GMSA credential + spec to use. + type: string + runAsUserName: + description: The UserName in Windows + to run the entrypoint of the container + process. Defaults to the user + specified in image metadata if + unspecified. May also be set in + PodSecurityContext. If set in + both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: 'StartupProbe indicates that + the Pod has successfully initialized. + If specified, no other probes are executed + until this completes successfully. If + this probe fails, the Pod will be restarted, + just as if the livenessProbe failed. This + can be used to provide different probe + parameters at the beginning of a Pod''s + lifecycle, when it might take a long time + to load data or warm a cache, than during + steady-state operation. This cannot be + updated. This is a beta feature enabled + by the StartupProbe feature flag. More + info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: One and only one of the + following should be specified. Exec + specifies the action to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the + command is root ('/') in the + container's filesystem. The command + is simply exec'd, it is not run + inside a shell, so traditional + shell instructions ('|', etc) + won't work. To use a shell, you + need to explicitly call out to + that shell. Exit status of 0 is + treated as live/healthy and non-zero + is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed + after having succeeded. Defaults to + 3. Minimum value is 1. + format: int32 + type: integer + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in + httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after + the container has started before liveness + probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) + to perform the probe. Default to 10 + seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. + Must be 1 for liveness and startup. + Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: 'TCPSocket specifies an + action involving a TCP port. TCP hooks + not yet supported TODO: implement + a realistic TCP lifecycle hook' + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the + pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 + to 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + timeoutSeconds: + description: 'Number of seconds after + which the probe times out. Defaults + to 1 second. Minimum value is 1. More + info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should + allocate a buffer for stdin in the container + runtime. If this is not set, reads from + stdin in the container will always result + in EOF. Default is false. + type: boolean + stdinOnce: + description: Whether the container runtime + should close the stdin channel after it + has been opened by a single attach. When + stdin is true the stdin stream will remain + open across multiple attach sessions. + If stdinOnce is set to true, stdin is + opened on container start, is empty until + the first client attaches to stdin, and + then remains open and accepts data until + the client disconnects, at which time + stdin is closed and remains closed until + the container is restarted. If this flag + is false, a container processes that reads + from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the + file to which the container''s termination + message will be written is mounted into + the container''s filesystem. Message written + is intended to be brief final status, + such as an assertion failure message. + Will be truncated by the node if greater + than 4096 bytes. The total message length + across all containers will be limited + to 12kb. Defaults to /dev/termination-log. + Cannot be updated.' + type: string + terminationMessagePolicy: + description: Indicate how the termination + message should be populated. File will + use the contents of terminationMessagePath + to populate the container status message + on both success and failure. FallbackToLogsOnError + will use the last chunk of container log + output if the termination message file + is empty and the container exited with + an error. The log output is limited to + 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. Cannot be updated. + type: string + tty: + description: Whether this container should + allocate a TTY for itself, also requires + 'stdin' to be true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of + block devices to be used by the container. + items: + description: volumeDevice describes a + mapping of a raw block device within + a container. + properties: + devicePath: + description: devicePath is the path + inside of the container that the + device will be mapped to. + type: string + name: + description: name must match the name + of a persistentVolumeClaim in the + pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the + container's filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container + at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines + how mounts are propagated from the + host to container and the other + way around. When not set, MountPropagationNone + is used. This field is beta in 1.10. + type: string + name: + description: This must match the Name + of a Volume. + type: string + readOnly: + description: Mounted read-only if + true, read-write otherwise (false + or unspecified). Defaults to false. + type: boolean + subPath: + description: Path within the volume + from which the container's volume + should be mounted. Defaults to "" + (volume's root). + type: string + subPathExpr: + description: Expanded path within + the volume from which the container's + volume should be mounted. Behaves + similarly to SubPath but environment + variable references $(VAR_NAME) + are expanded using the container's + environment. Defaults to "" (volume's + root). SubPathExpr and SubPath are + mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. + If not specified, the container runtime's + default will be used, which might be configured + in the container image. Cannot be updated. + type: string + required: + - name + type: object + type: array + timeout: + description: Timeout defines the maximum amount + of time Velero should wait for the initContainers + to complete. + type: string + type: object + type: object + type: array + required: + - name + type: object + type: array + type: object + includeClusterResources: + description: IncludeClusterResources specifies whether cluster-scoped + resources should be included for consideration in the restore. If + null, defaults to true. + nullable: true + type: boolean + includedNamespaces: + description: IncludedNamespaces is a slice of namespace names to include + objects from. If empty, all namespaces are included. + items: + type: string + nullable: true + type: array + includedResources: + description: IncludedResources is a slice of resource names to include + in the restore. If empty, all resources in the backup are included. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector is a metav1.LabelSelector to filter with + when restoring individual objects from the backup. If empty or nil, + all objects are included. Optional. + nullable: true + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement is a selector that + contains values, a key, and an operator that relates the key + and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: operator represents a key's relationship to + a set of values. Valid operators are In, NotIn, Exists + and DoesNotExist. + type: string + values: + description: values is an array of string values. If the + operator is In or NotIn, the values array must be non-empty. + If the operator is Exists or DoesNotExist, the values + array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single + {key,value} in the matchLabels map is equivalent to an element + of matchExpressions, whose key field is "key", the operator + is "In", and the values array contains only "value". The requirements + are ANDed. + type: object + type: object + namespaceMapping: + additionalProperties: + type: string + description: NamespaceMapping is a map of source namespace names to + target namespace names to restore into. Any source namespaces not + included in the map will be restored into namespaces of the same + name. + type: object + preserveNodePorts: + description: PreserveNodePorts specifies whether to restore old nodePorts + from backup. + nullable: true + type: boolean + restorePVs: + description: RestorePVs specifies whether to restore all included + PVs from snapshot (via the cloudprovider). + nullable: true + type: boolean + scheduleName: + description: ScheduleName is the unique name of the Velero schedule + to restore from. If specified, and BackupName is empty, Velero will + restore from the most recent successful backup created from this + schedule. + type: string + required: + - backupName + type: object + status: + description: RestoreStatus captures the current status of a Velero restore + properties: + completionTimestamp: + description: CompletionTimestamp records the time the restore operation + was completed. Completion time is recorded even on failed restore. + The server's time is used for StartTimestamps + format: date-time + nullable: true + type: string + errors: + description: Errors is a count of all error messages that were generated + during execution of the restore. The actual errors are stored in + object storage. + type: integer + failureReason: + description: FailureReason is an error that caused the entire restore + to fail. + type: string + phase: + description: Phase is the current state of the Restore + enum: + - New + - FailedValidation + - InProgress + - Completed + - PartiallyFailed + - Failed + type: string + progress: + description: Progress contains information about the restore's execution + progress. Note that this information is best-effort only -- if Velero + fails to update it during a restore for any reason, it may be inaccurate/stale. + nullable: true + properties: + itemsRestored: + description: ItemsRestored is the number of items that have actually + been restored so far + type: integer + totalItems: + description: TotalItems is the total number of items to be restored. + This number may change throughout the execution of the restore + due to plugins that return additional related items to restore + type: integer + type: object + startTimestamp: + description: StartTimestamp records the time the restore operation + was started. The server's time is used for StartTimestamps + format: date-time + nullable: true + type: string + validationErrors: + description: ValidationErrors is a slice of all validation errors + (if applicable) + items: + type: string + nullable: true + type: array + warnings: + description: Warnings is a count of all warning messages that were + generated during execution of the restore. The actual warnings are + stored in object storage. + type: integer + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_schedules.yaml b/config/crd/v1/bases/velero.io_schedules.yaml new file mode 100644 index 000000000..5e5aec210 --- /dev/null +++ b/config/crd/v1/bases/velero.io_schedules.yaml @@ -0,0 +1,394 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: schedules.velero.io +spec: + group: velero.io + names: + kind: Schedule + listKind: ScheduleList + plural: schedules + singular: schedule + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Schedule is a Velero resource that represents a pre-scheduled + or periodic Backup that should be run. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ScheduleSpec defines the specification for a Velero schedule + properties: + schedule: + description: Schedule is a Cron expression defining when to run the + Backup. + type: string + template: + description: Template is the definition of the Backup to be run on + the provided schedule + properties: + defaultVolumesToRestic: + description: DefaultVolumesToRestic specifies whether restic should + be used to take a backup of all pod volumes by default. + type: boolean + excludedNamespaces: + description: ExcludedNamespaces contains a list of namespaces + that are not included in the backup. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources is a slice of resource names that + are not included in the backup. + items: + type: string + nullable: true + type: array + hooks: + description: Hooks represent custom behaviors that should be executed + at different phases of the backup. + properties: + resources: + description: Resources are hooks that should be executed when + backing up individual instances of a resource. + items: + description: BackupResourceHookSpec defines one or more + BackupResourceHooks that should be executed based on the + rules defined for namespaces, resources, and label selector. + properties: + excludedNamespaces: + description: ExcludedNamespaces specifies the namespaces + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + excludedResources: + description: ExcludedResources specifies the resources + to which this hook spec does not apply. + items: + type: string + nullable: true + type: array + includedNamespaces: + description: IncludedNamespaces specifies the namespaces + to which this hook spec applies. If empty, it applies + to all namespaces. + items: + type: string + nullable: true + type: array + includedResources: + description: IncludedResources specifies the resources + to which this hook spec applies. If empty, it applies + to all resources. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector, if specified, filters the + resources to which this hook spec applies. + nullable: true + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a + selector that contains values, a key, and an + operator that relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are + In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. If the + operator is Exists or DoesNotExist, the + values array must be empty. This array is + replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is "In", + and the values array contains only "value". The + requirements are ANDed. + type: object + type: object + name: + description: Name is the name of this hook. + type: string + post: + description: PostHooks is a list of BackupResourceHooks + to execute after storing the item in the backup. These + are executed after all "additional items" from item + actions are processed. + items: + description: BackupResourceHook defines a hook for + a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and arguments + to execute. + items: + type: string + minItems: 1 + type: array + container: + description: Container is the container in + the pod where the command should be executed. + If not specified, the pod's first container + is used. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + timeout: + description: Timeout defines the maximum amount + of time Velero should wait for the hook + to complete before considering the execution + a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + pre: + description: PreHooks is a list of BackupResourceHooks + to execute prior to storing the item in the backup. + These are executed before any "additional items" from + item actions are processed. + items: + description: BackupResourceHook defines a hook for + a resource. + properties: + exec: + description: Exec defines an exec hook. + properties: + command: + description: Command is the command and arguments + to execute. + items: + type: string + minItems: 1 + type: array + container: + description: Container is the container in + the pod where the command should be executed. + If not specified, the pod's first container + is used. + type: string + onError: + description: OnError specifies how Velero + should behave if it encounters an error + executing this hook. + enum: + - Continue + - Fail + type: string + timeout: + description: Timeout defines the maximum amount + of time Velero should wait for the hook + to complete before considering the execution + a failure. + type: string + required: + - command + type: object + required: + - exec + type: object + type: array + required: + - name + type: object + nullable: true + type: array + type: object + includeClusterResources: + description: IncludeClusterResources specifies whether cluster-scoped + resources should be included for consideration in the backup. + nullable: true + type: boolean + includedNamespaces: + description: IncludedNamespaces is a slice of namespace names + to include objects from. If empty, all namespaces are included. + items: + type: string + nullable: true + type: array + includedResources: + description: IncludedResources is a slice of resource names to + include in the backup. If empty, all resources are included. + items: + type: string + nullable: true + type: array + labelSelector: + description: LabelSelector is a metav1.LabelSelector to filter + with when adding individual objects to the backup. If empty + or nil, all objects are included. Optional. + nullable: true + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If + the operator is In or NotIn, the values array must + be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced + during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A + single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is "key", + the operator is "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + orderedResources: + additionalProperties: + type: string + description: OrderedResources specifies the backup order of resources + of specific Kind. The map key is the Kind name and value is + a list of resource names separated by commas. Each resource + name has format "namespace/resourcename". For cluster resources, + simply use "resourcename". + nullable: true + type: object + snapshotVolumes: + description: SnapshotVolumes specifies whether to take cloud snapshots + of any PV's referenced in the set of objects included in the + Backup. + nullable: true + type: boolean + storageLocation: + description: StorageLocation is a string containing the name of + a BackupStorageLocation where the backup should be stored. + type: string + ttl: + description: TTL is a time.Duration-parseable string describing + how long the Backup should be retained for. + type: string + volumeSnapshotLocations: + description: VolumeSnapshotLocations is a list containing names + of VolumeSnapshotLocations associated with this backup. + items: + type: string + type: array + type: object + useOwnerReferencesInBackup: + description: UseOwnerReferencesBackup specifies whether to use OwnerReferences + on backups created by this Schedule. + nullable: true + type: boolean + required: + - schedule + - template + type: object + status: + description: ScheduleStatus captures the current state of a Velero schedule + properties: + lastBackup: + description: LastBackup is the last time a Backup was run for this + Schedule schedule + format: date-time + nullable: true + type: string + phase: + description: Phase is the current phase of the Schedule + enum: + - New + - Enabled + - FailedValidation + type: string + validationErrors: + description: ValidationErrors is a slice of all validation errors + (if applicable) + items: + type: string + type: array + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_serverstatusrequests.yaml b/config/crd/v1/bases/velero.io_serverstatusrequests.yaml new file mode 100644 index 000000000..7ac36c8e8 --- /dev/null +++ b/config/crd/v1/bases/velero.io_serverstatusrequests.yaml @@ -0,0 +1,87 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: serverstatusrequests.velero.io +spec: + group: velero.io + names: + kind: ServerStatusRequest + listKind: ServerStatusRequestList + plural: serverstatusrequests + shortNames: + - ssr + singular: serverstatusrequest + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: ServerStatusRequest is a request to access current status information + about the Velero server. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ServerStatusRequestSpec is the specification for a ServerStatusRequest. + type: object + status: + description: ServerStatusRequestStatus is the current status of a ServerStatusRequest. + properties: + phase: + description: Phase is the current lifecycle phase of the ServerStatusRequest. + enum: + - New + - Processed + type: string + plugins: + description: Plugins list information about the plugins running on + the Velero server + items: + description: PluginInfo contains attributes of a Velero plugin + properties: + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + nullable: true + type: array + processedTimestamp: + description: ProcessedTimestamp is when the ServerStatusRequest was + processed by the ServerStatusRequestController. + format: date-time + nullable: true + type: string + serverVersion: + description: ServerVersion is the Velero server version. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml b/config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml new file mode 100644 index 000000000..4a63234c3 --- /dev/null +++ b/config/crd/v1/bases/velero.io_volumesnapshotlocations.yaml @@ -0,0 +1,72 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.3.0 + creationTimestamp: null + name: volumesnapshotlocations.velero.io +spec: + group: velero.io + names: + kind: VolumeSnapshotLocation + listKind: VolumeSnapshotLocationList + plural: volumesnapshotlocations + singular: volumesnapshotlocation + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: VolumeSnapshotLocation is a location where Velero stores volume + snapshots. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: VolumeSnapshotLocationSpec defines the specification for + a Velero VolumeSnapshotLocation. + properties: + config: + additionalProperties: + type: string + description: Config is for provider-specific configuration fields. + type: object + provider: + description: Provider is the provider of the volume storage. + type: string + required: + - provider + type: object + status: + description: VolumeSnapshotLocationStatus describes the current status + of a Velero VolumeSnapshotLocation. + properties: + phase: + description: VolumeSnapshotLocationPhase is the lifecycle phase of + a Velero VolumeSnapshotLocation. + enum: + - Available + - Unavailable + type: string + type: object + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crd/v1/crds/crds.go b/config/crd/v1/crds/crds.go new file mode 100644 index 000000000..4b2ce8e26 --- /dev/null +++ b/config/crd/v1/crds/crds.go @@ -0,0 +1,69 @@ +/* +Copyright the Velero contributors. + +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. +*/ + +// Code generated by crds_generate.go; DO NOT EDIT. + +package crds + +import ( + "bytes" + "compress/gzip" + "io/ioutil" + + apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/client-go/kubernetes/scheme" +) + +var rawCRDs = [][]byte{ + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec<]o#9r\xef\xfe\x15\x05\xe7a\xee\x00K\xbeŽ\x04~\x9b\xf5x\x11a7sƎ\xe3<\x04y\xa0\xbaK\x12\xcf\xddd\x87dˣ\x04\xf9\xefA\x15\xc9\xfeR\u007fP^On\xef0|\x99q\x8b,\x16\x8b\xf5\xcd\"\xafV\xabՕ\xa8\xe43\x1a+\xb5\xba\x03QI\xfc\xeaP\xd1_v\xfd\xf2\xcfv-\xf5\xed\xf1\x87\xab\x17\xa9\xf2;\xb8\xaf\xad\xd3\xe5\xafhum2\xfc\x84;\xa9\xa4\x93Z]\x95\xe8D.\x9c\xb8\xbb\x02\x10Ji'賥?\x012\xad\x9c\xd1E\x81f\xb5G\xb5~\xa9\xb7\xb8\xade\x91\xa3a\xe0q\xea\xe3\x9f\xd6\u007f^\xff\xe9\n 3\xc8ßd\x89։\xb2\xba\x03U\x17\xc5\x15\x80\x12%\xde\xc1Vd/ue\xd7G,\xd0\xe8\xb5\xd4W\xb6\u008c\xe6\xda\x1b]Ww\xd0\xfe\xe0\x87\x04<\xfc\x1a~\xe4\xd1\xfc\xa1\x90\xd6\xfd\xdc\xf9\xf8\x8b\xb4\x8e\u007f\xa8\x8aڈ\xa2\x99\x89\xbfY\xa9\xf6u!L\xfcz\x05`3]\xe1\x1d|\xa6)*\x91a~\x05\x10\x96\xc3S\xae\x02\xc2\xc7\x1f<\x84쀥\xf0\xb8\x00\xe8\n\xd5\xc7\xc7\xcd\xf3\x9f\xbf\xf4>\x03\xe4h3#+\xc7D\U00048074 \xe0\x99\x97\x05&\x90\x1f\xdcA80X\x19\xb4\xa8\x9c\x05w@\xc8D\xe5j\x83\xa0w\xf0s\xbdE\xa3Сm@\x03dEm\x1d\x1a\xb0N8\x04\xe1@@\xa5\xa5r \x158Y\"\xfc\xe1\xe3\xe3\x06\xf4\xf6\xaf\x989\vB\xe5 \xacՙ\x14\x0es8\xea\xa2.я\xfd㺁Z\x19]\xa1q2\xd2ٷ\x0eWu\xbe\x0e\x96\xf7\x81(\xe0{AN\xec\x84~\x19\x81\x8a\x98\a\xa2\xd1z\xdcA\xdav\xb9\xcc!=\xc0@\x9d\x84\nȯ\xe1\v\x1a\x02\x03\xf6\xa0\xeb\"'.<\xa2!\x82ez\xaf\xe4\u007f7\xb0-8͓\x16\xc2a`\x80\xb6I\xe5\xd0(Q\xc0Q\x145\xde0IJq\x02\x834\vԪ\x03\x8f\xbb\xd85\xfc\xab6\bR\xed\xf4\x1d\x1c\x9c\xab\xec\xdd\xed\xed^\xba(M\x99.\xcbZIw\xbae\xc1\x90\xdb\xdaicos\xe9_\xd1:\x99\r{\r\x90\xfa4:(\"\x85\x16^\x0f\xe8\x0eh\x88\u007f\xf8\a\x16\xc93\x98\xc0[j1g\x89\x14/\b\"`Ϣ]\x14P騅,lO\x11\xd9\xf5\x19$Oۭ\xd6\x05\x8a\xa1\x96\xc0\xafYQ\xe7\x987j\xfb\x8c\x06\x83\xd5=\x9c\r`\x93&\xa4\"\xa9!#B\xe8\xa9\xf6WR\xcc#\x8b\x13\x06\x81\xf8V*\x0f\x8fu\xee\x01G7\x88\x9atX\x8e\xe06\xc9f\xbe\x91\xa9\x14\xdb\x02\xef\xc0\x99\x1a'(#\x8c\x11\xa7\t\xbaD\xf3\x9eJ\x96\xa6\u007f\xd0\"\x85\xcc\xd8\xfe4\xba\x82)㭕0\xe7\x18\xc1\xef\x99(\a\xad_\x96\b\xf1/ԧ\xd5{\x90\xb1\x97\x04[<\x88\xa3\xd4&,=\x98\xa1-\x02~Ŭv8\xc6\xff\xc2A.w;4\x04\xa7:\b\x8b֛\xbei\x82L\x8b253\xbd\x99g\xebh7\x928\x95W>\x85:\t\xf4P\xaeb#D\xc9h\x90ۢry\x94y-\n\x90\xca:\xa12\xbf\x1e\xd1\xe0u\xbe\x1e\x98\xdb\xe43\x9c\xbd:\x8c\x98\xd3N\xf4T\xa3V\b\xda@I\xf6\xe0\xbc\xebЂ\xb5mj\xd9[A\xdaI{\x165u\x816L\x95\xb3\xcemu\xc0\xcd$\xe8fG\xbc/Q\x88-\x16`\xb1\xc0\xcci3N\x8e\xa5M\xf6-E\xafMPqDõ\xba\x9b\x96\xda.l\x06$\x90\xda~=\xc8\xec\xe0\xcd~\xd2h?k\xc7_\xbe\t9=\xe2o \xa6\x1f\xc8⥼\xda&:tsh\t\xcc\xed\xdb\xc6Gx\xcd\xf6H\v\x1bEqK\xa0\agD\xfdt\xf3\xf6\xa1\xdf\xca\xdar\x92Li\xb5bS\xb9\x1e\x9b\xc9\x13;\x11\xa46\xbd\x1d9G\xad\x99\xd4O\x98\b\xf6\x89,\x89\x1f\xefs\xbc\x85\xc80\x87\xbcfbrfR8\xdc\xcb\fJ4\xfb9\xc3\xd1m\x15\xe9\xf74\x14\x12\xb5\xaeo\x17rX\x9ai\x8f-\xa8\xee|\x19\x99\x15InB\xaf\xb8ً]'\x12\x92\xd3]\x97W\xc4&\x96\xfd\x8fE\xea\x8a<\xe7\xb3$Q<^\xa0\xf1/؋s\xdb\xef\x11\xf3\x16\xb2\x14\x9cd\xfc\x1f2s\xcc\xd0\xff\v\x95\x90&A\x86?\xf2\xd1P\x81\xbd\xb1!\x8b՝\x86f\x90\x16h\u007f\x8f\xa28Ou\x8f,N\x93n\xc1\xc2\x1br\xbd;\xf3Xn\xe0\xf5\xa0\xad\xb7\xa9;\x89\xa3)\xd5~\x93\x16\xae_\xf0t}s\xa6\a\xae7\xea\xda\x1b\xf8\x8b\xd5M\xe3-hU\x9c\xe0\x9a\xc7^\xff\x16'(\x91\x13\x93\xba\xf1\x11\\\xaa\xabL\xb1d\xf4\x04h`s\xeeDn\xee\x1c\xd6I|Xi\xeb\x92Qy\xd4\xd6\xf9\xccb\xcf-\xbd$\x8b\x05\x9e\x87B\xf6\n\xc4Ο\xfci\x13\xcftH\xed\r\x12\xae\xb4kv^\xc3\xd266\x191\x0f\x94\x02\xab\xebV\x82\xbd>\xbd\xf6\a=<\x89\xc8عX\x84[\x19\x9d\xa1\xb5\xf3,\x92\xa0\xad\x17\x92\x84M\x82P\xf8\x00\xc6\x1f\x98\xcc'%cKwH\x89H\x17\xba\xf2\x0f_;\xd9K\x12~\xfa{\x89\xf9.\xc5\vXf\xcbR\fO\x06\x93P\xbc\xf7#\xa3\x98\x04@>40\xfb\x9aE=݃\f\x8c\xf4{0ӥT\x1b\x9e\x00~xw\xb3\xde(I|\x8b\xe3~\x1fǶDo>\xb0\xf4\xa6zD\x9a3\xf7\x06{;w\x9e\xe7&G1\x11\xa4Ү\x9bN \xb8\x95\xce?X\xd8Ic]\x17\xd1T\xa6\xa8\x17\xa4\xbfm\x97FN\xea\xc1\x987\x05N\u007f\xf1#;\x89\xac\x83~\x8d竓\x87\x99c\x8d\x0f\x85\x10\xe4\x0e\xa4\x03T\x99\xae\x15\xa7_H\xd4y\n\xbf\x05^A'\x93,MAPCU\x97i\x04X1\xd7I5\x9b\xa7\xe9v\xffI\xc8\xe2[l\x9b\x93%\xeaz\xd6p\xb6\xad\xb7mO~d\uf83c\x14_eY\x97 J\"}jس\xf3\xc51\xbd\x1d\x87W!\x1d[\x0e\x82\xcbf\xc4i\x12\xaa\xaa@\x97*\x91[\xdci\xc3\xf2le\x8e\x8da\x0e\\\xa0\x15\b\xd8\tY\xd4&QC^D\xdbKb\x8d\xa0,\xde/\x88H\x9b|ŤHH\xc4&:\x8b\xf3ں2\xe9\xae\xe2\xa3\xc14\xf7l))\x1dݳ\xcaH\xe2%\xfd\xde\x1eZ`1\xa1N\xdf]\xb4\xb3\xf6\xddE[h\xdf]\xb4\xc9\xf6\xddE[n\xdf]\xb4о\xbbh\xb1}wѾ\xbbhs\xdd\xe6\xb4\xf5\x12F\xbe\xe2~\xe2\xc7E,\x12\x8e\xa7\xe7P\x9c\x81\x1f\xaa)\xee}\xf5}j\x85\xe5f|\xd4H]m(\xeb_\xf1\x8d\x841\x0eh\x8b.ZSҔ\\\x92\x80D\xf6\xf6\x05\xc4\vE\x98I\xe5\x94\xe3շ)\x05?Ke>\xfd:Ӧ\xcc&\x16\x9a\xea8\xc9\b\x1d\xe2\xcd\x06r{\xbb5$\xfdz\x1d\xf6s#\xa6\u007f\xf3\x1aԄR\x9c\x85\x02\x9c\xf9\xc2\xdc9z\rB\x8f>\xc1L\xaf`\xf4wC\xaf\x85*\x99\xe9ژp\x12\x84N\x1c\u007fX\xf7\u007fq:T\xca\xc0\xabt\x87\x91\xa5\xbc\x1eP\xf1\x19\x96\xdaw\xcb^#\xbf\x85+&C:\x826\xa0d\xc1\xe4\x9c\xe1\xd6\x1ey\xe1/\x95\x0f\xe1.\x96\xcb\xf9\xf0#\xad\x96\xe6\xcd\x154\xfd\n\x99\t\x15}\xe9\x91Qz\xa1pz\x8d\xcc|Q\xcb%\x951ú\x97I\xa0\xcb\xf50)\x91\xe3B\xed\xcb\x1b*^\x12\xab\x1d\u007f\xf3\xc1XJM˛*Y\x16\v\x02\x13\xebW\xfa\x95)\xf3 /\xa8ZI\"\xcer\x85\xca\xc5u)\xa1\x0edv\x1d\xc9\xd5(#u&\xb3\x80'kP\xe6\xaaK\x16\xb2R\xe7\x95'\xe95%\xb3\xa0\xb9\xded\xb9\x92\xe4\xfd\xeaE\xdf\xc3\a\x9eV5\x8b\xd5 \x8b>\xf2<~\x8b\xf5\x1e\x97Ty,R\xec\x8d\x15\x1dM\xc5\xc6ļ\x97\xd6q\xf4\xeb4&\x80\xa6ToLTgL@\x9c\xad\xd9H\xadɘ\x80\xbd`vg\xb9d\xe6Gmr4\xb3\x8el*\u007f\xcc\xf2F?14\x98sP\x8d\x1e\xef\x17R\xaf\xaes\x82\x1f\x840\xb9G\x8dS\xc8ͥ\xf3Wa\x9bd\xf1\xa8%l\xc1\xf9\x91\xech\x124\xcc\x01\x8f\xa8@+\xce\r\xf3\xcdQ\xffh\xc9p\xccXΥ\x03%$\x9f\xeb\xaa\xd0\"\x8f\x12\x1emVx\xe8\xe2\x89\xf5\x979\xa2\xf9`g`\xf2\xc5\xfa\x9d6cD8W\x98ް\xdcA.\x1c\xaeF\x81&\xe9\xbeQf\xe3c\x94\xc5\xeb\xe5\xdc\xc9K\x10\x9f\xc1\xc47\x00\xfc!L\x89֊}\xbcW\xfeJ\nl\x8f\n\xd9n\x8e\xac?\xb8\xfdmҾ\u007f\xab\xdag\x1eD\xe6j\x11&\x88I\x97N\xaf\x0fcf\xa5\xd0{\xd8ɂ\xbb\x86\x170\x82f\x9fR;R9\xdc\xe3Ыï\x954)\x96\xe0\xa1\xe9H\xb4\xe1\xb4\x13k\x83\xf6\xa5\x18,\xe4^\x92\x1a\xa5\xcd\xde\v\xb3\x15{\\e\xba\xa0\x98^ju\x8e\u05f7\xdck\x0f{\xf4%\x98\xb3\xa5\xfd\xd4\xed\x1b\xfd\xa9\xc0\xec\x1eN|\x18\xe6&X\xe8\xf1Ƞ\x14\u007f\xd5\xe6\x06J\xa9\xe8\x1fr\xc38\x80\x8b\x83/\xb2\a|\t\u007f\x01\xefG\xeaӜ\xfbv\xb4\x1bF6\x9b\xf2\x1f\xc6\xcf\xfaV\xf0\x19\xcf͝?\xbeÜS\x14c\xcf\xdfP\x97\x8dz4zO\x11\xc6ȏ\xf7Q\x97\x8d\xfc\xf6(\x8c\x93\xa2(N~\x92\xc9\xd9G~\xf8\x84\xa4M&M\xca8Y\x03\x96K\x94\r\xdd\xdapF*\xcf\t|\xf0\xb6յ\xeb\th+\xe0#l\x11\xe7\\\xc3g\xed0f\xbbd\x1f&\xd9U\xb4n\x85\xbb\x9d6\xceGO\xab\x15\xc8]0Q#pI\xc3s\x86\u05ffF\x03ҵY\x86\x96{\xd9\xfb4(,s\xaf\xe37q\xf8\x10Fd\x19y@xk\x9d(F\xb4\xc6oJ\xea\xb2/@܇\xf9\xbf\x8d\x18\xc73\x82o\xba\xfd\x9bJ\xf8\xba\xdc\xfa\xe8\x88\xc1y\xca\xf1!\xb9ט\xc5T\xbaa\x8b\xa8\xe0\xd5H\xe7HKuS\xe0\xe0H/\x15\x05X\r;1\xf1\xee\xc1\x9c\xbe\xe4ߵ\x13\xc5f:\xf5\xd2w:\x9b\xceqY<\xfc|q\x9a\xb6e\xcb$\x98X\x96/\u00926\x8e\xa5\xad\xcc\x0eB퉩\x8c\xae\xf7\x87ȗ\x13\xf6f*a]\x13RP\x15\xf5\x9eX=\xa4\x90]mT'.\x0eI弃\xae\xc8^&1\rI\xb4\xf8\"\xdamx\xc9`\xb53\xba\\\x85\xbd\xe0\f\xf0M\x88W\x8d\xd4\xe4\x94Qt5\x01\xb4\xbd2\xcclPU\xa8@\u0600OB\x85\xd8\xfc\xb6\xce\x05\x8fN\x18\x97\xea\xea}\xe9u^\xf0\xf2\x18\xf28\xbe_B4\xee+\xe5\xee\x87o\xd3Qܬ\xe2cl>\xda\xf7\xac`\xc9\xf93\xc8\x01\xd4hZ\xff\xccm\xeb9i}\xf4\xff\u007f\xfd\xb3cca\x1eR<\xb5\xe7A\xf7\xc1q#Iy\v1xW#\xf4\xf8\x83\xdc\xf9\U000c6330\xfe\xe3\xdf\xfc\x18\xf1\x98\xe4\xb3|\x98uW\xd8\x13i\xfc\x0e\xf8\x84\x95\xc1\x8c\xa4wl\x19\x8f\x05\x92\x1fa\x11\xfb\x9eЇ\x8b\x1c\xc9~\x00k?:\x87e5:\xe3L\x04\xdb\x0e\x9bR\x96\"v\x18YH|'0\x02\v\x1583!\xeb\x05\vj\x9c\x98\xcb\x16\xd4\f\x9bZ\x90\xad3RZ\xbbzܜ5q\xe0;\xaf\xeeU\x18%\xd5~I\xc6\xfe=t\x1b\x89\x87\x02\x84\x91\x88hd\x19M\x8c\xb4\x18\x11u\x02\xa2\x88\xe3\xc4\xf3]\x83 \xe9\x9dB\xa2Q;p\xf6\x91\x15hޑ\xed0S\xf8\xd2f)D\x96!\xb1\xeb\xe7\xe1{\xa0\xd7\xd7\xfcG|\xf2\x93\xff̴\xf2\xe6\xd6\xde\xc1\u007f\xfc\xe7\x15\x844\xd8s|ۓ>\xfe_\x00\x00\x00\xff\xffR\xf8w-;U\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4YK\x8f\xe3\xb8\x11\xbe\xfbW\x14f\x0f}\x19˳\xd9K\xe0K\xe0\xf1$\xc0 =ۍq\xa7sH\x02,M\x96lnS\xa4BR\xf6:A\xfe{P|H\xb2$\xb7݃d\x97\x97n\xf3Q\xac\xfa\xeaM\xcd\xe6\xf3\xf9\x8c\xd5\xf2\x19\xad\x93F/\x81\xd5\x12\u007f\xf1\xa8\xe9\x97+^~\xef\ni\x16\x87\xefg/R\x8b%\xac\x1b\xe7M\xf5\x15\x9di,\xc7OXJ-\xbd4zV\xa1g\x82y\xb6\x9c\x010\xad\x8dg4\xed\xe8'\x007\xda[\xa3\x14\xda\xf9\x0eu\xf1\xd2lq\xdbH%\xd0\x06\xe2\xf9\xeaÇ\xe2\x87\xe2\xc3\f\x80[\fǟd\x85γ\xaa^\x82n\x94\x9a\x01hV\xe1\x12\xb6\x8c\xbf4\xb5\xf3Ʋ\x1d*\xc3\xe3]\xc5\x01\x15ZSH3s5r\xbazgMS/\xa1[\x88\x14\x12[Q\xa4\x8f\x81\xd8&\x12\xbbO\xc4º\x92\xce\xff\xf9\xf2\x9e{\xe9|\xd8W\xab\xc62u\x89\xad\xb0\xc5\xed\x8d\xf5?vW\xcfa\xebT\\\x91z\xd7(f/\x1c\x9f\x018nj\\B8]3\x8eb\x06\x900\v\xd4\xe6\xc0\x84\bZ`\xea\xd1J\xedѮ\x8dj*\xdd\xde%\xd0q+k\x1fP\x8e\xb2@\x12\x06\xb24\xe0<\xf3\x8d\x03\xd7\xf0=0\a\xab\x03\x93\x8am\x15.\xfe\xa2Y\xfe?\xd0\x03\xf8\xd9\x19\xfd\xc8\xfc~\tE\xfc\xe0J\xa2\x1e\xc2\xef\x9am%=\xe9\xfd\x9f\r:O\xba*`\x1d2\x16l\x11\x9a:\xf8}\x01\x9f5\xacY\x85j\xcd\x1c\xfe\xdf\x15@H\xbb9\x01{\x9b\n\xfa\xc9v\xb89\xa2\xd6[ȹ\xf0\x82\xbe&\xbdxS#?\xf3\x1f\x81NZ\xb2p\xcf<\x06\xbf\x18\xe0\x9a\\\xfcr2\xcdcڹi0\xceѹ/F\xe0pe\xc0\xf2\xaa\xddx\xc6c\x8d\xb6\x92.\xa4E(\x8d\x1df\f\xd6F\xe0\xfeȑ\xaa\x18\xad\xa1n\xaa1#s\xf8\x8aL\x86\x8d\x19\xe3x\x8cxi\x1c\x86\xe0{\x8d\r\xb8n㜭\xd1\xde\xc2\xcbzE\x1b\xdb4\xc9`\xbd\x82m\xa3\x85\xc2\xcc\xd1q\x8f\x9a:\x04Y\x9e\xa6\xef\xa2\xf1t\xbfɨ\x86\n#\xd5\xf8\x19\xdbi\x19b\f_\xc2\xf64Q\x13\xdc dm\xb1\x94\xbf\xdc \xe4cؘ\x01\xaf\x99߃\xd4N\n\x046\x01\u007f,\xd6.\b\xda\xe6\xff\x87\x14E\xbeA=\xafy{d\xe7-\x0e\x9f1\xbe\xe2?\x8fi[\x8bB\xfe\x9d\"\xffy-xɏ'%:\xb4\x0f\x06\u007f\x8a\x15\x16\x9fH\x95g\xcc<\x8fO\xbcR\xa9\xe5g\x8b)g\xa6\xba\xc0X\x8b\xae6ZP\xf3t[\x9dֱ\xfc\xbf\xab֦\xd5:?\x8fr\x83\xb5\xac\x85\x9bZ\x95\xf0D\xf3\xe6f%>\\\xf5[\x01\xb3u\xd4)v\xfd\xca@\xc6_\xa5My\xd7\xebS\xa8\x1f\xd6\xd0\xe8P\xa9\x85\x8c_\xc0\xdf5|\xa2ޖ\xb2\x93X\x12\xdfv\xca\x00\xa4\x03m\x8et\xbcG/\x90\x00\xa3c\xbe\xa6n\x8di\x91\x9a\xe1\xb0t\x94JQƶX\x99\xc3dƦBӢ:\x01sd:\x87\xdf\x15\x1f\x8aw\xbfY\x17\xa4\x98\xf3\xd4Ԡ\xf8\x8a\a9~\xe5\x19\xa3{?:\x91\x1d\xbfu\a\xfa\xf1Sn\x96\x176m\xfbi\x02\x8cR*\xaa\x05'\xe2DW1\x8c\xdf#?n\xee\xef\\(\xe1Q\xfb\xa9\xb2\xef\x88\x16CDŽ\x82\xaax\x93\xde%\x1a\xe7\xd1N\x18@\xab\xbd\xa0sPF\xef\x06\x8e\x13Gz\xa5\xa0\n-\x1a\x94\xb1 \xd0Sj\xd2;\xe0{\xa6wؽB%\xfe_\xe7\x94\xccg`3\x9d\x85H}\xc9\xa6-n\x13\xf5\x0e\xb9\x14\x9f\x8e>|h?\xb5\x1f\x1a\x00\xcbXҿҀ\xa2f\x88\x1b\xf0\xa9\xef\x1b\x00o\x06܀\xc3\x1e\x15\xb7\xc6>\xa6\xc8\xf8gBQi\x0f\xd8#\x87\x96B#\x11m>x\xcf!\xc5\r\x1c\x1d5\u007f\x04U/\xf4\xb9\x94\xfa\xa9\x94\xba\xab\xa5\x8a\xb7'џ_\x8b\xf8\x85ƨ\xd8'6\xfd2\xa0\x12 \xe4\xf7\xa97\xbc\x18\xd2\x00\x88\r\x117p\x93aEc\xd15\x00#\x1f\x05\xe6j\xbc\xf1\xe1c-g;\x1cL\xc5\x0f\x10\"\xfa\x1fo\xaf\x1f>ݟ\x99\x01\x1c\x8ae\x8aZX]\xc0\x0f$``D\x01\x1aFp\x10\xa3\xacQ\xe0rϠ\x80v8\xdd\x14\xddx1\b;Ў\x04\x18#\xa3\xa0\xaf]tV\x18r\x90\xf1\x10\xb6\u007f\xa0\xd5\x16\xee\x91s\x19\x90.\xa4\xde\xe5V; +0ڰ\xf7\xf4\xf7Km\xc9\xf7̇\xf6F'\x91\x8f\x0fyE\xf6\xa6\x87\x83\xe9\x13~\x0f\xc6;\x18\xcc30\xe6S \xf9\x93z%DZ\xf85\xd3D~\x176ЩF٬\xd7{\xd2idl\x18\x86\xe4I\x9fץ\xfbi\x9b4\xb0\xac\x1d\x1e\xb0_\v\xedW\x86mG\x8aV\x13\xe3\xdaDZ\x15辌M;\xb8\xefx\x1c2y\u007f\x86U\x9fsÈ2\xf9\xfd\x89\xa3t\xf37\x14Ƚ\\e\xaf\xa9\xf5\x16G\xa2\xb3)\xb3s\xf7\xe5\xfe+LG\x171\xe6\xec\x17ޏ\x89r\x94 \x13F~\x87\\E\xdcq\x18JM\xf4.\x06\xf2Z^lO\xe8\xe7\xf4K\xda\x0e\xa42\xb5d֪\x85\xab\xb2G`\x8b\x90\xa23\x8a\xae\x85k\x0fWf\xc0\xfe\xca\b\xfe\xef\x02d\xa6e\x95\x89}\x9b\x04\xa7+p\x1e\\Y;qL;\xea\x15\xbd\x16\x86\xf6>\xa2\xcd\nf\x12s6\xedȖ\xf1\x80]`x\xea\xc8v\xd3\xd0\xce\xd8}\x19\xf0\xf6̱<\xd0\xf9\xa9e\xf2R\x9a{^\xbd<\x14\xed\x88qօ\xab\x93bo\xe2E\x8d&\xf9\x8f̔\x9c\x89\x1b\x9b\x98\xd1\xebX\xa9l\x8b\xa5\xa4\xb7r\x81́/\xac3P_JP\xf9\xce\x19\xf2\x02\xc6?\x8f\x89\xa0\x9dQxB\xcec`C\xca{\x06\x1d\xb8t\xc1\xdfHK\x87U\xac,l\xe4`Q\xa4\xbd\x88#\xc5a\x01\xd37\xd4\xc9O\xfe\x86\x9am\x8f\x1bPN\xf8\x8a\xb2\x86\xd9<\xcf|\xb13\xb2\xd0\ng\x14\xdc\xe6\x98%\r\xb0nu\xfcw\x11\n\xdd>\r\x97'\xad\xe0\x06\x9f\x16\xac\xd7\xfe\x96ÞQ\xe6-\x9f\x9d\xb7\x95\xbd\xf2M}#K\x8bMya\x94\xbc\xef\xdc\t\x8b\xa2\x81\xcd~\xe2\xf5\xd8\xc2\xc6Z\x8c\x8a\xeef\xfe\xd7\xf1\xee\xdd\xd9\xefCy\xb5\xc1;\xaa?M\xf0\xdb\xefM\xad\x8a\xeea\xfa\x1b\xc8\xc6\u007f\x02\x00\x00\xff\xff~\x96\x80P\xae\t\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4WMo\xdc6\x10\xbd\xebW\f\xd2CZ \xd2&ȥ\xd8[\xeb\xe4\x104\r\x02;\xf5\xa5\xe8\x81K\xcdJ\xac)\x92\xe5\f\xd7q\x8b\xfe\xf7bHi?\xb4Z\xdb9T\xb7%\x87\xc3\xc7\xc7\xf7\x86\xb3U]ו\n\xe6\x16#\x19\xef֠\x82\xc1\xaf\x8cN~Qs\xf7#5Ưvo\xaa;\xe3\xda5\\%b?\\#\xf9\x145\xbeíq\x86\x8dwՀ\xacZ\xc5j]\x01(\xe7<+\x19&\xf9\t\xa0\xbd\xe3\xe8\xad\xc5Xw蚻\xb4\xc1M2\xb6Ř\x93O[\xef^7o\x9b\xd7\x15\x80\x8e\x98\x97\u007f1\x03\x12\xab!\xac\xc1%k+\x00\xa7\x06\\C\xeb\xef\x9d\xf5\xaa\x8d\xf8WBbjvh1\xfa\xc6\xf8\x8a\x02jٴ\x8b>\x855\x1c&\xca\xda\x11P9̻1\xcduI\x93g\xac!\xfeei\xf6\xa3\x19#\x82MQ\xd9s\x10y\x92\x8c\xeb\x92U\xf1l\xba\x02 \xed\x03\xae\xe1\x93\xc0\bJc[\x01\x8cgϰ\xea\xf1t\xbb7%\x95\xeeqP\x05/\x80\x0f\xe8~\xfa\xfc\xe1\xf6\xed\xcd\xc90@\x8b\xa4\xa3\t\x9c\x19\x9ca\x06C\xa0`D\x00\xec\xf7\xa0@9P\x91\xcdVi\x86m\xf4\x03l\x94\xbeKa\x9f\x15\xc0o\xfeD\xcd@\xec\xa3\xea\xf0\x15P\xd2=(\xc9WB\xc1\xfa\x0e\xb6\xc6b\xb3_\x14\xa2\x0f\x18\xd9L,\x97\xefH\\G\xa33\xe0/\xe5l%\nZQ\x15\x12p\x8f\x13?؎t\x80\xdf\x02\xf7\x86 b\x88H\xe8\x8a\xceN\x12\x83\x04)7\x9e\xa0\x81\x1b\x8c\x92\x06\xa8\xf7ɶ\"\xc6\x1dF\x86\x88\xdaw\xce\xfc\xbd\xcfM\u0090lj\x15Or8|\xc61F\xa7,\xec\x94M\xf8\n\x94kaP\x0f\x101\xf3\x94\xdcQ\xbe\x1cB\r\xfc\xea#\x82q[\xbf\x86\x9e9\xd0z\xb5\xea\fO\xa6\xd2~\x18\x923\xfc\xb0\xca\xfe0\x9b\xc4>Ҫ\xc5\x1d\xda\x15\x99\xaeVQ\xf7\x86Qs\x8a\xb8R\xc1\xd4\x19\xba\xcb\xc6j\x86\xf6\xbb8ڐ^\x9e`\xe5\a\x91\x19q4\xae;\x9aȚ\u007f\xe4\x06D\xf5E0ei9Łh\x19\x12v\xae\xdf\xdf|\x81i\xeb|\x19s\xf6\x8br\xf6\v\xe9p\x05B\x98q[\x8c\xe5\x12\xb3\xf2$'\xba6x\xe38\xff\xd0֠\x9b\xd3Oi3\x18\xa6I\xccrW\r\\\xe5J\x03\x1b\x84\x14Z\xc5\xd86\xf0\xc1\xc1\x95\x1a\xd0^)\xc2\xff\xfd\x02\x84i\xaa\x85\xd8\xe7]\xc1q\x91\x9c\a\x17֎&\xa6Jv\xe1\xbefV\xbf\t\xa8\xe5\xf6\x84@Yi\xb6Fgk\xc0\xd6GP\a\xe7\x8f\x046'\x99\x97\x9d\x9b\xc1\xa9\xd8!\xcfGgX\xbe\xe4 \xd9\xfe\xbeW\xa7\x85\xe6{l\xbaFj\x05\x8d@J\xf5\xf8\xa19\xcbx\x19\x03,\xaaw\x11\xc9$b\xa1Ax\x95R E\xea\x18\xd3\xf9\xd6\xf2\xa1K\xc3\xf2\x065\xfc\x9c1\u007f\xf4ݣ\xf3Wޱ\xc8\xfdѠ[oӀ7N\x05\xea\xfd\x13\xb1\xd33\xbb\u007fz\xce\x03\xafQ\n4^\x866\x06\\#%{a\xbb\vb\x9d\xbe\xfc(=ͼ/\xcc\xd7&\xf5\x88\xc8k\x93\xdd\xfd\xed\xf0E\xed&\xe2\x82t\xea,\xa9\x85a\x01\u007f6|\xc1\xa3\x976\xa8G\xdf<\xcb\xe7\xac8\xd178=\xc7OT\xeb\x14#:\x1e\xb3\xe4\x97o\xbe\xe0\xb9V\x9f\xfc\xf1\xdb\xf5\xc7'\xfc\xfe\xee\x10\x99{;e\\A\x13\"\xd6d:y\xafeN\x1c\x9f\x9dxNF\xf9N\xfb\x87S\xa2\x16o\x14\xbf\x06\x13s]{\x02\xe2\xfb}`)K\xe8ʓ3\xef\x90rB\xa4\xfc\x9ck5o$\xe4\xdb \xb4h\x91\xb1\x85\xcdC\xa9\xaf\x0f\xc48\x9c\xe3\xde\xfa8(^\x83`k\xe7\xa0;\xa5&\x00\x1a[\x9a\x835beT\xd7\xd2\x12\xcb\xe7\xce\xfa\xe9\x8a\x1493\x95f\xe2-\x95|i\xedLg\xe7\xb0\xdbHg\xb3@I\x99G#>F6\xef\"\x9b\xb8\xa3\xa4\x0f\u007f\x1f\xdb\xfdM\xfa\x10)\xac\xea\x1c\xaac!⦗\xba\xee\x14\xba\xa3\xed\t\x80/\x8d\xa59<\xb0\x18\x16K\x12\x13\x80\xac{\x14\xab\xc8ڭ~L\xacʆZL\xf2\x02\x18K\xfa\x97\xc7\xfb\x8f?/\x0e\x96\x01\xac3\x96\\\x90\xbdj\xe9\xdb\xf3\xe8\xde*\x80 _:iC\xb4\xf753LT ؕ\xe4!4\xd4\vE\"\xcb\x00\xa6\x82\xd0H\x0f\x8e\xac#O:9\xf7\x8010\x11j0\xcb\u007fR\x19\xa6\xb0 \xc7l\xc07\xa6S\x82#`E.\x80\xa3\xd2\xd4Z\xfe{\xcb\xdbC0\xf1R\x85\x81\xb2\x85w\x9fԁ\x9cF\x05+T\x1d\xdd\x00j\x01-n\xc0\x11\xdf\x02\x9d\xde\xe3\x17I\xfc\x14~7\x8e@\xea\xca̡\t\xc1\xfa\xf9lV\xcb\xd0Griڶ\xd32lf1(\xe5\xb2\v\xc6\xf9\x99\xa0\x15\xa9\x99\x97u\x81\xaeld\xa02t\x8efhe\x11E\xd71\x9a\xa7\xad\xf8\xce\xe5\xd8\xf7\xd7\a\xb2\x86\r\xfb\xd6\a'u\xbd\xb7\x11\x03\xed\x8c\a8\xd4@z\xc0|4i\xb134/\xb1u>\xfce\xf1\x04\xfd\xd5\xd1\x19C\xebG\xbb\xef\x0e\xfa\x9d\v\xd8`RW\xe4\x92\x13+g\xdaȓ\xb4\xb0F\xea\x10\xff(\x95$=4\xbf\uf5ad\f\xec\xf7\u007fu\xe4\x03\xfbj\n\xb71\xbdaI\xd0Y\x81\x81\xc4\x14\xee5\xdcbK\xea\x16=}u\a\xb0\xa5}\xc1\x86}\x99\v\xf6+Ӑ8Ymo\xa3/\x1f'\xfc5\xa8\t\vK%{\x8f\r\xc8'e%˘\x1aP\x19\a8$\x9f\x1e0\x1eO\\\xfeR\xc5X\x04㰦\xdfLb9$\x1aH\xf6n\xecL/\x1bו\x94Ĕ\x99\x83O\x94GL\x01T\u007fxݐ\xa3xƑ\x0f\xb2\xe4\xe02^\x06\xe36̘9\x90\x98\x1eq8\xe1\x06\xfe\xb4\x11tA\x8f\a#hLl>\n\xa1\xc1\x14\xad\x8f&f\x8d\xeb\xb4>\xbe\x85?\xa3_%\x985\xe2\x82\\\xf9F\x04G\x159Ҝ\x85\xa9pY\x13\xcb[@\xa9\xfblM\x85\x1f\x82\x19\x91l\x99\\@\x02\x86\x01\x01g\x83\x02\xceT\xf5Q\x89\u007fy\xbc\xef+yo\xc4,{8\xbe\xf7\x82}\xf8\xab$)\xf1\x88\xa1y\xc1\xdd\xd7\xf7U\xba,ִ`\x00\xc1J*\xe9\xa0I\x80\xd4>\x10\n0\xd5(G\x06\x12\xc0\x89\xef(\x9f\xb8I\x15,\x97\xca]ka\xdb\x03r\xed\x94\x02\xfe\xb6x\xff0\xfb\xeb\x98\xe9\xb7Z\x00\x96%yf\x84\x81Z\xd2\xe1\x06|W6\x80\x9eՐ\x8eĂw\xa6-jY\x91\x0f\xd3|\a9\xff\xe9\xa7\xcf\xe3\xd6\x03\xf8\xd58\xa0/\xd8ZE7 \x93ŷe\xb9\x0f\x1a\xe9\x939\xb6\x1ca-C#\x87\xcdtk\x01\x0e\xaf\xac\xf6:\xaa\x1b\xf0\x99\xc0du;\x02%\x9fi\x0eW\\~\xf6\xc4\xfc\x0f\xe7\xce\u007f\xafNp\xfdCJ\xed+&\xbaJ\xc2m\xfb\xf0~\xd2\xed\x84L\x99\xe7d]\x93\x8b\xc0e\xec\x8bM\x85K\xf5\xf7`\x1c[@\x9b=\x16\x911{/\x15J\x12GB\u007f\xfa\xe9\xf3I\x89\x0f\xed\x05R\v\xfa\x02?\x81\xd4\xc96ֈ\xef\xa7\xf0\x14\xa3c\xa3\x03~\xe1\x9b\xca\xc6x:eY\xa3ՆunpE\xe0MK\xb0&\xa5\x8a\x84\x83\x04\xacq\xc3V\xe8\x1d\xc7\xf1\x86`х\xb3\xd1ڣ\x9f\xa7\xf7w\xef\xe7I2\x0e\xa8:Vb\ue695d4\xc30&\xf5\xe2\x18\x8dGͼ\xff|\x97\xc2'\x18(\x1b\xd45%}\t\xaa\x8e\xbb\xe3\xf4\xfa-y|\fI\xfao\x04\x9a\f\v\xc7\xff\xad\xb9\xbfP\xb9\x88\xa0_\xa0\xdc\xc3^\x94\x9fU\x8eg\x15\xa7)P\xd4O\x98ҳj%\xd9\xe0gfEn%i=[\x1b\xf7,u]ph\x16)\x06\xfc,\x8e\x1b\xb3\xef\xe2?o\xd6%\x0e\n/U(\x12\u007f\v\xad\xf8\x1e?{\x93R=\x86}y\x1f\xbb^dd5<\xcbi\xb1nd\xd9\xf4\xc3I\xae\xb1'\x92I2\x12\x16\xa94\xa3\xde|\xf5Pf\x83v\x8e%\xda\x14y\x00.P\v\xfe\xbf\x97>\xf0\xfa\x9b,\xd8\xc9\x17\xa5\xef?\xee\xef\xbeM\x80w\xf2M\xb9z\x02\x80\xa7\x18\xb1\xe6^\xb0)+I\xee\x020\xfbp@\xdcC\xc7\x11ĺ\xa5y\x152\fX\x8f@1\x14\">{\xa0z<\v\xd8\xceZ\xe0@\x8d'\xac=\xa0#@hѲ\xe7\x9eiS\xa4\x16oQr\u007f\xe6\x16\x9c1ϒ\x00\xadUr\xb4\x15\xe7F\x9eAh\xc6\xfb\xea\x87\xc4\xe1\x82\xfdӀ3\x06ٳ\x00\t\xdfla{0\xb0\x1cK\xd13\xa0\xf8\xa4\x15y.e\xb4v(b1>@\rhx\xa0\x18,Y#\x06+\x87\x918\xd8L\xfa\xbdh\xaa\f\x18:\xff\x8a\xb92\xd2\xf76MU$d.\x11B\xbfu\xb2,\r\xa3\xd3ç\xb5\xf3\xee\xbd=>\x11\x1fq\x9cH\xc2\x05\xd9r\xcc\xe6([\xa3\xef\xef\x18\x1b\ra\x8f]:\x19\xeb6s#\x11\xa1##\xdb\n\xa5\"\x01\xfd\xdb\xde\xf0\xcc\b\xd7}.K\xaa\xb8\xc8uV\x19\x14\xfd@\x96\xc5\xdb\xc23\x9e\xd7\xe3\xebȵ?ó\xf3$\xe2$?b\x84c\xc8V\x19\xd7b\x98\x83\xc0@\xc5(S\xdd)\x85KEs\b\xae;\xde>S,Z\xf2\x1e\xebK\xa9\xf8{\xa2Jsj>\x02\xb84]\xd8\x0e\xaa\aE\xe1\xda\xe7\x98zݬ<:\x02\x1e\x8632D\xf7\x19\xaa*\x15\xcf\xec\x17\x82݃p\x94jI\xe3\xad\xee-5\x01\xc06\xe8/\x99\xea\x91i\xc6\x12l[\xbd\xcef\x18\u007f\xa4\xbb\xf6\xf8\x96\x02\x1eh=\xb2z\xaf\x1f\x9d\xa9\x1d\xf9\xe3\xc0)\xfa\xf8\x1a\xa9\xe6\x05\xfc\x1a\xb3\xe1U\xfa\xe7\x8b.\x99 \x93AcT\x9f\xcc&\xa0\x02ݵKrl\x87\xe5&\x90?,\xe7c\xaf\x12q\x9aٙq\xef|\xef\xbf\xc4)\x0fh%\xea\xf8z\xc8\xd9\x15\f\b\xe9\xad\xc2\xcd\b\xe3^\x91\x88X8\xb9\xb8\x04\xec\xe2\xb9OjK.n\xbd\xf65%\xcatg\xf4\t|\xdd\xe7\xb3\xd4\xe1O\u007f<\x83o\xa4\x0eT\x0f\x9aC\xdegs\xbe\xe3[\xbe\xce\rgZ\xb7\xd7h}c\xc2\xfd݅(Xl\t\xfbl\xd8\x01\xa5X\xfb\xe2\xdbf&ʡ0\xe6\xaammyU\xaa\xfa\x80.\xbc\xb4\x15-\x0e\x88/t\xa1\xc8y\xbc\a-Ȣ\xe3L\x8f/\xe1\xb7\xc3ߚn\xc0\xcb\xf8\xbc\xc7x+\x01\xb04|{nN\f,\x8d\xa3\x91\x92\t\xc7m堉\x1c\x8a\xff-\xfb\xc7h\x9c\x1c-F\xc9\xc5\x1e\xef\xfcD\x9cWv\x18\x06K\x9e\x0eH<\f\u007fO\xbbJ\xaf7\xfd\x0fd\xf1\xcf\xd2\xe8\x04\x95\xfd\x1c>}\x9e@~6\xfe\xd8\xff\xeeŋ\xff\v\x00\x00\xff\xff~\xe4\xff\xab\x84\x1c\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xc4YKo\xe3\xc8\x11\xbe\xebW\x14\xbc\ag\x81!\xb5;\x1b\x04\x81n\xbbv6P\xb2\xeb1F\xce\\\x06sh\xb1\x8bb\xc5d7\xd3]\x94\xac\x04\xf9\xefAu\xb3\xf5\xa4\x1e60\x13^l\xf5\xa3\xfa\xab\xaf\x1e]E\x8e\xb2,\x1b\xa9\x96>\xa1\xf3d\xcd\x04TK\xf8\xc2h\xe4\x97ϟ\xff\xecs\xb2\xe3口g2z\x02w\x9dg\xdb|Do;W\xe0=\x96d\x88ɚQ\x83\xac\xb4b5\x19\x01(c,+\x19\xf6\xf2\x13\xa0\xb0\x86\x9d\xadkt\xd9\x02M\xfe\xdc\xcdq\xdeQ\xad\xd1\x05\xe1\xe9\xe8\xe5\x0f\xf9O\xf9\x0f#\x80\xc2a\xd8\xfeD\rzVM;\x01\xd3\xd5\xf5\b\xc0\xa8\x06'\xd0Z\xbd\xb4uנC\xcf֡ϗX\xa3\xb39ّo\xb1\x90S\x17\xcev\xed\x04\xb6\x13qs\x8f(j\xf3h\xf5\xa7 \xe7c\x94\x13\xa6j\xf2\xfc\xf7\xc1\xe9\xdf\xc8sX\xd2֝S\xf5\x00\x8e0\xeb\xc9,\xbaZ\xb9\xe3\xf9\x11\x80/l\x8b\x13x\x10(\xad*P\x8f\x00z\x02\x02\xb4\xacWq\xf9c\x94UTب\x88\x19\xc0\xb6h~~\x9c~\xfai\xb67\f\xd0:ۢcJ\xea\xc5gǬ;\xa3\x00\x1a}\xe1\xa8\xe5@\xfa\xad\b\x8c\xab@\x8b=\xd1\x03W\x98@\xa1\xee1\x80-\x81+\xf2\xe0\xb0u\xe8\xd1D\v\xef\t\x06Y\xa4\f\xd8\xf9?\xb1\xe0\x1cf\xe8D\f\xf8\xcav\xb5\x167X\xa2cpX\u0605\xa1\u007fod{`\x1b\x0e\xad\x15c\xcf\xf1\xf6!\xc3茪a\xa9\xea\x0e߁2\x1a\x1a\xb5\x06\x87r\ntfG^X\xe2s\xf8\xdd:\x042\xa5\x9d@\xc5\xdc\xfa\xc9x\xbc N\xee\\ئ\xe9\f\xf1z\x1c<\x93\xe6\x1d[\xe7\xc7\x1a\x97X\x8f=-2劊\x18\v\xee\x1c\x8eUKY\x80n\x82K\xe7\x8d\xfe\xce\xf5\x01\xe0o\xf7\xb0\xf2Zl\xebّY\xecL\x04g;c\x01\xf16 \x0f\xaa\xdf\x1a\xb5\xd8\x12-C\xc2\xceǿ̞ \x1d\x1d\x8cq\xc8~\xe0}\xbb\xd1oM \x84\x91)\xd1E#\x96\xce6A&\x1a\xddZ2\x1c~\x145\xa19\xa4\xdfw\xf3\x86X\xec\xfe\xaf\x0e=\x8b\xadr\xb8\v1\x0es\x84\xaeՊQ\xe705p\xa7\x1a\xac\xef\x94ǯn\x00a\xdagB\xecu&\xd8MO\x87\x8b#k;\x13)\x85\x9c\xb0\xd7aZ\x98\xb5X\x88\xf9\x84A\xd9J%\x15!6\xa0\xb4\x0e\xd4\xd1\xfa|O\xf4p\xe8\xca3W\xc5s\xd7\xce\xd8:\xb5\xc0\xdfl\x94y\xb8\xe8\x00\xdb/C{\x128\xc9,1\x8c\xb1\x17\x0e>\xae<\x12\nP\xa7ͫ\n\x1d\x86=\x92Ũ\x10\xf7\xb2\x9eغ\xb5\b\x0e*\xe9\xfcH\xc2\tC\x04\x95\xad\xbe\xa0ƣ\xed\x03\xc2a\x89\x0e\x8d\xb8{\xcc\x10\xad\ry\x84\x15\x99\x14\x161\xc5\x02\xdb\x01-\xe6\x11\xf50\xc4\xd3\xd4Ù\xec9\b\xf8\xe7\xc7iʘ\x89\xe1\x1e:\x1f\x9f{\x81\x1eyJ\xc2Z?*\xae\xae8\xfbvZ\xc6\xc3B\xee`\v\nZ\xc2\x02\xf7\x921\x90\xf1\x8cJ\x83-\a%ʭ\r\x12`\x0e\xfb\x1d\xefb\xa6\xe8S\xd26\x85\v\xf5\xa0$G\x91\x86\xbf\xcd><\x8c\xff:\xc4\xfcF\vPE\x81^\x04)\xc6\x06\r\xbf\x03\xdf\x15\x15(/j\x90C=\x93\x99\xbcQ\x86J\xf4\x9c\xf7g\xa0\xf3\x9f\xdf\u007f\x19f\x0f\xe0W\xeb\x00_T\xd3\xd6\xf8\x0e(2\xbeI\u007f\xc9g\xc8G:6\x12aE\\\xd1\u1975a@\xbc\xabW{\x15\xd4e\xf5\x8c`{u;\x84\x9a\x9eq\x027\x12\xe5;0\xff#\x81\xf5ߛ\x13R\xff\x10\x03\xe8F\x16\xddDp\x9b\xfbn7\"\xb7 \xb9R\f\xech\xb1@\x17\n\x84\xa1'$oI\x89߃u\u0080\xb1;\"\x82`\xb1^\xccG\xa8\x8f@\u007f~\xff\xe5$\xe2}\xbe\x80\x8c\xc6\x17x\x0fd\"7\xad\xd5\xdf\xe7\xf0\x14\xbccmX\xbd\xc8IEe=\x9eb֚z-:Wj\x89\xe0m\x83\xb0º\xceb\xbd\xa1a\xa5\xd6\xc2B2\x9c\xf8\x9b\x82V9>뭩\xcax\xfap\xffa\x12\x91\x89C-B\xbe\x93۩$\xa9\x1a\xa4\\\x88w^\xf0ƣK3=\xbe\x8b\xee\xc3\x16\x8aJ\x99\x05F}\x11\xcaNn\xa1\xfc\xf6-q||\xf5\xa7g\xa0\x048L\x1c\xff\xb7K\xf4J\xe5B\xa5z\x85r\x0f;^~V9i\f\x9cAƠ\x9f\xb6\x85\x17\xd5\nlُ\xed\x12ݒp5^Y\xf7Lf\x91\x89kf\xd1\a\xfc8\x94\xf6\xe3\xef\u009f7\xeb\x12\n\xf2k\x15\n\x8b\xbf\x85Vr\x8e\x1f\xbfI\xa9T+^\u007f\x8f\xdd\xce\xfa\x02\xe6p\xaf\x84Ū\xa2\xa2JM@\x9fcO\x04\x13IũcjVf\xfd\xd5]Y\b\xed\x9c Zg}\xb7\x99)\xa3\xe5\u007fO\x9ee\xfcM\fvtU\xf8\xfecz\xffm\x1c\xbc\xa37\xc5\xea\x89B7\xfaHk\xa7Z\xa8,\t݅\xba\xec\xe3\xde\xe2TW\x0eԅ\x9b5\xaf*\f\xbdQ\xad\xaf,O\xef/\xe0\x98m\x16&\f[\x03\xf4\xe5`\x92%\x8e{\xb6\n<\x83'\x8a\xba\x80%\xd6\xf6C5v\x8f$\xd6\x1caD\xeaڀg8X_\x8bPZ2)\xa0\xf6\x11fÝ\xc3\xc1\x9a\xd6ꃑ}O8\x98ܚ\xe6`\"*yU[Ŋ;\xff\x9a\xc6*lH\xcc\xc6\xf8\xe6^L(n\xdf\xdcZ\x15V\n\xc7\xfdWL\xe7\xad|w\xbc#\xbc\xc7p:\xa2cj0\xf4+\x01\a\xac\x94O\x87\fY\x14v\xe4ŭ!\xa7\x8a8ԡ\xac\x93\xaa\xb3TT\xa3\x86\xcdK.x\x92\x0e34\xf4\xb7CUL\x12\xd4yԡ\xf7\x1c\x00}\xbc\xaf\xb4\xaeQ<\x01i\xe33\x11q\xb4\xc2tu\xad\xe65N\x80]w<}&\x80\x1a\xf4^-.E\xd0\xefqU\xec\xf8\xfa-\xa0\xe6\xb6\xe3M\xcbׇROŭ\xef\xbd\xe0umg\xa5\xfc%(\x8f\xb2f\xc8\xe36A}\xde\xe5\xe4A\xd35\xc7\xc7d\xf0\x80\xab\x81ѩytv\xe1\xd0\x1f[&K\x06\x1ch\x022\xf85xǫ\b\xe8\x0f\xba\xc4A\xbf\f*['ﶬj0]3G'D\xcc\u05cc>1\x92R\xc3P\x0f\x1dj\xef-\x93[\t)\xdbEQ}7Q(\x13^)\x89\xff\xb2\x05M\xbe\xad\xd5z@n\xd2$\\\xaf\xe2\xbe\x12G[\x8fIQ(\xe1\x1f\xe6^\xdb\xfb\aP\xf7֜\xa8\x06SȐ\xe1?\xfd\xf1\xccmL\x86qq\x90J\xfby!\xf4\x179\xe5\xeb\x9cp\xe6\xc2\xf7\xac\x1c_\x9b\xf6f{\x8b/e\xbc z8\xdf\xed\xa6\xae\xe3D\xb5\u007f̷\xccQ\x83D\x1d\r\x06\xe4zGv\xffެ\x1f\xd9\xdel\xaa\x90b\x0e\xf5\xc3ᧆ\x9b\x9b\xbd/\a\xe1ga\x8d\xa6\xf8\x99\x04>\u007f\x19A\xff.\xedS\xfa\x1c \x83\xff\v\x00\x00\xff\xff\xb9\xf7H\xe3\xa0\x19\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4W\xc1n\xe36\x10\xbd\xfb+\x06\xdb\xc3^*y\x17{)tk\xd3\x16\b\x9a\x04\vg\x91K\xd1\x03E\x8d\xeci(\x92%\x87Nݯ/\x86\x92bYV\xe2\xcd\x02\xab\x9bə\xc77\xf3f\x86\xf4\xaa(\x8a\x95\xf2\xf4\x80!\x92\xb3\x15(O\xf8/\xa3\x95_\xb1|\xfc)\x96\xe4\xd6\xfb\x8f\xabG\xb2M\x05W)\xb2\xeb6\x18]\n\x1a\u007fŖ,19\xbb\xea\x90U\xa3XU+\x00e\xadc%\xcbQ~\x02hg98c0\x14[\xb4\xe5c\xaa\xb1Nd\x1a\f\x19|\xb0e\xf1\xff\x00\x00\x00\xff\xff\x1b\xa0}D\xf4\f\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec}}s#\xb7\x91\xf7\xff\xfe\x14\xa8\x8d\xeb\x91t\x11\xa9\xdd\xe4.u\xb7\x95z\\ʮ\xec\xa8\xecղV\xca\xfaq9>\x1f8\xd3$q\x9a\x01&\x00\x86\x12s\xbe\xef\xfe\x14\x1a\xc0\xbc\x90\xc3\x17`\xa8}\xb1\aWu\xf1R3=@\xa3\xd1\xe8n\xfc\xbaA\v\xf6\x1e\xa4b\x82\xbf$\xb4`𨁛\u007f\xa9\xf1\xfd\xbf\xab1\x13\x17\xcb\x17_\xdc3\x9e\xbe$\xafJ\xa5E\xfe\x0e\x94(e\x02\xafa\xc68\xd3L\xf0/r\xd04\xa5\x9a\xbe\xfc\x82\x10ʹ\xd0\xd4\xfc\xac\xcc?\tI\x04\xd7Rd\x19\xc8\xd1\x1c\xf8\xf8\xbe\x9c´dY\n\x12\x89\xfbO/\x9f\x8f\xff8~\xfe\x05!\x89\x04|\xfd\x8e\xe5\xa04͋\x97\x84\x97Y\xf6\x05!\x9c\xe6\xf0\x92HPZHP\xe3%d Ř\x89/T\x01\x89\xf9\xd8\\\x8a\xb2xI\xea?\xd8w\\G\xec \xde\xd9\xd7\xf1\x97\x8c)\xfdm\xf3\xd7\xef\x98\xd2\xf8\x97\"+%\xcd\xea\x8fᏊ\xf1y\x99QY\xfd\xfc\x05!*\x11\x05\xbc$7\xe63\x05M \xfd\x82\x107&\xfc\xec\xc8\xf5z\xf9\u0092H\x16\x90S\xdb\x1fBD\x01\xfcrr\xfd\xfe\x8f\xb7\xad\x9f\tIA%\x92\x15\x1a9\xe3\xfaF\x98\"\x94\xbcDZ\x99\x0e\xe0$\x10\xbd\xa0\x9aH($(\xe0Z\x11\xbd\x00B\x8b\"c\t2\xb1\xa2H\x88\x98Uo)2\x93\"\xaf\xa9Mir_\x16D\vB\x89\xa6r\x0e\x9a|[NArРH\x92\x95J\x83\x1cW\xb4\n)\n\x90\x9ay\xc6\xda\u0590\xa3Ưkc91õO\x91\xd4\b\x10\xd8.;\x96A\xea8dz\xab\x17L\xd5C[\x1f\x8e\x1b\x12\xe5DL\xff\x1b\x12=&\xb7 \r\x19\xa2\x16\xa2\xccR#wK\x90\x869\x89\x98s\xf6ϊ\xb62\x035\x1fͨ\x067\xdfuc\\\x83\xe44#K\x9a\x95pN(OINWD\x82\xf9\n)y\x83\x1e>\xa2\xc6\xe4\rN\x0f\x9f\x89\x97d\xa1u\xa1^^\\̙\xf6\xeb'\x11y^r\xa6W\x17\xb8\x14ش\xd4B\xaa\x8b\x14\x96\x90](6\x1fQ\x99,\x98\x86D\x97\x12.h\xc1F\xd8u\x8ekh\x9c\xa7\xbf\xab\xa6\xed\xa4\xd5W\xbd2\x92\xa7\xb4d|\xde\xf8\x03\x8a\xf9\x8e\x190\x02oeɾjGQ3\xda\xfcd\xb8\xf3\xee\xea\xf6\xae)gL\xads\x1f\xf9\xde\x10\xbez\n\f\xc3\x18\x9f\x81\xb4\x93\x88\xd2fh\x02O\v\xc1\xb8\xc6\u007f$\x19\x03\xbe\xce~UNs\xa6ͼ\xff\xa3\x04e\x04Z\x8c\xc9+T*d\n\xa4,R\xaa!\x1d\x93kN^\xd1\x1c\xb2WT\xc1\x93O\x80\xe1\xb4\x1a\x19\xc6\x1e6\x05M}\xb8\xfe\xb0\xe5Z\xe3\x0f^ym\x99/\xb7\xfao\vHZ+Ƽ\xc6fn\x99\x93\x99\x90-\xe5`^\x19\xb7\x88v/Z\xd3\xec\xea7\x1al\xfd/k]\xf9K\xf5\xa0\x91\x1fӉ\x92\xb3\u007f\x94\x80*ήX\xd8P)\x1b$\x89\xef\x1f\x8a\xc5x\xe3\xef[xj\x1a<&Y\x99BZiۍ\xb1\xac\xf5\xf8j\xe3\x05\u070e(\xe3F\xfe\x8d\xfa7\xdd\xe6\xf5_\x8d:\xed\xe81\x95@\x8c\x042n\xe9\x11\xc6q\xb0\x9d\x9c6\x8di\xc8;:\xb7st\x04\xf79:\xcd\xe0%Ѳ\x84-\x9c\xa1R\xd2\xd5\x16\xc6\xf8\xbd\xf9P\xbeT\xcf;\x85\x90\xb1\x04\x9a\x1b\x85e\x8d\xddd\xa8\xdc\xec\x11\xf9\xa4\xb9\xb2\x10\xe2~\x1f'\xfej\x9e\xa9u\x18I\xd0\xc6!SX\xd0%\x13ҍ\xddm)S \xf0\bI\xa9q\x9bߠ[\xa2:\x15\x92\x14B\xe9\xed\\ؾ\x12\x89]\x1cۦp'\v7F\xe6\x14\x87\x9fb3Ж\x12\x11\x1cL_s\xb3\x12\xebg\xa5(\xed\xb3\xebھ\xc1\xf0n\x8e\x90)U\x90\x12\xe1d\xa0\xcc@\xb9o\xa5\xa8\x9e\xeaUv\xbe\x95t5x\xbb\xefft\n\x19Q\x90A\xa2\x85\xdc\xe4\xe4!\xfc\xb4\xed\x10ͱ\x85\x8f\x1d:\xc4\xe9^\xa7\x89\xeb\x81\xed I\x8c\xd1\xf1\xb0`\xc9\xc2n\x89F6\x91\x0eI\x05(\\F\xc6l[m\x1b$\xd97\xf7\xee#\xbb\x16R\xdd\xf6,\xa9uz]\x8b\xabn\a(\x9f\xba\xedQCm\xce\xd6\xf6j\xe7>R\xb7_'c\xbd^\x8d\x10\xda\xeb\x8dW\x8f+\xb4\xe8b\x18\xd3\xf7zF /\xf4\xea\x9c0\xed\u007f\xddG\x91fY\xe3\xfb\x9f\xf1ĄK\xfc\xf5\xfa\x9bG\x95\xf8\x9d\xb3\xb2\x8f\xa2\x99\x95\xea\xf3\x9f\xe1\xa4\xe0fq\xeb\xf6\x8a\x83'\xe4\xbb\xe6[\xe7\x84ͪ\tI\xcfɌe\x1a\xe4\xda\xcc\xf4Z/\xc7`\xc6!\xfb\x9di9\xd5\xc9\xe2\xea\xd1X6\xaa\x0e\xc7\x1cȗ\xf5\x97\xad\x81\xe8-\xe6\xf6Ƽ\x87.Ag\x8eIȭ\x93x\x87ܬ\u007fA\xeb\xfa\xf2\xe65\xa4\xbb\xd8C\x0e\x93\xbc\x8d\x81\\\xaeu\xb6\xf9ig\xf5\x1e:\fg\xfaT\x1e\x84u\xff\xcf\t%\xf7\xb0\xb2\x16\v\xe5\xc4L\x0e5\x1f\xda\xe2Kl2\a\xe3\x10(d\xf7\xb0B2.\xb0\xb0\xf7\xedCE\xc1\xb6{X\x1d\xf2\xd8\x1a\x03M\x9f\x9c\xbbg9i~@F\xa0\x1bz8\xf3\b\x06\x89\xbc.\xda?8r\xb8\"\xf1\xcd\xf3>b\x98մ5\x82i8\xb1'\xcaN\x91Y\x05\vV\x1c8P\x8c\xa5)\xc0\xd5\xe2\xc3D\xefi\xc6\xd2\xeaCV\xee\xaf\xf9vk\xb8\xddn\x84\xbe\xe6\xe7\xe4\xea\x91)\xd35\x9e\x92\xd7\x02ԍ\xd0\xf8˓\xb0\xd3v<\x82\x99\xf6E\\^ܪmÇf\xbc\xe9\x00\xe1\xb6\xedچ\x15\xaa\xe9a\x8a\\s\xe3\xb88~`\xf4\xd0~n\xf7\xfe\xd0ny\xa90\xa0\xc4\x05\x1f\xe1V9\xee\xfa\x92e\xf6\x81$\x85l\xcd\xc8fת\x8f\xda\x0f\x1eH\xf6\xce\xec$\xf6}\x1b\x0f\xcdh\x02\xa9\xf761\x8aG5\xccYBr\x90\xf3]\x1bG\xb3\x15F\xbf\x1fօ\x03\xb5\xaem\x81\x12v\xd8\xd6\xee\x9bS\xdd\xe9\xfeΌ\xcc\xca=\xe0)?\xd9{\x1f\xdd\x12\xbc\xdb\xfe\xe8\xfe\x11\xe1\x16\x8b\xf6\xc7^\xee\xd24œ\x16\x9aM\x024~\xc0\\l\xee\xfd\xb6cv\x87\xccia\xd6\xef\xff\x98m\x0e\x05\xfa\u007fIA\x99<`\r_\xe2\xa1I\x06\xadw]\x98\xa8\xf9\x19\xf3\x05\xa6\x88\x99\xdf%\xcd6\xc3\xc2\x1d\x83\x13F\xb7@f7r1۰X\xce\xc9\xc3B(\xbb\xa7\xce\x18d]!\x9bvc\x8a<\xbb\x87ճ\xf3\r=\xf0\xec\x9a?\xb3\x1b|\xb0\xba\xa9\xac\x05\xc1\xb3\x15y\x86\xef>\xebc\x04\x1d(\x89\a=\xc6;\x83\xbeuk\x89E3\xf0[G|\x9d\x99\xbb\xab\xd7\a\xc9a!\x94\xfekw\xc0nK\u007f&\xfe\x8d\xb6m\xda\x11\xf7\xdak\xb3\xbb\x18V\xa5T\x8d%7\xd3 ]\x10\xcf*Z\xef\x01\xf4\xf4\x8d\xf6\x05\xe9\xaa\x00\x1d\xad\x02\xe5\x86\xc1{\xa4\xc2\x1e\x00\x1c\xd2\xc5\x10\xab\xd1\xf0%\xd0\u07bezl\xc4\x18\xcd\n5\xffn\x0e\xe4\xd8Vm\"\xf2\x9c\xae\x1fy\x1d\xd4\xd5W\xf6M/ӎ\x90\x9d}9/q]\x1en\xeey\x19\xc2î\a\xa6\x17\x8c\x13\xea\x97?H'P\x94\x14b\xbf&\xb2mA\x15\x99\x02pϾ\xbd\xaa\xc1\xb6\xa7ݯsƯ\xf1\x03\xe4\xc5\xd1\xf7wR\xb3+j:=\xab\xab\t\xad~\xc0\x1d\xe7P\xd3H\xa4\xe4a\x01\x12ZR\xb1\x19\xf06\x16\xe3\x81$\xb9\xd0\u0378\x82\xa1[\x88\xf4D\x91\x19\x93J7;z\xa8\xc0\x95\xeaPq\b\x9ca3\xba;\x96\x83(u\xc4\x1c\\\xd5o\xb7N+s\xfa\xc8\xf22'4\x17\xe5\x01\x9b\xbbmf\u007fayu\xa4\xe8f\xe0\x812\x8d\xea\xce\xd0\xc5\b\x8b\x16f\x96\x8a\f\xf4\xa1S<\x85\x99QG\x89\xe0\x8a\xa5 \xfd\x91\xb7\x9dY&\xcc\u009dQ\x96\x95]\xc77]-\xd4M\xe5WRFy\xa9o훍\xa8\xe1B<\xb4\x19t0\v\x16t\t\x84\xcd\b\xd3\x04xb\xe6\x05\xa4U\xd9\xf8\t\xc7\fd\xcd\xc1by\x98\x827\rx\x99\x1fƀ\x11\xael\xc6w\x06Ś\x8f\u007fMY\xf6\x14\xd3f$/~i|_\xbf\xfdA\x96F\xa5T\x0e\xdf¦@\xde\x01MW~}P\xad\x8d\xab\x8a2 \x88,yS#>\xc1\xca\b\xf1\xef\\/\x8e\xe9\xb81\xce\x0e\x98صx>\xd3MkǐxRk\xc7|\xa0\xda\xe8bB3\xd7-\x02f\xab\xf4\x863\xf6\xbd\x92\x9a\x00\xcbg\n\xc6A\x85\xd4\x06\xbd\xcc\xf6\xe9\xech\v\xe4\xd9r\f\xde9\xba\x10\xd3e-\xcc\xeb\x1c\xcd\x06\xf8-x\t\xb8\x00\xefJ\x94\xe4\x81r텾2\xe6\nq\xa0ԇΪmT\xce\x03\x9e\xde@\xd6y\x93\xd5\xc3ۀk\xb9B\xb8ա\x9d\xb6\u0378\xa6\xa9H\xee\x8d9\x92\xd39\x9c\x9c(\xf2\xea\xcdk#*\xc6\xea0[F\xc0\x8e`\x1b\xb3'\xb1\x85\x14K\x96\x1a\xd3\xe9=\x95\x8cN3\xe3\x04\xcf@\x02O@\x91/O\xdf_\xbe\xfb\xf9\xe6\xf2\xcd\xd5Y\x10q\xe3:\xc3cA\xb9\x91\xc1R\xf9ݼ\x9a}3\x00\xe0K&\x057\f\n\xe3\xc6\xf5\x8cP\xb2\xf4\xbdM*$\x9aq\xb5\xb2\xa5\xb3\xe6\x82(V#\xf6\x81\x10ƋR\xfb\xe8\xe8\x03\xcb22\r\xa3X\xf2dA\xf9\xdc\xf0\xd5L^\x83\x8fD\xad\xb8\xa6\x8f\xa6\xdfA\x14\x8d\x99\xab\x12Z@\x8a\xd2O(IEi\x18\xf0\xe5\x97\xe7\x84\xc1K\xf2e\xe3#a\f\xbdrt\x1b\x13\x8fc\xe6\xb0\x04i\xedk;\x95\x87\x06\xc6m\x930\xa72\xcd@)\xa3\xcb\x1e\x16\xa0\x17 ]\xb8\xc6M\x1e\x84Dsm\x13\xd2\xc8m'\x02\xb1\xc6\x1c\x06Q\xf4\xf8\xc4\xfb\n`;f\xe2\"\x15\x89\xba\xd0Tݫ\v\xc6\xcdV5J\xa9\xa6\xa3\x862\xbb\xb0\xbb\xcc\xc8\xed{#\uf84e*1\xbf\xf8\x9d,9g|>\xa2\xd5S\x8c\x8f\xe8H- \xcbN\x02z\x19\xa4\x86m\v\xf6#\x9b\xaf\x85\x04\xee\x03\x1d~\xdbښ\xf2\xaaR\x8c\xf6\xcbcr#\xf4.d\xd7\xf6Vm\r\xc8\xe3q\xa7\uef3a\xb9{\xf7\xc3\xe4\xed\xf5\xcd]\xa8\xcal\xaa\xdb\xed*4N\xf9\xb4\xd4m\x87\n\r\x9b\xfd]궭B\x83\xe8nQ\xb7\x1b*4\x8c\xb1\x1d\xeav\x87\n\r\xa2]\xab\u06dd*4\xac\xbf\xeb\xeav\x9b\n\r\xa2\xba\xa9n\xbbUh\xb0\x1c\xac\xa9\xdbM\x15\x1a\xb6\xb5m\xaa\xdbA\x85v\xbc\x16\xa6B\x81/\xa3\xd5\xe7w\xce]h,\xf1j\xce\xc36W-\xf0\x84\x9c\xf1\xb6\xfe\xe8\xdam\x9f\x96\xf3\xed\x10\x16_\xbe\xa7m\x18\x00o\x0e6\x882\xa9\x97\x83G\x18\xe3vQy`a\xb6S\x8cWa۾\x93\x9e\xee\xb6y\xfe\xe3P\xfe\xf1\xfc \r\x9e\x8c\xc9\x1bw\"Nɫ\x9f\xaf__\xdd\xdc]\u007f}}\xf5.\x8c)$~\xed\x10\x0fr\xe8ɚ\x93\x0ew&\x82/\xbbw\xe4\xe0\x8dζB\u0092\x89\xb2\x06c\xf7_\xb8\xb6\xad\xaf[\a\x80Z\x11\x05rɒ\x98\xbevv\xad\x8f\x01a\xdb^3\"~\xf4{\x8c\x89\b\xc2\xdb=\xb8\x86I\x11A\xf7\xd8~\x9cm\xfb\xbc\xb9\x18!8\xa2Ab\xdb.\xb3\xe45\xcch\x99\x05\xba\x85\x8e\xac Ϟ\x8dC\xac\x02\xf7^Oe\xf5\xb5\x14\a\x86Λ\xad\xa5\xb0nmz\x8f\x8f\x15\x1fG\x9d\x9f8Hdk\x03WQ\xc2\xca\x1cj\xce{=A\x88\xa9\xba\xc5\xef\x97\xc4\x1eF\xce\xd8\xfc\r-\xbe\x85\xd5;\x98ŐXg;\xa2%\x1d\xb0\x90\x88C\x8f\x0f\xd7\x1b\xda\x0f\xb6k1k\xb6/_H\b\x96\xb4\xab\xb5xr\xe7p\xafh\r\x1a\xf6\xc4\r\x89\xf4[X\xbe\xc5\xd9I\xbe\xb5\x8d\x82\x86\xc1\x14M\xb1\xf2\xd8\xf5\xa1.P\"x\x02\x85V\x17bi\xf6ax\xb8x\x10\xf2\xde\xf84f\a\x18ٓ\x10u\x81\t\x18\x17\xbf\xc3\xff\xe9ѻ\xbb\xb7\xaf߾$\x97iJ\x04\x06\xdcJ\x05\xb32\xb3\x80\xab\x831\x9e]\xadN'?ǔ\xe6sR\xb2\xf4\xabpe\xeb\xdb\x11dC\x14\x16\x83w$\xf9\xb8\xc53\xdcU\x8f}\xcd7\xa3\xc2+\x8d`v6\xa6\xd5A\x00\xc8\xed\xcdCU\x9d\xd1ؓ\xedS!2\b\fA\xfbv\xf8\xa1`W;\f\b\xda\xd5\x02\x0e\x0e\xbb\x1a\xae\x80\xe3\xec\x1a'\xf5\xb6q\x18\x90\xb1\xbb9\u05ed\x10\xe9K\xa2ʢ\x10R\xab*U}l\x14AX\\\xaan-\"\x98\xd5uN\xfe\xab\xfa\x11\xb3\x06ԏ''\u007f\xfe\xf6\xea\x87\xff{r\xf2\xd3\u007f\xc5~\xa7\xa6٨2r\fª\x80d\xccE\nFe\x9f\xdb\u007f:/\xe62Ah\xc4M\x0f\xf6(Mu\xa9\xc6\v\xa1\xf4\xf5\xe4\xdc\xff\xb3\x10\xe9\xf5\xa4'I\xa4\xa1\"LPr\x14#`[ɏ\x90֒t_\x1a\xa4\xf7\xa6骈\x18y\xff\xda,\x99\tՋ\xc3\xc1U]\xedA2\xad\x81\xa3\xdf\a27\x1eɹю\xb1\u0383oƉX\xbex\xf6Q\x8d\x9e\x99gё\xa6\x11\xb9\xed\xd4M\x1f\x8dE|\x90Ш?\xefqW8\xba\x1eD/'\u05fe\xe4\xccGd|ߝ\xad\x9a\xb6\x8f\xb1\xbfy\xa8\xf1\xd7O\xb2\xcfy\xea\xfd\xb6\xba\x1aMj\xd1\xf7\x87\xe5pno\x19\xc3\xda4\x94\xa7u}\x9aS\xfb\xe38)\xcaXe\xee(\xe4\x90\v\xb9:\xf7\xff\x84b\x019H\x9a\x8d\x94\x16\x92Σ\xb7\x1f\xdfU\xecb\xfd/\xfb\xb9X\xcd\xdf`\xc1fO\xc3\xce\xcc\x1aT%\x90\xa4\x94\xc6\xdb\xc9V\xdeF\x81\xf4\xa3\xedo\x95\xfct\x17\xc79\xb4\xb5\x85\xbc\x86)\xf7\xf35k\xfd\x81a\x9c\xa5\xc8\xca\x1c\xd4y\xe5\xa5\xf4 l\xe8\x01_\x92%\x95\xea\xa3z\\)[2u(P\xb6\xabQ\xbez\x1b\xa9\x9a\b\xeaX;\b\xc65\xcc{\xb8h\xa3c0\xa3\xd3}t\x85\x03zL\xb6(uQ\"l4\xa7\xba:\xdfy,D\\\xe4ηF)\x17o%\xa1\xad\xf3\xe2Y4тj\r\x92\xbf$\xffy\xfa\xf7\xdf\xff2:\xfb\xea\xf4\xf4\xc7\xe7\xa3\xff\xf8\xe9\xf7\xa7\u007f\x1f\xe3\u007f\xfc\xcb\xd9Wg\xbf\xf8\u007f\xfc\xfe\xec\xec\xf4\xf4\xc7o\xdf|s7\xb9\xfa\x89\x9d\xfd\xf2#/\xf3{\xfb\xaf_N\u007f\x84\xab\x9f\x0e$rv\xf6\u0557\xd1]~\x1c\xd5\x11\x9a\x11\xe3z$\xe4\xc8\n\xc1\xde4\xff]\xcd3\xf7X:靷D\xfan\xbc\xa4i\xb1}D\xd5\xd1״\xeaņ\x9e\x96\x95\x82D\x82\xfe\xf4bζ_\xde\f\xb7\xf9+\x95\xc3\xff\xab\tC\xf7w=-\x9bj\xbf\x05\xcb\xdc\x11<\xea\xeeA\x16\x0fɗXA\xc0}\xe1\x1e\"ND|\x1bB\xe5C\xa8|[\xfb\xb5\x87\xcao\xed\xfa\xa9\xe3\xe4\x18\xed\xee\xb76\x878y\xd4n\x17\xfdr\xdchm5\xe6\xa0W\"{\x18\x89\xca\v=\xda\xefD\xe6\xd5%\xc4H!\x8a2\xa3\a\xe7EV\xfd\xd8D\xe1l\xc2\xf4\x82h\xba\xed\xb5F!\xd5\xc8i\vE\b^\x82\x9b\xa81r\x99e\x84q\xbbI\xe2ǂQ\xb1\b\x11\xb2Q\aB-\xf2oi\xd8\xf0\xb0\x00\x1e\x95Ug\x1bSDi*5\xe3\xf31\xf9\xdeв֘â0N\xf22Ӭ\bD7U\x1eVU\x95\x82P\xa5D¨\xf6\xa8\xe3\xd0\r5\xa3J\xfb)A \x8f\xa6\xf7\x88]L \x05\x9e\x00V1*\x03\xf7A?\xe7ӕ\xe1\xe8\x15_V`\xa4҂s!X\xfbt\xf7\xedc\x03G\xcd\xf2uК\x1a?\x1a\xa8\x141\xc6mi\x88Y]D\xaa:\xdf\r\xa3\x17obW\xe8\x97(7dö\xaeϧ+\xcb8\xe6TU\x8a\xfc\x03\xa3\x80\xe2\xcdܭ&nm\xa8F\xda\v\x9f\x9ay\xfb$\xa6\xed1\xcdڞ&m?sv\x97)\xdb\xc3\xe3\xa9W\xd41\xc0\x1a\xfd\f\xd0\x1eF`!a\xc6\x1e{j\x98K^\xcd\x11a)p\xcdf,\x0e**L\x87\n\xe0\x98\xcd\f4Y\xd8\x02\x88\xbc\r\xb2\x89\x91\xe9O\x00\xebn#\a\xc7Q\xe8\xb7kq\x8eA\x9b\x0f\xda|G\x1b\xb4\xf9\xee\xe6\x96\xd3g\xac\xca?\xa0\xa7\x8c\xb9\xb5\xf1\t\xc0\xaf\x1b\x19\xba\xa8\x11\x9e\"\x9b\xbbZ\xafuI\x8d\v\xfcbز\xc4\xf2\x9f\xb8\xf4\x8c\x17Ymr\xb6\x8c\xbax \v6\x0f\x8d\x88e\xb0\x84\xcc\xd9\xf7$\xa7\x9c\xcem\x11E-\xfcQ\x1d9\xb8\xa0\xafmF%I\x96\xb6Jn\xe1P\xcd\xc6i\xd4T&h\x98,\u05f7\x86)\x92\xb1{ \xaf\xa1\xc8\xc4\xca\xd5J\xe4)\xb9\xd5T\x1b\xb5t\v:\f\x00\x17\xa5\x9e\xcfa\x95\\7\xdbZ\xf5A@\xd1@0\xa5\b߶|C\\\xb00\xe6\x8b\x11\xaa\xba\xb2f\xb5\xd1\xc49\x19Xz\xb6}\x9f\nE\xb5\x89\x15\xb1\xe8\xfd\x81E\xc8ڭ/F!\xa2ZM\xb3\xed(X\x1b}\xd6\xe8K\x9af\x8cC\xb3r-\xc3j\x98\xf1G\x98\xcd\x15l\xf5\x91\xf3P\xe3\x0f\x81\x99\xc4\xdb%V\x8d\xaa\x86\xb6\xef}\xc0\xfcR\bMNO.N\xce6\x0e\xb5N\xe2\xa9\xceX\x06vw\xb5%d\x92j\xb2\xa2I*\x96\x17\xd9\n\xe7\xe7$Ż|\\:\xac,\xe3Έ\t*53˾d\xd19Q\x82hI}}\xf9\xf8\xbe\x1aj\x86\xb8\x96\xa5\xb3UNO~99'\xa0\x93X<0!\x0f\x82\x9fh\x14\xa31\xb9\x13\xa4Tuǣi\xaeDI8\xd8r\x85\xf0Xd,a:[\xe16\x1fMS\x94ږ\xddë\xf1\xb0\x14\xd4\xd5#\xd3.O'\x9e\xec\x8c<\xc7\xd5nM\x05B\x8d3\xb4\x84\x8b\x05\xd0L/\xe2\xf3\xfb\x8c\\r\xc1G\xff\x04)\xb0\xd0\x14w\x14c\xa3;\x11gg\xcdv\x04\xc4IL\x18a\xfd\xedH\x10\x831\x10\xbe\x81`\x93\x93l\xdcEyw7\xf9\x06t{\v\x8bb\x87\xe9\x91\xc7\xe7cH\x1b\xe4LȎ\xcbV\xf7\xb7\xbe\xfb\xdfB\xa8(ΐ͛:\x95\xb6\xf7\x0eX'\x85\xc7ŜmӢ\rKv\x88Fr=\x89\ab\xfd Jí)\x9df\xab\xaa~\xa8\x02M\x9e\x99\xae\xc7Þ\x19\xc7\xf9\xfc+\xd0\x14+\xb6r\xa5\x81F\x9aHGXj\x8d\xbe\x1cǨ\xb17\xae.,\xc9\x1e3\xda,&\xe5d\u007f\x8ck*^M\x1a\x13\x15\xefܱ\xea\xd7\xf5\xf1#)\xc9\r]ag\xc1\xfd>\xed\x85M\xa4\xfe\xe2[;DW\xd57\xb2x\x87o\x8cc7qQ\xf4\xe8]\u007f\x940\xe9\x8dV%]'`\x96W\xbdh\xba\xdc\xcbpX\xdaz;J~It1\xacf{J6a\xf7>>\x9f\xfaA-I\x1c\x10\xb1\xfdz?N\xf4\xccP \xbd\xed-L\xe6\x89N7\xdeL6ւ\xd0$\x01\xd5\xc3Զ\x1b\a*,\x05r\x19\np\xac[o\x11+Dx\xfcҷ^\to\xc7Iw;J\xb2[G\xe5AIx\x99O{h\x92\xaa\x00\x86Ե\xc0\xb8\x89\xef\x11L\xa9\xcaV\xde`\xf7\xfc\x11n\x1f{\x0fM\x18\xca\xe7@^\x98\x9e\xfe\xe9\xdf\xfe\xed\x8f\xff6F6DS\xf5\a˔\x93\xeb˛˟o߿ªo\xb1R\xfe$\x99mX\xb6!z\xffi\x9f\xcc#)ýRa\xa1\xb3>3l|\r\x17\xff\xb6\xc1eկr\x9cmZ\xa0\xba\xf9Hz\xa6\xcf&6\xc2E\xf4\xa1\xfdl\x9d\x14\xb7\"\xb9?\x82\xa7}r\xf7jbI\xd5\xcev\xd4,P\xeeČ/E\xb6\xb47\xc5ݽ\x9a \x83\xe2fּ\x8d\xe7\x03\x18\xea[\x99>\xfaLx\v͉\xa2\xca\xf2\xc2ݕH\x89\x04\x9a1\xa5Y\x82ߪ\x8e)\"\xfd{q\x1f\x83\xe2\xf9d\xe2\n'o=\x1c\bC\fѫy-4\xd1\n1\xf4Q\x11\x8d\xd0DlJ\xd7`\x91\x1c\xdd\"\xb1[\xbd\x90\xfd\xec\xf8\xc1\"\xf9\xb4-\x92\xcfm\x8f\x8c~\xb5\x90p\xabE\xd1\x135a\x89\x1c\t3\xe1\xef \xdb\x06j iĔ\xda[\x83/'\xd7Ut\\\xb4\x80\b\b^\t\xa6\xaa\xcad\xe1\xcff8(u\x81\xf0\x88\xb2\xb0\x91/\u007f\x95`\xf8\x89U!\x01\xef_\x13\xfc\xbc\xaaH\x80\xec\x00n\u007f\x04\x9d\x84\xaf\x16\x8c\xc98\xec\x88;O\xf4\xd3\xd5\x17\x86\x91H\xaa\x16\x80ŕ\xe1\x91i\xe5\xef9\xa6Jp{\x84릏\x89\xf0\x03L\xa6HA\x95\xb2\aw\xba\x1e\x84\xfd\xc8D\xa4'\x11\xa7\xb7\x8d\x0e\x91\xb9\xa4\t\x90\x02$\x13)\xc1\xaa\u007f\xa9x\b\xef\xe7\x14\xe6\x8c+/\xbf\xa6\xa3~a\x18[\t\xa2N\x84\xeb;Gߵjb\xe3EեND\x84\x1ev\xaf;.\xae\x03\x88\x82S'\xb1\x9bf\xf9\x944\xcbV\xf5B\xf5\x99\x9e\xfa\xf8\x93\xb4\x89$\x8aeB=\xeeu$Q\xf8i`\vyd\x96B\x8dJ\xea#\xfe-\xe9dʬ\xaad\xd1\xe3\"*\x12\x0e_\x1e\xa0M{\xdb\x00m:\xb8\rЦ\x01\xda4@\x9b\x06h\xd3\x00m:\x88\xc4\x00m\xaaz4@\x9bv\xb4\x01\xda4@\x9b\xf6\xb7\x01\xda4@\x9b\xea6@\x9b\x0ej\x03\xb4\xe9\x806@\x9b\x06h\xd3\xd66\x1c$\x0eЦ\xdf\xe2A\xe2\x00m\n{}\x806\x05\xb4\x01\xda4@\x9b|\x1b\xa0M\x81m\xb0H\x06h\xd3o\xd1\"\xf9\xdc\xf6\xc8^\xd5\xc5\x02_\xf38\x9e\x89\x14\xd3\x1ee\xc6&xV\xcf\x12\a\x03\x12\xb3\xe8\xda:\xb6;c\xf2\xaa\x05\xcfp\x17\xda\xdb*-A\x14\x1dЧ\x86'\xf5\xad\xd7\x13\\\x93\xc9\x17\x05S\x17\x85\xb0\xff\xaf\xc6\x144\xc0\x046\xbe\x16\xb29\xc4n\xbe1(\x82}\b\x82(]\xb7\x1b=\x80H\x80`\x9a\xc7D\x0e\xf4\xb1nz \x06v\xa0\x05<\xd9(\xe5ڍ\x14X;\U0004f1828\x94\xc0\xe6i\u007f\x1f\xc0\x05B\xe16N\xfa#)V\xe8\x80m\xa7\xfcq&\xb9:\xfe\t\xff\x13\x9c\xee\x1f\xffd\u007fǩ>Y\x892\x8a\xe6\x96\x13}w2\x1f)\x9b\x9d\xa7\xf9\xfeT>\x8ef\xf7I~\xebD>V\x98z\x9d\xe2\xf78\x9c\xeai\\\xc7G\x92\xa3-%\a6\xbe[HP\v\x91\x05\xebږ\x9e}\xc38\xcb\xcbܨ\te\xd4#[Vh\xe6p\x19\xf18'ku\xd8c8C\x98\xa5\x80\x97XR\x96Ŕ\xaa\xc3\xd2z\v\x8a\xf1\tU&\t@j\xf6\xc9\xd7\xf5\x11x0\xcd?\x8e\xab\x91\xdb[5\x98\"/B%\xcf^\xa8\x88\xfe\xdd\x1f\xff\x105\xfb1\x9ea$`c?X\x03)\as\xb2?P\xa3\x8f\xb9\x11\x1bHy\x1ap\xc6\x0e`\x06\xf9!rk\xd8\x01\xca ,n\x9b=\x12 \xa3\x97\xe6\xec\t\xc4\xd8\x01\xc2p<\x8a4@6\x01\x18\xeb@\x8a8\x96ǃ/z\xecmO\x05\xba\xd8\x0e\xb8\x88\x15I\xd2\x1bl\xd1\x1fhq\xc4\xdb\x0ek\xe4@\xef\xdb\xf1{\x85\xe8\x8e\x109\xec\t\xaax*\xb6\x1c\x03B\xf0\x11o\x9f\x8d\x9e\xd5>\xe0\x89\x9e\xc0\x89>\xa0\x89X\xc0\xc4\x0e\xb0D\x9fHsO\xa0D/\xf1\x89=\x8e\x88>\x8a\xe8\u007f\f\xd1\xfb\bb\a \xa2ϝ\xb0\x9dG\x0f\xb1\xf7\x17\xfa\xd6>vX;>\x884\v\x9bG\x0eG=:8\xfa\xb1A<\x88a7\x80\xa1\x01D\x88\xe5\xe1&x\xa1\x0f\b\xa1\x87D\xc7*\xff\xa8C\x95h\xa5\xcd8ӌf\xaf!\xa3\xab[H\x04O\x83-\xa3\xb5\v\x91\xaa\xf5\xaa,9뙇#!Z٘\v\xean΄\xd4'\xd4\xfaӐpՊ\xe6#\xa1xNaF\xaf\xdbٓ\x1f\xf7܂|\xb4\x90\x81M)=\x86\x10\xfcU<\x101\xd3\xc0\xc9)\xe3^\x0e\xc2\xe3\xa8u\xb0\xa0\x8e\x17U\xcb\xda\xfc\xf5\xc5\xf3p\xcde;\xf3\xf9\x06v0\xb4\xa5\xd4\xd3\xc5\xf5\xdc\a\x8e\x1f\xd8s\x84gex\x8c\xbe\x15ܳ\x01¶~\x0f\x9e\xbc\xfa\x1a\xbe\x17\xd8o\xafM0J\xed\xca6D\xd0\xfcL\x85*\x1av\xb6\x17rF\"n\x1e\xdb\x057\xab\xa1c\xc1d\xb7@\xcdj\xd8XxG\xb7\xc1̢ c\x1f=¹\x06\x13\x8bw?\xb7@Ĝy\x16i\xc4G\xc3\xc3\x06?,\xb0퀁\r~\xd8'\xe4\x87}\x1e\x1e\x86f9\x88R\u007fR\xce\xc5Â%\x8b\xa6\xad\xc2rPD\x94} \xef\xc6\nq\xdd\xea\xb4.\x9f\xfa\xea\xa9_\x9dG\x12%q\xa1\xe1\xf9\x8e\x98\xd3z%\xa0\nt\x154n\xaa\b%\xafon\u007f\xfe\xee\xf2/Wߍ\xc9\x15M\x16\xcd\x12f\x9cP\xb3\xa9\x05\xd1D]\xb4\xa0K \x94\x94\x9c\xfd\xa3\xb4\xb7\x96\x92\xd3\xea;g\x1e\xbf\x17D7\x0e\xeb\x17\xb5\xcb\x18\xcd\x13\xa4\x04Z\x13\xf4\x1dSxI\x1cRqP\x18\xa1 \xfc\x02\xe9\xf6\xceC\xae\f\x19ki\xe2.\xb5\x00\tdΖ\x81N\x90\xa1\xea.V\xa4\xa9\a$\xe1\x126\xab\xc7شt*\xca@\xf5\xb9\x00\xc2A\x9b\xd5]E\xc7\x04W\xadzx\xa5\x02\x15\x86M\x9b\x96\b\xc3*$˩d٪\xd9I\x9a\x8dɍ\xf06\xfc*Ԇh\xb2\xf0\xf5۫[r\xf3\xf6\x8e\x14\x12K\x82Y\xbcQ\xf0\xeec\xa6\x97L\xc1L\x90\x9d\xf0tL.\xf9\xca~\xc8\xea\xf2@\xac\x921ځ\x1b\x82\xce\f\xf1\x17\xde>{>\xc6\xff{ffP\x86\x86\x97*hZ\xb2\x01еV\x0f\x9b\x06\xe6\xa0\xe0\xd0\x1b2\xd0\x13\x9f\x1bqL\xbc\x06\xb8t\xe3\x9a\x18\xd6K(읮\xa1\xbb%\xadD\x1a\xa7\x10\x95\xa1Y\u007fY\xb4=\x18\xef<%\xcd!\xf5\xbc\x0f\xbf\xb6O\xbc\xb1k\xe55\xc2VtrY\x88\xf4D\x91\xeb\x89\x17DZ\xbd\b\xda\xec\x04\x11D\x8d\x1c\x1a\x9b\x84\xa5\xb6\x83\xf6p\xe5\x9c<'\u007f&\x8f\xe4\xcf\x11\x14\x8d\xa9\xfc\xa7p[\xb8\x8f=\xd1'\xd0a=\xe5\xebI\xcfy\xfeި1C\xc9̌\x16dʢ\xf0\xb1f\x82\xe1Q\x834ۄ\x93\x98p^\xf6\xf0\xf6\xcc\x10>I\xb1\xb7'8׳Ɲ\xd3D/\xa2\x00\xa9\x95\x03\xb7E\xf0c\xfc8\xf2g'\xf8\xa6\x8b\u007f\x15J\xdf8u\x16\u007fK\xb6m\xda/n\x92S\x9d,\xda\xfaָ\x10Q˾.\xddHR\x81q0\v%^\xb0\b\xac\xd1\xc7[\xbaqЛ\x96\xa4nJT\x1fU\xba\x16\x12\xc0ر\xb3\xcbm\xb1\xd3H\x9dP\x88\xd49\ff\xc8ic\x93\f\xf5\x18l\xdb\xe27\xb8\bG\\\xe2x\x9d\xd4gtaB\xb9\xcdB\x9a\x81\x94\x88R\x8fa\xe9\n\xd1\x16,\x81\b\xb1\xec\xa1\x05\v)\xb4HD\xd6S\xb6&\x8e\f\x9e'\xd8`\xf5\x9bh\xd9\xfa\xdb\xeb\xc99\xb9{59'B\x92\xdbWw\x93~HfB\x9eݽ\x9a<\xfb\x80l\x8d\vN\x8d\xda\xe6X\xe0\xbb~\"\xc3\x1c\xac>\t\x85\xa18\xa7V\x04\xd08!\xa3\x9c\x16\xa3{X\x05\x99\xad\xf1\\\x8a\xe2\xd1f\xa7\xed\xe0sz8\x10\\\x02M\xd9'\x94K\xe9\x14Mݯ\xee\xa4\xca\\,\x03\xe3>\xe8\xb0y\xea\xc0\xd3B0\xaeUW\xa6e\x10\xd9M\xaf\xef\x93A,\f\x99\x96\x1dmȴ\xdcچL\xcb!\xd3rȴ\x1c2-\xbbېi9dZ~Vة!ӲцLˈ6dZnkC\xa6\xe5Amȴ\xdclC\xa6eg\x1b2-;ڐiyh\x1b2-\xab\xf6\xebA\xf8\x0e\x99\x96\x9f*\xc2wȴ<\xa4}\x1e8\xe8!\xd3rȴ\xf4|\x192-\x83ڐi\xb9ֆL\xcb\xcfU\xa8\x86L\xcb!\xd3rȴ\xec\xfe\xeeo\xdd\x0f\x1b2-?U?\xec\xf3\xf00\x86L\xcb!\xd3\xf2\xc3eZJP\xa2\x94I\xd8\x1e\xda\x16\xb2W\"/J\r\xe4\x9d'U-\xb4\xa0\x81OW\x16\xc9\xddH\xe8\xfb\xb0\x97\x18$\x82\xcfؼ\x94\x98>w\x91SN\xe70J\xec\xe0F\x15\x9fFU\xff.>\x04\xbc.c9\vK\xb54\xad\xce[\x9c\xf40\x92\"\xf7\xe4\xbe;r\xcf\xfd\xb8\xa0Z\x83\xe4/\xc9\u007f\x9e\xfe\xfd\xf7\xbf\x8cξ:=\xfd\xf1\xf9\xe8?~\xfa\xfd\xe9\xdf\xc7\xf8\x1f\xffr\xf6\xd5\xd9/\xfe\x1f\xbf?;;=\xfd\xf1\xdb7\xdf\xdcM\xae~bg\xbf\xfc\xc8\xcb\xfc\xde\xfe\xeb\x97\xd3\x1f\xe1\xea\xa7\x03\x89\x9c\x9d}\xf5epW\x8f\xbc\xbf\xb5\x97\xe5w(9\xf5\xa9$\xaa\xef\x9c>\x1a=\x1b.\n\xb9(\xb9\xb6@]\xbbګ\x05aOrC\xd7&\xf9\xc4\xd6'\xe9\xb3e\xbb\x93\xeda\x99\x06\xb4a\x99\xdae\xfa\xce\xc9N{\xa1\x06\xf71w\x06Ԏ\x85\x1a\x05B2\xdb8\xe6\xc7U\xfdd\x8a\x88\x9ci\riT\xceQ#\xab\x1a\xc1\xadMgת\xacp\x9bofq\x99L5\xa1\x9e\x8d\f1\xa1\x17 \x1fXD*\xa3q\xbfx\x1d\xf1@\xd53Ja\xc68\xb8K\x9e\u007f\xb3j/\xea5\x05I)\x99^\xbd\x12\\\xc3cP\xa4\xa0\xbdln\x1d!\"\n\x8b?\xf6\xa80\v\xfe\x0fS\xdf%\xc7L\xbf\xe0C\x8dBd,Y]\xf8A\xe1\x1c\xc0\xa3\xbex\x02+USu_\xcb\x02\x8c\x8c\xbbRO\xf9F\x0f>\x84i\x8a\xfb\xfeD\xb2%\xcb`\x0eW*\xa1\x19\xcah?\x97\xf5r\v\xd5\xe0efX!E\xa6\xc8\xc3\x02\xcc\xfa'Ԍ\x14C)\t\xe5dN#@U\xb9\x99\xab\xc2w\xce\b\x9d\xd1\x0eZ\x91\x82J\xe0\xda\u007f \\'`9\x80\xa9\x10\x99\xcbx\xc8Vu\xffY\\\b\x89\x8b\x9f9<\xfclz\xab\xc8,\xa3\xf3*!J\x81\x8e\x85y\xd4'\x8c~\xa8\xe4h\x13\xc6\x14\ue984f\x0ft\x85Ӷ\x16\xf1\x8a\xa0\xf8\x92\xbc8\xc3\xf5M\x15\xa9\xfa\x98\x92?\x9c\xe1\t\xe9\xab\xcb\xc9Ϸ?\xdc\xfe|\xf9\xfa\xcd\xf5M\x9c\xda4s\x06\x811\xfb\x84\x16t\xca2\x16c\xeem \xbf\x9a\xc4p\xbbJӋT\x8ap\xc81\xf2[\x96\x1c\xeb\xa9Թ\xe6\xfd\"<͢,(v\xb3V\x87\x83I\xce%\xe5x\xa6\xbdZ;\xf0\x96%\xd7,\xff\xa0IY4ퟐu\x99\xa6\x90\xf6c\xc9\U00070b2f|7VuM\x98(\xaa\x84L\xde\xde^\xff\xbf5\xd9\\\x15}\x00v\x1f!\x97\x84\x10\xb3\x90z\xcf\xf1;\x9b\u007f:\xcc\xf2\xce\xf6\xf9e\fUv@?L\xc1\xbb\x92\xb7+\xca\xd5t#\xec\x93\x14\xc6db\xb7fPmj\r\xa5\x1e\xae\xeb$\x10C\x92kF\xb3lE\x8cg\xb8\xa4\x19\xd8\xe4\t)\x02KՑ\xf5\x1a1Ml\u008cf*X\x91\xc7\xef\xc6Ɛyc\x9c\xe6^\xb3XQ!)p\xa1]\xb8-j5\x88\x19R#֓o\x80\xfdZ;^\x94\x91Yo\xc6Ly\x9eO\xaa\x9e\xe3)O0\xd5R\x81\xeaތ\xe3o\x957\xa3\x95@S\xcc\t/\xa8^X\x9cIN\xd5=\xa4\xf6\x87H\x1b\xdb\xc54l\x8f\xab\xa1߭\n 3\xa0\xba\x8c8rB\xdbڢw\x80\xd3i\x16\x1e\n\xedQ\x9e\x83\xa6oy\xb6z'\x84\xfe\xbaJC\xee%\xc8\xdf;o\xa9}\x16\x13\x0e\xb0\xc0ʙ\xa6\u007f#\x9cDL\xbbnfJ;\xe9\x8b\xf1\x12>\xb0\x82\x90%\xbfT\xdfHQ\x06\x9b\x02\x1b\xc6\xfa7ׯQ_\x96V\xf7\x01\xd7r\x85\xa5%b\x94D{\xcdU\xfe\xd8\xdf\xcczt+0\xdc\xe0\xf1\xeaaFJ\xae@\x8f\xc9\x1b\xba\"4S\xc29\x8e\x11\a\xb2d\x82(\xc9f\xdcgL\xb0\x86\x13\xe8\x98̦\xa9\xd0\v\xb2F\x10\xd5\xc3\xe6w\xc2\v\x10\x18\xa6\xdaC\xe8*~h\x86\xb0F7\x9c,\xbd\aE\n\t\t\xa4\xc0\x93`\xe9m\x9c'\xff\xe9_?\xd0y\xb2\x93\xfc\x1b\xc1\x8dz\xe9%\xfb\xd7\xa1\xfb\f\x96\x10Q(t\xfd\x1e\x03C\xc58\xa4^j\x90lT\xf43\xa3SȬihW\x8e\xda\\9\xd1Q\xd1Ƞ\xaa\x14Y\xff\x94\xd5w\"C\x9d\xc9\xd8)\x1e|\x95\xfa\xb3+\xf3Ÿ\xee\nW\xea\xf2Mu\xad\x81a8\xf04\xb6\x92CA\xf5\xe2\x9cH\xc8(&%;\x85vo\x03Z'q\xf3\xd4\x18\xb0\xd7\f~\xe2\xd0\xcef\x82\xc7%\xa1\xe1\xa8\xf1X\xc0[\xc43ԁF\xc1?\xfb\xce\v[D\x9d\xf3Oa7\u007ffGRE<\xe3N\xd5L\xbbg|\xe4\xce\x1f\xac\x1d\x85\xd7x\xc0\xe6\x88\x19\xcd趴X\xc7g\xf3\x90n\xe3\xd0-\xce\x03Z?\xa8\xf3NPt\xa0hǁ\x1da\xe1\xb1zb\x0fƏzhG\xb6\x1c\xdc\xc5\x1fa\x93\xa7>\xc6&Ow\xa4@\x8ep\xac@>J(/.\x99Ζ\xdd\xeay\x17\xd3m\x83J\xc3m\xd5\v\x1a~\xc5\xf1D\xa4\xb6\xf4`U\xba\f/%ƒ\x89쟡\xc0\xc8\xf65\u007f\\\xd8<\xcef=Bw\xf9L\x98\x97e\xfc\xb5\xccG(\xf3\"3\x16B\xab\xc7\xc1\x90\x17\xa4ո\x14\xea\xbcbF}\a\x95\xab\xc6\x18\xb6^\xfe\xbbT\x9a\xd0\xea\xde)_tmR}ʆ\xb8\x02/\x1eq\xd7\xfcaeq-|P\x95\xa4l6\x03\x9f\xc6\x16\xe8e\x17T\xd2\x1c4HE\x1c\xbek\nsfs\x89ČPÌ\x93\xc00TU\x8d\xe5\xdc\xe6&1Mr6_XS\x9cP\x92\t>'\xc1(G-H&hJP\x8b\vI\x1e\xa8\xcc\t%\tM\x16pn\x13\xfa\xd22x\xe1c\xb9\xff\xd5Hi\xaa\x8d+\x056[\xd7]\xf3\x9b\xf82&ab\xeao\bC\x1ax\xf41\x05M=L\xd9c\x8d\x83h:\xab\xb2\xb5\xe4=\xbdYF\xe7\x11Ew>\x81\x82;\xc3\xd5e\x1dm\xb8\xbalk\x1b\xae.\x1b\xae.\x1b\xae.\x1b\xae.\xebn\x9f_\"\xe2pu\xd9pu\xd9pu\x99m\xc3\xd5e\x11m\xb8\xbal[\x1b\xae.;\xa8\rW\x97m\xb6\xe1\xea\xb2\xce6\\]\xd6ц\xab\xcb\x0em\xc3\xd5eU\xfb\xf5\x94\xcc\x1f\xae.\xfbTK\xe6\x0fW\x97\x1d\xd2>\x8f\x8b\x05\x86\xabˆ\xab\xcb<_\x86\xab˂\xdapu\xd9Z\x1b\xae.\xfb\\\x85j\xb8\xbal\xb8\xbal\xb8\xba\xac\xfb\xbb\xbfu?l\xb8\xba\xecS\xf5\xc3>\x0f\x0fc\xb8\xbal\xb8\xba\xec\xc3]]\xa6tʂ.\x1b8\xa0\xceeL֞\xaf:C(\x99\x96\xb3\x19H\xb42\xb1w^I\xc5!\xdb}Ms,j\xe7@\x80ƲQ\xa0ϱ\xb4\xa6\xcd\xd6\n\xf3):\xbb\xe5\xcb\xe7`\xe1}\t*\xb40'\xe3\xe4\xea\xed\u05f5\xc3\x16S\xa43\xae\x8e\x18\x8e\xe7-O\xe2\x01е t\xd4\x15\n\xe3\xad\x05\xef%\x99P\x16Mf\x99\x9d,(\xe7\x909φ\x85qvA\x15\x99\x02p\"\n\xe06/\x88\x12\xc5\xf8<\x03B\xb5\xa6\xc9blF\x10fy;!p\xf7-\xd4=UZ\x02ͭ0H\xc8Co\xc80]$4\x91B)\x92\x97\x99fE\xd5I\xa2\x00\x93\xbc\x02\x0f<\xafg\xf5\x04#\xc0\fЬ\xc0\n\x8f\xd5(\x82\xfbh\x13\xf8\x1bk\xde\xf8\x80\xe7x}P^\xe8\x95\x05\x88\x87m|\v 3&\x95&Iƀk7j[Y\x04\xfbyNBqu\x1a\xefc\xc0YP\x8e\xb5\x86C\xbb\x14Y\x99\xc3kX\xb2>\x97\xb2\xb7\xa8\xf8\x9c\xa9\x8c)MDXj\xeb4\x13\xc9=I\x1d\xa1\x06\xaes\xfd\x06\xb6\x10\xceD X\xb7\x8e\xaeqonh\x19\xed\x9c\x16E\x95\xa0*\xe9Ck\xb0\xa8K\x82\xc1\xab46\xc8\x1d\u007f\"d\xbb\x1bj\xb0\xfbw\x1b\\\xad\ty\x81)Bw?\xdb\\\xd6\xd6F)u\u007f\xf7C\xd49\x85\x9b\x13k\xa7\x99\x99C\xcd\x1c\x1e\x9a\xefq`\x12\x87\an\xf1\x98W\xe7\f9\xd5Χ\x89<{C\xa9-@*\xa6\x8c\x01\xf3\x1e\xd7ī\x8c\xb2<>;0\xa6\x94f\x8fˋb\xce4F\r9\r|1\x98ѽ\x8a9\x84\xe1b\xadJ\xc3˨\xe2\xb5\xfeD\xa4\x8e\x10\xaaj{\x81\x98qe\x83\xc5a[\x92h/\x83\xa3\xaf\xda\u007f_\xf3\xa8\xa9\xf5\xed8×3. K\xd3)\xfb\x8f\xa1\xbe\xb1\xf3G\xd0ި\xb7\xdd0\xfa\x16\xd3i\x06l\x9c@5\\/\x17#\x19[\\M\x04y#A\xae{\xe4\xe4\xe5\xc9\a\xd5\xe1\x96\xddR\x14t\x1euY\xf5\x1a\xd7\xd7ɑ\x14\xac\xab\x13\x95\xb4b\xdcd\xa4XU;F\xba\x90VU\xf9\xa2\x88\xdad\xbcz\x1f\xf6\xee\x13\x96S\x89\xa0\xf8@W\x84JQ\xf2Ԟ=ԇRo\xd6\xd8q#xL\x97\x99\xaa\xaa\xf7\x1aÛA\x86y\xffX\xfe\x82q\xf2b\xfc\xe2\xf9\xe7\xb6\xf1\xe3H\xd66\xfeȒe\r\xbd\xf5A\xb9\xe0/\x1b\xecɉ7.\xc4Z\xdf\r\x18UK˞\x01!\x91\aɴ\x93\xe6\a\xa6\x80\x9c\x86F\xcd}\x13\xb2Y\xa0\xeb\xec\bג\xf6\xb9\x1e\x89\x10UN\x9f`g\xb0\n=\x82=\xa8\x84\xbab\xf1*\x9efǶ\xd2d\xfa\xb3\x98\x1a\xb5\xa7\xb67'\xb6b\xc6\xd9\a]$nʮ\x1e\x8b\x88;\x0fZ\xd3v\xf5XP\x8c\xfa\x17\xf5\xfcŬ\x93z\v\xdf>\u007f\x11t\xb7\x9b\x05\u007f\x81\x05]F\xed\u007f\x8a\xe5,\xa32[\x99\xa9\xbf\xb5\x9c$\xd3R\x13\xe0K&\x05\x8fBn\x12\xb2\xa4\x92\xd1i\x06D\x02\x16\xb8J@\x91/O\xdf_\xbeCtWL\xd1\x0f[{\xcc\xcdO\xa9\x18\x9f\x1f\x81\xa3\x8dA\xae/\x82Z\xa4#\xe8\xdaE\xe0\xf9i$\x13-\x00\xcf_\x1a\x01U\"$/uio\x82~L\xb2R\xb1\xe5\x87܋b=\xc7\xca\xd6\xfe\x159\x8e\xae\xdc\xd0k\x16\xa4o\xd6J+Պ|\xa3zQ0`\x03\x8d\xc1\xbal_'\xac&P\x8e}i\xf5f=i\x17Pw%\xe1l\xfa\x81\xbb\xad \x14\xba\xb4\x866\xc8\xe9\xfc#\x84\xd6Ce:H*\x83\xe51L\x12\x1d\xee\U000f0bb7\xcdb\xfb\xa6\xbb-\xc0F\x1ds\xfa\x88\x80J\x8a\xcb\xf5\xc0\x11\x8a\x19\xf6\x82\xbc\x87\f\xa4\xf0\xdb\xd2\x03e\xba\xcaUa\x9c\xe9W\xa1W\xe0\xa3\xe3d\x8bD\x1e&\x00AS\u007f\xf0\xbc\x1c\xf8\xe0\xfei\xdb'f;\xc5jo/v}\u007f\xc7ˌ'Y\x99«\xacT\x1a\xe4;P\xa2\x94\x9d\xa7\x1fk\xa7˝o5\x12R\x1e܁Sb\x1f\x19\xa9D\x14\x9d\xeaA\xd6/W\xf6\x8c\xebT\xea\x93U1\xb7\x89\xbat\x15W\x15Di!aK\xb9P^f\xd9ZB\x84,;\x84\xc8\xd21B;\x97\x16\x84\x8a\xb8,<\x9d=Gp\x05\xaf\xbf`\xb3/\xed\x877\x87\xbf5(\xb8s!\x1dĴ.9\xf4\x1d\t\x14\xb2\xfa\xf95\x86y\xc99\x84_\x9bb\xd3\xe4X-\x83\xee\xb9)M\xee\xcb\xe2\xd3b\x1fޝv\v\x19\xda\x06{X\xf7]\xf3Y˶\x1c4]\xbe\x18\xb7\xffb|k\x96iD!w\x9af\x0f\x16\ti\xb8fL\x13\xc6S\xb6diI\xb3\x96\x046xV\xb3\x16\x93YX\xd6\x05\x90\xc2rz\xee\xfd\x16\x8f\x89\x87\xaf\x05\xaf\xd5\xddQ`\f\xfc\x18\xf3\xdbAa\xbbUp;\xbc\xb8\xf6\x8a\xe5\xa2;\xc7u\x17\xd9)\xcfG\xa7ڍ\xff\xb0\x15f{\xe7\x8a\x19\xf9\xe7p\xe4\x977\xaf\xb7\x997;C\xf6\xad\xae^\xee\xe8\x8e[3Մ\xef*-\xed\f1e\xf3)\xd49\xa1\xe4\x1eV\xe7\x16\xfc\xca]m]G\xc4\xdew\xe5̆{\xd8n\xaa\x98\x97-\xbdm\x8c9$\x80\u007f\x0f;c_-v\xdcê:vG\xbe\x98\x1f\xaa\xcb\xef+V\xb8\v\bw\xef\xfd;O9\x0f\xb27<\xd7\x0e\xee~\xc5f\tF\xf8\xac\xa8\x981\x9c(wɘ\xe0j\xc1\x8a}\xe0\x18\x8a\x90m1\xf3ܯ\xae\x9d\xb2\xe4\xad\xfc]\xf3sr#\xb4\xf9\x9f\xabG\xa6\xf6$䘹|-@\xdd\b\x8dO\xf7f\x8e\xed\xda\xc1\xac\xb1\x8f\xa3Hs\xab#1I\t\xbfQ\r\xf3z\u007f\xee\\\xc5b\xa6\xc857\x8a\xca\xf1\xa0*\x8e\xaf\x1cy\x9f\x97\xc6\x05\x1f\xa1V\xdbm\x89\xdao\xb7\xe8[\xb6\x9ao49\xd7\xfc\xd4n\x96\xb7\xbaa\xbb`#\xda\xf6/\b\xd0.2\x9a@\xea\x8ag\x9b\x89גj\x98\xb3ݥ\x8bs\x90s\x04\x1a$\x8b]\xa3:\xe0\xe8\xf0@\xc3\xfb\x18&\xf2vU3\xaa\xd8\xfe\x14&\xb4\xdbCp\xfb\xdc\xc2\r\x9a\xfa긓\xbd\x1am/\xc76\xf7\"\xfbi\xb7\x99\xd3\xc2H\xfe\xff\x18\xf5\x8cB\xf4\xbf\xa4\xa0L\xaa1\xb9t\x19*[\xbe\xdb|\xc3\xd9:M\xe2\x86.S\xc4\xcc\u0092f`\x8b\x1cRN`g궘m\xec\x96\xe7\xe4a!\x14\xee\f\xf5!ҳ{X=;o\xad\x90-\x14\xcd\xc3\xd7\xfc\xd9yu^\xd6Z\x94\xd5>\x85G\x18\xcf\xf0o\xcf\xc6\x1b\x1b\xec\x16\xda{\xb6ݝR\xb2㏕\xd5\xfd\xc6B\x9b6g\xfeP\xf9\xd8)\x1b\x1b՛\x9a\xdfl\tG\xd38n\xb9\x15]\x9f\xa4r\x0e\xba\xcb\x05q\x163B\x19\xc6䒯6\xe8bb\\\xa7\xc9휸JΊ֝\fB:\xb0\u007f\x93\x94\x03.\xa9nG\xd8<\xb89k;&\x057P\xb9\x84\x1b\x91\xc2D\xc8.|G\xfb\xbcf\xfd\xf9\x0e\x8f\xb6\xc1\x14\x91\xa5\x88\xb3\xc7G;\xfa\x8b\xb6\xb1\xb3\x8b\x8f\xe9|\xba\xefO\xde\xef\x1bϻ\xea\xc1\xdd\x03\xa1X\x97\xdb\xceW\xc78\xcc\xfb6׆\xd3B-\x84&\xa7KF]F\x93(Sw\x8d\x85\xec8\xef\xe91J\x95, -3\xe8\xbeIi\xa3ĕ\u007f\xd4\xdb~%g\xff(ۗK\xf9\b\x95{\xbak!\xd4<\xa9\\\xebFDը\xa3\xbf\xe0|\xfa/9/\xd2Q\xde\x02\x85o\x92\xb4kA(\x8dyJ\\7\n\xb6x\xb73q\xa5\xbd\xdd\xe3\x9div~\fۖC\x87\xfa\xe8\xde\\G\xee\xab\x1b'\xe2[\x96\x95\xc5ҷit\xc9ܭ\xc5\xdc'\xb4Х\xf4\x17\xb7\x95\x12/9\xa9˟S\xcf9Ǣ\x16\xd9펁\x8b\v2\xc1\xefX\x0eJӼ\xd8#!\xaf6\xdf0\x13 dj\xbb\x86\x11\xccF\x88\xa0\xbeI\xa4\xcb+\xa6\xf5\xfd5\xe9\xb8AےA\x9b̐\x86\x94\xc0\x128qI>x\xf2n\x03\x10\x1dD\xed-\xe0r\x89g\x01\x9e\x0e\xe2}gB\xda{C\xaa\xaeoJ\x84O\x1dO\xa9\x86Qg&\xe1A+\xb1s\xd7A\x98\xfe>U\x83\xb9\x0f\xce\xf3\xc0\xa5\xfa=\x80\x042\anXܩq\x9c)k\xaf\x890\x8cu+\xb8\n\xe0\xdcٛ5J\xea>`ݙjW\xd9\x1a2\xc3G:\xb3\xacv%л\x8c\x8fw@U\x17n\xa9ň\xaf\x9b\xcf:_\xc5\xf2\x00\x87\x9eP{\xf9\x8f\xbd\x86\x8dI\xe8\x14}\xd7%\x81_\x0eX\xe3\x84\x14\v\xaa\xf6\xa9ˉy\xa6\xbaΣ\xb1(+M\xf9nK\x9f\x80\x97\xf9&\xf1\x11\xb9\x81\x87\x8e_\xbfF\xa1G\xbf\xb3{)\x8d\xc85\x9fH1\x97]\x15\xe6F~auHȈL\xa8Ԍf\xd9\xea\xeb\xeeJ\xf6\xfe\xebA\xbcs]\xd9k%\xd8\xc7jC\x94q\xbb\xfe\x8c\xa4\xd2)\xde\x14Q\v뉪\xe5\xb8c\x92\xfdG\xc7\xc6\t\x05\x1f\xa8`m\xa2\b\xc1Rz\x04\xb3\x99\x90\xee\x02\xefш\xb0\x99ӟ]\xc6\ae\x19\x9ap\xf6\x10\x8d0];\x88Ն$$\xa1|E$\n+^\x1b\x92ӕ\r\xc1\xd3$)\xcd\xf2\xbcP\x9av\xed3\xbd\x02r\xe8T:!\xdb\xe2\xed\xb5c\xc1\xcd\xe7\xab{#\xab:%HβnA\x97^3d\xdb\\E\xcc\xea\xaflPeVY\xb7'\xb2\xaf\xa8\x06\xe6D^ow\x90\xdb\an\xd5\xc3~\x006\xa5rc\x18\xa2i\"o\x0f'2\xe5_5s\x96,\xb0\x1a\x8f^HQ\xce\x17^\x04\xb7)\xd0ma\xc5\x12\x93~\x8b\xac\x9c\x1b\xb1v\x81>]J\xde\xf0^\\\xe8/\xad\xbb\xbb\x8b\xe8n\x16\xee\xb0\xddUk\xc7\xdbg\x00\xb6\x1e\uedf3W\xe9\xee\x9f\ue3bc\xacT\xea\xd5!{\xf3\xfb\xb5\xc7\xd7\x0eR\xcc.]St\xfbi\asN\xd9\xccFM\x13\xd3\xebM\xf0\xce\a>\x10y\xa0\x923>\xdf7\xf8\xef\xddc\x1d\xa6\x89\xa3\xd0a\x9ct\f\xa22W\x82\x8c\x13\xdf\xc9-X\x9f\xca`\xe9a\x9et\xae\xa1\x8d\x1fQ\x90\xd3\x06\x93ݗ\xdc/\xb5Yo\xcb\\\xb8\x83J\xcb\xdb{\xc6ӗ\x1e\x10Xd\xa5\xa4\x99\xfbg\"\xb8U\v\xea%\xf9\xf1\xa7/\xfc\x80ރTՏ\xff?\x00\x00\xff\xffA@\xab\x06\x18\xcd\x01\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xec\x1c]o\xe4\xb8\xed=\xbf\x82H\x1f\xb6\x052\x93[\xdcK\x91\xb7\xbdl\x0e\rn\xbb\xb7ؤy)\xfa\xa0\xb19\xb1\x1a[r%y\x92i\xd1\xff^\x90\xb2\xfc5\xf6X\x9e\xcd\x02\xd7C\xf4\x92\x8c-Q\x14I\xf1K\xb4\xceV\xabՙ(\xe5\x03\x1a+\xb5\xba\x02QJ|q\xa8\xe8\x97]?\xfdٮ\xa5\xbeܽ?{\x92*\xbd\x82\xeb\xca:]|E\xab+\x93\xe0G\xdcJ%\x9d\xd4\xea\xac@'R\xe1\xc4\xd5\x19\x80PJ;A\x8f-\xfd\x04H\xb4rF\xe79\x9a\xd5#\xaa\xf5S\xb5\xc1M%\xf3\x14\r\x03\x0fS\xef~X\xff\xb8\xfe\xe1\f 1\xc8\xc3\xefe\x81։\xa2\xbc\x02U\xe5\xf9\x19\x80\x12\x05^\x81M2L\xab\x1c\xedz\x879\x1a\xbd\x96\xfa̖\x98\xd0l\x8fFW\xe5\x15\xb4/\xfc\xa0\x1a\x13\xbf\x8a\xbbz?\x03\xb0\x89.\xf1\n>\xd3T\xa5H0=\x03\xa8\x17\xc6S\xafj\xd4w\xef=\x8c$\xc3Bx\x9c\x00t\x89\xea×ۇ\x1f\xefz\x8f\x01R\xb4\x89\x91\xa5c\xf2\x04\xf4@Z\x10\xf0\xc0\v\x04S\xb3\x02\\&\x1c\x18,\rZT\x8ez\x94\x06W\x01ô\x01\t\xa0\r\x94h\xa4Ne\x02?\x89\xe4\xa9*\xfd`\x9b\xe9*Oa\x83`*\xb5n\x06\x94F\x97h\x9c\f$\xf4\xad#2\x9d\xa7\x03\x8c\xdfѢ|/HIVЂ\xcb0\x10\x06Ӛ\x0e\xa0\xb7\xe02i[\xfc\x99\xfd=\xc0@\x9d\x84\x02\xbd\xf9'&n\rwh\bL\xc0:\xd1j\x87\x86(\x90\xe8G%\xff\xdd\xc0\xb6\xe04O\x9a\v\x875_\xdb&\x95C\xa3D\x0e;\x91Wx\x01B\xa5P\x88=\x18\xa4Y\xa0R\x1dx\xdcŮ\xe1\xaf\xda H\xb5\xd5W\x909Wګ\xcb\xcbG\xe9\xc2VItQTJ\xba\xfd%K\xbd\xdcTN\x1b{\x99\xe2\x0e\xf3K+\x1fW\xc2$\x99t\x98\xb8\xca\xe0\xa5(\xe5\x8aQW\xbc]\xd6E\xfa\x87\xc0Q\xfb\xae\x87\xabۓ|Yg\xa4z\xec\xbc`\x81>\xc2\x01\x92l/0~\xa8_EKhzD\xd4\xf9zsw\xdf\x15&i\x87\xd4g\xbaw$\xace\x01\x11L\xaa-\x1a\xcfĭ\xd1\x05\xc3D\x95\x96Z*\xc7?\x92\\\xa2\x1a\x92\xdfV\x9bB:\xe2\xfb\xbf*\xb4\x8ex\xb5\x86k\xd6\x1f$\x87U\x99\n\x87\xe9\x1an\x15\\\x8b\x02\xf3ka\xf1\xbb3\x80(mWD\xd88\x16tU߰\xb3\xa7Z\xe7EPS\x13\xfc\n{\xfc\xaeĤ\xb7eh\x9c\xdcʄ7\x06l\xb5iU\x80\xedj\xb3\xd0\xc6w-Ԫ\x87\xba\x0f\x9f\x1f\xd56\xd7F+\xc0\x17\xe2}\xbb\x9bIv\x9e3T\xb4\xc3L\xa5\b\xcf\x03\x98P\xab\x98\xf5\xc1\x9b\tj\xf2+,Jڮ3(\xde\xd7\xdd\bE\xa2Qژ#\xafP\xb0Qo\xba\xd6jp\xa0Tx\xba\f\x89^;\x99\xd6Z〚\xc7)\xea\x11ۊ*w\x0f:\xaf\n\xb4\xf7\xfa+Z'\x93\xb1\x9e\x83E|\x1c\x1d\x18\xf8\x8d\x96(\xec24\xb49\xf9\x05\xeb\xbbQ\xb8\xc0{\xc6b\xca*O\xda5\x99,\x17P\x80\x146X\xe4\x1d\x16\xf2\xb1\x0f\"\x97i3\x19\xef\x93\x05\x10o\xd5\x05|֎\xfeܼHK(\xaa\x14>j\xb4\x9f\xb5\xe3'ߕ\xc4~\x11'\x12\xd8\x0f\xe6m\xa9\xbcY \xba,\x9a\xbfŁM(\x89h\xc36i\xe1VQ|\xe6鳄M\x19\x06\xe4\x91e?\xde=n\x95l\xde\xd9\x1f\x8a\xa2\xbeHSN=\x8b\xfc\xcbB˲\x90_\x87>\x88Gһ\x1f\x85\xe0d\xef\u007fȼ\xb2x\xff7\xce\x1a\ni\xec\x1a>\xf0\xe1f\x8e\xdd\xf1!Kؙ*\n$a\"-\x90\x9c\xecDN\xee\x03)o\x05\x98{gBo\x0f<\xa88\x15\xf3\x9ci\xebm\xfeVbΧ[\xe7O\xb8?\xbf8\xd0^\xe7\xb7\xea<\x0e&\xe9\xfc\x03\xa5\xd5x-Z\xe5{8\xe7w\xe7\xec\x98-\xd9\"'8o\v\xa4:\xba+\x1f?/\t\x05(\xd6\x0e^\v\rn\x0eiɅ\x9f[E\xb4L\x97ںEh}\xd1\xd6\xf9\x04`\xcf\xdd\x1e\xc9\x10\xc6D\u007fu\xd6\x10\xc4֡\x01\xeb\xb4\t\a\xa2\xa4v\a\tr⼝\xe7=\xb1\xba\xc9Fz\xc0\x14d\x9e\xb7\x1a\xc2\xeb\xf4s\u007fRJ\xff\xcf\xc3L\xd8Ybإ\xd1\tZ;/J\x91\x96c&a\xdb$k\x85\x0f\u07b6Q\xaa9&\x95\x1c\xda2W\x9cH{B`s\xf3\xd2\xc9;\x93\x1a\xa2\xdf1\xa2|\n\x8e\xc0E/E!\x86\x87\xf3\xd1\xe8^\xfb\xd1a\x03\xd6\xc0|\xc0d\x1e+V*\xcb\xfc\xe6Z$\u007fk\x8eG!\xd5-O\x04ᅴ\xb3\x02A\x95㩡\xccu\x18\xdf2\xa4y\x10\x1b\xbfB8j\xd6|Vc\xb0\xc7\xd9Ó\x8cxN\x019\xd3J\xbbn\xb2\xa6\x9e靅\xad4ֵ\b/\x80*-\x1f'\u007f\xdf\x18S\xdd\x18sr\x88\xf9\xab\x1f\xddI+f\xfa\xb9.\x8cX\x12X\a\xe2gb\x87 \xb7 \x1d\xa0Jt\xa58\xe1EꂦY\x00\xd13\xd1\x1b\x93H\x9b\xd9\x19\xac\xaa\"\x9e +\x96N\xa9f\xb3c\xdd!?\v\x19\x97\x9d\x82\xd3\xd8\xead\x81\xba\x9a5\xedm\xebWv\xf8ѽ\n\x98B\xbcȢ*@\x14Ė%q㖱i\xcae<\xaf\x9f\x85t|\xe8G\xb0\x89=˴i\xa2\x8b2G\x87\xb0\xc1\xad6\xac\x0f\xacL\xb1q\x1fj\xfe\x8f֛L5\x01[!\xf3\xca,\xd0ы9\xb34n\xab\xd5\xd3\xeb\ac\U00048b18\x98\x91I\xf7\x05N\xf3\xbc\xfd(\xcd2\x97\xf9\x8b\xc1\xd7wMK#IJ\xf5\x9cw:\v\x93\xbd\u05fewZ\v\xafP\xfb)\xf7t\x16*c\xf2\xe6\x9e6\xed\xcd=}sO\xdf\xdc\xd3A{sO\xdf\xdc\xd37\xf7t\xbc\xbd\xb9\xa7\x9d\xf6\xe6\x9eFۏ\x18\f\xfdWGG:Da\x15Y\x821\x87\xf6\xcc\\u\xa5\xd1u^Y\x87fI\x85\xf4\xed\xf8ȑ\x1a\xfa\xc4wY\xf1\xd7ZSRӖ\xae\xb4F\xaf)\x99\xa6-\x196\x93\xff\x16#\xc2\v\x8f.\x83\x9e\xae\xb6\x8f-\xa0\x9b+\x9b\xeb\u05ce7\xe5j\xfe\xbf\t\x828\x1d\xa6\xaf\xb9\xe7\xbf\xf1\xe9\xd6\\\xf5k\xdf8\x0e\b\x18\xff&\xeb\xca#\xcb\xdaf\x8aَ\x17\xe2OY\xf8@\xcb\xc1\xe1B\x9f\x98\xa6W\xf8\xfd\x9b\xa6eD\xb5\xd9t\x8dY}j\x89N\xecޯ\xfbo\x9c\xae+\xce&V\xf6,]\xe6\xbf?\xa2\xd0U=v\xcbڃ\x9c\xd6\xdf\xfe\ri<\x01Q\x1bP2\xf7\f\b\x10z\xe4\x87_K\x1f\"\x9f\xbc\xcf\xe7\x03\xb5\xf8\xba\xb4\xa5\xd5hM\xfdмU\xf9\x86\x1a\xb4e\x1f\b\xcc֛\xc5 \r1Uf\xe3\xf5c3P\x97Ԗ\xc5\xc6\xe0\x11ud\xf1\xd5cq\xe4\x01\xfeb7\xb6f,\xdak\x8b\xad\x0f\xfb>Ua\x91\xb5`\x9d\n\xafY\x90'V\x80E\x13,\xae\xda+\xbaƫS\xb95O\xad#\x95]\xe3\xf5Z\xb3 \xc7\xea\xb9b\xaa\xb4\xa2p\x8d\xae\xcdj*\xae\xe63\x89\xdfT\x91\xf5\xfa\xb5߯\xe9\xe7\x1f\xaf\xaf\x8a\xaa\xaa\x8a\x8a\x05\xe6q\x8e\xaa\x9bZZ-\x15Eե\x95QM\xd5ӑ\x89\xa3\xea\xa1\x0ek\x9d\x8e-e\xb6\nj\xba\xc2\xe9\x18رڧ\x88\xba\xa6# \xbb\x15O\x8b݀Yi\x9a\xe9\xa0M\x8af\xd6A_\"G\xb32\xd4O\xdd\r\xe6\x1f|\xb9\x12\xbe\xab\xa6^]\xe7\u007fʡ\xd0͗\x14\t\xfc\"U\xea\x89Jr\xd31\xef|Y\x03\xd7Z5\x1e\xc7t\xf1i\xeb\xdc\r\x02\x0f\x8b\xa5 \xfd\x96\xc2f\xef\x13$v\r7\"ɚ\x8e\x13\x10y\xe6LX\nr\v\xe1༉\xe8.\xc3Hzr\xbe\x06\xf8Y7\xc1t\xe7K\xc9\t\xb8V\x16e\xbe\x87\xca\"\x9c\xf7\x01}[@2);V\x89\xd2f:|T\x1f\x11\x93\xdc\xf5G\x8c\xa4\x0e\xc2'\xf5I\xae\xab\xb4\x99\xe1\b\xbb\x85\xda×\avj\xf8C\xe2\xa4\xfd\xe0\xbavZB\x881\xf8\x1e{\x02\xe4\xd4=\n\x8bH6\x9d`\xb0N\x1b\U000487f4\xbfb\"\x86f\xfd\x11\xbd[Fj\x15\x13ҍu\xfd\xe0\xa4$\xfb\xb5\r\x01\xb6\xa7\x10\xf5nk\xf31\x84\xed\x94\xf6\x99\xd9\xe7\xce\xe5\x11\x8b\xbb\xbf\xff\xe4\x17\xe4d\x81돕O\xf6\xacJa,\x12\xa5\xc3B\xfd\xa0ʹY\xca\xf43亦\xc3O\xc3u\x18\xe4S\x0f\xce+\x9d\xb4\x1a\u007f\x9bC\x10\xdf@\xba\x18\x91\u007f\x18\x1fى\x1b;L<\x96\x1e\xd2\xdbIX\xc2Z\x9dH\xd6E\x1c\xad\xf3a\xc3\xf7\xbbn\xe0\x98srDeT\x16\u007f}Vh\xbe\x86\x8djo\x95\xe7\xd4\xcc\x05$\u007f;\x18\x18\x18<\xa6>H\xff\r\xba\x8f\xd9=U\x13\xc8\xfak\xb0\xbc\x1ag\u0085+Y\x0eI7\xb3\xff\xa7\xf7\xfe\xb8s\xb9\x1a\xbf\x05e\xd5\\\xccr\x16AY넫l\xcc]7\xdc\x11\x12Q\xba\xca\xd4\xe65\xa9\f߽@@\xd0_Mp\xdam7\xb9\xb0.\x8a\x97\x9f\x9a\x8em\xb0m\x9d?\x9a\t\n\n\x9e\x85\xe5kd\xfc\xc1̨in\xee͙\xbcH\xc6[\xd7+H\x85\xc3\x15\xc1?\x8d\x9d\xa3\xfb\x80滛Y\xe9\x17\xea\xd3\x1c\x14ׄ\xe6\x81ᎋ\xbb)\xd4\xc7O\xfeV\xf0\x19\x9fG\x9e\xde(Z\xc4a\\\xe6\x8f\xf70\xe5`}즯\xa3K\xdc5\xa3\xf8luD[\xf4\xd5ܠ\xfb i+\xf2\xbc\x03џ\xa3\x8e\xb1\xf5\x8fr\xeb3(\t\xad\xe9O\a=&\x15\xd7Q\xa55\xa5\xb0F\xb7\xd4\xc1C\x8bf\x87iGHj\x1b^?i7\xa0H\x12,]}\x0eн\b\xef\xfc\x9c\u007f\x84{\xee\xf8g\xa2\x95\xf7\xa9\xed\x15\xfc\xfd\x1fgP\xdbڇp\x99\x1d=\xfc_\x00\x00\x00\xff\xff@\x82d\xbd6P\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4V͎\xe44\x10\xbe\xe7)J\xcba/$\xbd\xab\xbd\xa0\xdc\xd0\xc0a\x05\x8cFӫ\xb9 \x0en\xa7\xd2mƱCU\xb9\x87\x06\xf1\xee\xc8vҝN\xd2̀\x84o\xb1\xeb端~REY\x96\x85\xea\xcd\x13\x12\x1b\xefjP\xbd\xc1\xdf\x05]\xfc\xe2\xea\xf9\x1b\xae\x8c\xdf\x1c?\x16\xcf\xc655\xdc\x05\x16\xdf=\"\xfb@\x1a\xbf\xc3\xd68#ƻ\xa2CQ\x8d\x12U\x17\x00\xca9/*^s\xfc\x04\xd0\xde\tyk\x91\xca=\xba\xea9\xecp\x17\x8cm\x90\x92\xf1\xd1\xf5\xf1C\xf5\xa9\xfaP\x00h¤\xfe\xc5tȢ\xba\xbe\x06\x17\xac-\x00\x9c\xea\xb0\x06F\x8aJ\xa2$0\xe1o\x01Y\xb8:\xa2E\xf2\x95\xf1\x05\xf7\xa8\xa3\xe3=\xf9\xd0\xd7py\xc8\xfa\x03\xa8\x1c\xd06\x99\xda&S\x8f\xd9Tz\xb5\x86\xe5\x87[\x12?\x9aA\xaa\xb7\x81\x94]\a\x94\x04\xf8\xe0I\xee/NK`\xa6\xfcb\xdc>XE\xab\xca\x05\x00k\xdfc\rI\xb7W\x1a\x9b\x02``*\xd9*\a.\x8e\x1f\xb39}\xc0Ne'\x00\xbeG\xf7\xed\xc3\xe7\xa7O۫k\x80\x06Y\x93\xe9%\xf1\xbd\x12\x19\x18\x06\x05\x03\n\x10\x0fJkd\x06\x1d\x88\xd0\td\x94`\\\xeb\xa9K9:\x9b\x06P;\x1f\x04\xe4\x80\xf0\x94(\x1f\"\xab\xce\"=\xf9\x1eI\xcc\xc8Ơv\xa9\xbe\xc9\xed\f\xeb\xfb\x18N\x96\x82&\x96\x1dr\xf24P\x82\xcd\xc0\x00\xf8\x16\xe4`\x18\b{BF's\x94\x89\x9f\x16\x94\x03\xbf\xfb\x15\xb5T\x03\x0f\x1c\x93\x15l\x13\xab\xf5\x88$@\xa8\xfdޙ?ζ9\x12\x12\x9dZ%c\x9d\\\x8eq\x82䔅\xa3\xb2\x01\xbf\x06\xe5\x1a\xe8\xd4\t\b\xa3\x17\bnb/\x89p\x05?y\xc2Df\r\a\x91\x9e\xeb\xcdfod\xec:\xed\xbb.8#\xa7Mj \xb3\v\xe2\x897\r\x1e\xd1n\xd8\xecKE\xfa`\x04\xb5\x04\u008d\xeaM\x99\xa0\xbb\xd4yU\xd7|EC\x9f\xf2\xfb+\xacr\x8a\x95\xc5B\xc6\xed'\x0f\xa9!\xfe!\x03\xb1\x1dr}d\xd5\x1cŅ\xe8x\x15\xd9y\xfc~\xfb\x05F\xd7)\x19s\xf6\x13\xef\x17E\xbe\xa4 \x12f\\\x8b\x94\x93ؒ\xef\x92MtM\xef\x8d\xcbե\xadA7\xa7\x9fî3\xc2c\xed\xc6\\Up\x97F\x11\xec\x10B\xdf(\xc1\xa6\x82\xcf\x0e\xeeT\x87\xf6N1\xfe\xef\t\x88Ls\x19\x89}[\n\xa6St.\x9cY\x9b<\x8cc\xeeF\xbeV\xba{ۣ\x8e\x19\x8c$Fm\xd3\x1a\x9d\xda\x03ZO\xa0\xd6T\xaa7!I\x1a\xff\x12\xcb0I2\x9a\xd9|\x89\xfd\xf9:\x9a\xf5q\x92^\x0e\x8aq~9\xc3\xf4\x10e\xe6\xfe\xadiQ\x9f\xb4\xc5l\"O\x13|\x1dJ<\xe8B\xb7\xf4Y\xc2=\xbe\xac\xdc>\x90\x8f\x935\xcd\xf5\xebs\xa36 \xffo\xf6\xc6-\u009dG\x96\xa5\xd2?l:\xaa'\x03z0\x04\x14\x9c\x8b}\xbb\x98\x90\t\xc8|\x92/d\x8c`\xb7\x82f\x15\xcfg\xd7\xfa\xb4\t\xa8\xe8XI\xee'\x1c\x92=\xf8ɸV\f\xde\xceu>\xcb\xe1\xf5&B\xf3I\u007f\xd2\xff\xa6\x1cǍ!\\\xf5]&T\xab\x0f\xd1\xe3\x1a\xe3\xeb\xfd5\xa0\f֪\x9d\xc5\x1a\x84\xc2R;\xeb*\"u\x9aW\xcdXj\x97}\xea\x95\x02Z(\xc4>y9\xa0\xbb\xd5\r\xf0\xa2\xe6S\xfe\xca3\xecN\xb7T\xef\xce\xcbᲥr\xe9\xd6\x10gw)f\x85\xb37\x91\xb2\x9a\xbd\\ҫ\x9bǂ\x90\xedTv\x9c\x19W\xad1.\"\xcb\x18nBXM\xf6\xe22\x99o&\xe1\xb1xR\xfbi\xc0\x1cv\xe7?\xfd\x18\xc80\x92\xe1Ͽ\x8a\xcbt\x8e\xcb\\/\xd8\xdcϷ\xe0w\xef\xae\xd6\xd9\xf4\xa9\xbdkL^\xe2\xe1\xe7_\x8a\xec\x18\x9b\xa7q\a\x8d\x97\u007f\a\x00\x00\xff\xff!\xec@\xb2>\f\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xb4VM\x8f\xdb6\x10\xbd\xebW\f\xd2C.\x95\x9c \x97B\xb7\xc0\xed!h\x1a,\xe2ԗ\xa2\a\x9a\x1c\xd9ӥH\x963t\xbb\xfd\xf5\x05)j\xfd\xb1\xf26\v4\xbaq8|\xf3\xe6͇ݴmۨ@[\x8cL\xde\xf5\xa0\x02\xe1߂.\x9f\xb8\xbb\xff\x81;\xf2\xab\xe3\xdb果\xe9a\x9dX\xfc\xf8\x19٧\xa8\xf1G\x1cȑ\x90w͈\xa2\x8c\x12\xd57\x00\xca9/*\x9b9\x1f\x01\xb4w\x12\xbd\xb5\x18\xdb=\xba\xee>\xedp\x97\xc8\x1a\x8c\x05|\x0e}|ӽ\xeb\xde4\x00:by\xfe\x85FdQc\xe8\xc1%k\x1b\x00\xa7F\xec\xe1\xe8m\x1a\x91\x9d\n|\xf0b\xbd\x9e\x82uG\xb4\x18}G\xbe\xe1\x80:\xc7\xdeG\x9fB\x0f\xa7\x8b\t\xa2\xf2\x9ar\xda\x16\xb4ME\xfbXъ\x83%\x96\x9f\x9fq\xfaH,\xc51\xd8\x14\x95\xbdɬ\xf80\xb9}\xb2*\xde\xf2j\x00X\xfb\x80=|\xca\x14\x83\xd2h\x1a\x80*O\xa1\xdc\xce\x02\xbc\x9d\x10\xf5\x01G5\xe5\x02\xe0\x03\xba\xf7w\x1f\xb6\xef6\x17f\x00\x83\xac#\x05)\"/'\x02Ġ`f\x02\u007f\x1d0\"l\x8bj\xc0\xe2#r%\xfd\b\n0\xf3\xe7\xee\xd1\x18\xa2\x0f\x18\x85f\x81\xa7\ufb3dάW\xbc^g\xea\x93\x17\x98\xdcW\xc8 \a\x9c\xd3GS\xb3\x05?\x80\x1c\x88!b\x88\xc8\xe8\xe4T\xae\xd3\xe7\aP\x0e\xfc\xee\x0f\xd4\xd2\xc1\x06c\x86\x01>\xf8dMn\xc7#F\x81\x88\xda\xef\x1d\xfd\xf3\x88\xcd \xbe\x04\xb5J\xb0V\xf6\xf4\x91\x13\x8cNY8*\x9b\xf0{P\xce\xc0\xa8\x1e b\x8e\x02ɝ\xe1\x15\x17\xee\xe0\x17\x1f\x11\xc8\r\xbe\x87\x83H\xe0~\xb5ړ\xccc\xa5\xfd8&G\xf2\xb0*\x13B\xbb$>\xf2\xca\xe0\x11\xed\x8aiߪ\xa8\x0f$\xa8%E\\\xa9@m\xa1\xee\xa6n\x1f\xcdw\xb1\x0e\"\xbf\xbe\xe0*\x0f\xb9\x8bX\"\xb9\xfd\xd9Ei\xf7g*\x90;}j\x84\xe9\xe9\x94\xc5I\xe8l\xca\xea|\xfei\xf3\x05\xe6Х\x18\xd7\xea\x17\xddO\x0f\xf9T\x82,\x18\xb9\x01\xe3T\xc4!\xfa\xb1`\xa23\xc1\x93\x93rЖ\xd0]\xcb\xcfi7\x92\xe4\xba\xff\x99\x90%ת\x83u\xd95\xb0CH\xc1(A\xd3\xc1\a\ak5\xa2]+\xc6o^\x80\xac4\xb7Yد+\xc1\xf9\x9a\xbcv\x9eT;\x1f\xb0\xba\xc4n\xd4ky\x927\x01\xf5\xc5\x00e\x14\x1a\xa8N\xf6\xe0㕮j\x9e\xf3e\xbc\xee\xc2}y\xc0a\xda\xf1\x03\xed\xaf\xad\x00ʘ\xf2\v\xa1\xec\xddͷ\xcf\b\xb6\x90\xf7\xbaDʍ:\xf8\x98\x19\x1d\xc9`l\xe7<+\x93\x14k\u0084\xd6p\xf7\x04\xf2\x86\xe65\xc9\x02\xf9\x94\xe6\x05\x8f\xbbꖙd\xa1\xe7gӆº0\xcb\xfaT{\xbc\xc5`!\xe3\xdc\xe1\x14\xf1jV\xdb\xc7\x00_\xd5;\xa2$\xf1˻\xa7<\xab\x9e\xbb\xdaA:ňN*\xe6¦\xfd\u007f:(\x1c\x14\xe3\u007fh\xbe\x1c\xe1.\xbf\x9c\xcb`i@\xfd\xa0-N\x80\xe0\x87\x85n{\x11\xe5\xfc\xa1K\xe3Sn-\xbc?*\xb2jgq\xe1\xeeW\xa7n\xde\xde,\xfeb=\x9f\x189\xafSӃ\xc44a\xd7.\xab\x96S\xf5\x95\xd6\x18\x04ͧ\xeb\u007f=\xaf^]\xfcq)G\xed\xdd4\xac\xdc\xc3o\xbf7\x13*\x9a\xed\xfc\x0f$\x1b\xff\r\x00\x00\xff\xff2\x1e\xaa\xc01\n\x00\x00"), +} + +var CRDs = crds() + +func crds() []*apiextv1.CustomResourceDefinition { + apiextinstall.Install(scheme.Scheme) + decode := scheme.Codecs.UniversalDeserializer().Decode + var objs []*apiextv1.CustomResourceDefinition + for _, crd := range rawCRDs { + gzr, err := gzip.NewReader(bytes.NewReader(crd)) + if err != nil { + panic(err) + } + bytes, err := ioutil.ReadAll(gzr) + if err != nil { + panic(err) + } + gzr.Close() + + obj, _, err := decode(bytes, nil, nil) + if err != nil { + panic(err) + } + objs = append(objs, obj.(*apiextv1.CustomResourceDefinition)) + } + return objs +} diff --git a/config/crd/crds/doc.go b/config/crd/v1/crds/doc.go similarity index 58% rename from config/crd/crds/doc.go rename to config/crd/v1/crds/doc.go index 1103893f7..9eed410f6 100644 --- a/config/crd/crds/doc.go +++ b/config/crd/v1/crds/doc.go @@ -1,4 +1,4 @@ // Package crds embeds the controller-tools generated CRD manifests package crds -//go:generate go run ../../../hack/crd-gen/main.go +//go:generate go run ../../../../hack/crd-gen/v1/main.go diff --git a/config/crd/bases/velero.io_backups.yaml b/config/crd/v1beta1/bases/velero.io_backups.yaml similarity index 100% rename from config/crd/bases/velero.io_backups.yaml rename to config/crd/v1beta1/bases/velero.io_backups.yaml diff --git a/config/crd/bases/velero.io_backupstoragelocations.yaml b/config/crd/v1beta1/bases/velero.io_backupstoragelocations.yaml similarity index 100% rename from config/crd/bases/velero.io_backupstoragelocations.yaml rename to config/crd/v1beta1/bases/velero.io_backupstoragelocations.yaml diff --git a/config/crd/bases/velero.io_deletebackuprequests.yaml b/config/crd/v1beta1/bases/velero.io_deletebackuprequests.yaml similarity index 100% rename from config/crd/bases/velero.io_deletebackuprequests.yaml rename to config/crd/v1beta1/bases/velero.io_deletebackuprequests.yaml diff --git a/config/crd/bases/velero.io_downloadrequests.yaml b/config/crd/v1beta1/bases/velero.io_downloadrequests.yaml similarity index 100% rename from config/crd/bases/velero.io_downloadrequests.yaml rename to config/crd/v1beta1/bases/velero.io_downloadrequests.yaml diff --git a/config/crd/bases/velero.io_podvolumebackups.yaml b/config/crd/v1beta1/bases/velero.io_podvolumebackups.yaml similarity index 100% rename from config/crd/bases/velero.io_podvolumebackups.yaml rename to config/crd/v1beta1/bases/velero.io_podvolumebackups.yaml diff --git a/config/crd/bases/velero.io_podvolumerestores.yaml b/config/crd/v1beta1/bases/velero.io_podvolumerestores.yaml similarity index 100% rename from config/crd/bases/velero.io_podvolumerestores.yaml rename to config/crd/v1beta1/bases/velero.io_podvolumerestores.yaml diff --git a/config/crd/bases/velero.io_resticrepositories.yaml b/config/crd/v1beta1/bases/velero.io_resticrepositories.yaml similarity index 100% rename from config/crd/bases/velero.io_resticrepositories.yaml rename to config/crd/v1beta1/bases/velero.io_resticrepositories.yaml diff --git a/config/crd/bases/velero.io_restores.yaml b/config/crd/v1beta1/bases/velero.io_restores.yaml similarity index 100% rename from config/crd/bases/velero.io_restores.yaml rename to config/crd/v1beta1/bases/velero.io_restores.yaml diff --git a/config/crd/bases/velero.io_schedules.yaml b/config/crd/v1beta1/bases/velero.io_schedules.yaml similarity index 100% rename from config/crd/bases/velero.io_schedules.yaml rename to config/crd/v1beta1/bases/velero.io_schedules.yaml diff --git a/config/crd/bases/velero.io_serverstatusrequests.yaml b/config/crd/v1beta1/bases/velero.io_serverstatusrequests.yaml similarity index 100% rename from config/crd/bases/velero.io_serverstatusrequests.yaml rename to config/crd/v1beta1/bases/velero.io_serverstatusrequests.yaml diff --git a/config/crd/bases/velero.io_volumesnapshotlocations.yaml b/config/crd/v1beta1/bases/velero.io_volumesnapshotlocations.yaml similarity index 100% rename from config/crd/bases/velero.io_volumesnapshotlocations.yaml rename to config/crd/v1beta1/bases/velero.io_volumesnapshotlocations.yaml diff --git a/config/crd/crds/crds.go b/config/crd/v1beta1/crds/crds.go similarity index 100% rename from config/crd/crds/crds.go rename to config/crd/v1beta1/crds/crds.go diff --git a/config/crd/v1beta1/crds/doc.go b/config/crd/v1beta1/crds/doc.go new file mode 100644 index 000000000..16e695f91 --- /dev/null +++ b/config/crd/v1beta1/crds/doc.go @@ -0,0 +1,4 @@ +// Package crds embeds the controller-tools generated CRD manifests +package crds + +//go:generate go run ../../../../hack/crd-gen/v1beta1/main.go diff --git a/hack/crd-gen/v1/main.go b/hack/crd-gen/v1/main.go new file mode 100644 index 000000000..9bb05a400 --- /dev/null +++ b/hack/crd-gen/v1/main.go @@ -0,0 +1,136 @@ +/* +Copyright the Velero contributors. + +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. +*/ + +// This code embeds the CRD manifests in config/crd/v1/bases in +// config/crd/v1/crds/crds.go. + +package main + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "log" + "os" + "text/template" +) + +// This is relative to config/crd/crds +const goHeaderFile = "../../../../hack/boilerplate.go.txt" + +const tpl = `{{.GoHeader}} +// Code generated by crds_generate.go; DO NOT EDIT. + +package crds + +import ( + "bytes" + "compress/gzip" + "io/ioutil" + + apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install" + apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/client-go/kubernetes/scheme" +) + +var rawCRDs = [][]byte{ +{{- range .RawCRDs }} + []byte({{ . }}), +{{- end }} +} + +var CRDs = crds() + +func crds() []*apiextv1.CustomResourceDefinition { + apiextinstall.Install(scheme.Scheme) + decode := scheme.Codecs.UniversalDeserializer().Decode + var objs []*apiextv1.CustomResourceDefinition + for _, crd := range rawCRDs { + gzr, err := gzip.NewReader(bytes.NewReader(crd)) + if err != nil { + panic(err) + } + bytes, err := ioutil.ReadAll(gzr) + if err != nil { + panic(err) + } + gzr.Close() + + obj, _, err := decode(bytes, nil, nil) + if err != nil { + panic(err) + } + objs = append(objs, obj.(*apiextv1.CustomResourceDefinition)) + } + return objs +} +` + +type templateData struct { + GoHeader string + RawCRDs []string +} + +func main() { + headerBytes, err := ioutil.ReadFile(goHeaderFile) + if err != nil { + log.Fatalln(err) + } + + data := templateData{ + GoHeader: string(headerBytes), + } + + // This is relative to config/crd/crds + manifests, err := ioutil.ReadDir("../bases") + if err != nil { + log.Fatalln(err) + } + + for _, crd := range manifests { + file, err := os.Open("../bases/" + crd.Name()) + if err != nil { + log.Fatalln(err) + } + + // gzip compress manifest + var buf bytes.Buffer + gzw := gzip.NewWriter(&buf) + if _, err := io.Copy(gzw, file); err != nil { + log.Fatalln(err) + } + file.Close() + gzw.Close() + + data.RawCRDs = append(data.RawCRDs, fmt.Sprintf("%q", buf.Bytes())) + } + + t, err := template.New("crd").Parse(tpl) + if err != nil { + log.Fatalln(err) + } + + out, err := os.Create("crds.go") + if err != nil { + log.Fatalln(err) + } + + if err := t.Execute(out, data); err != nil { + log.Fatalln(err) + } +} diff --git a/hack/crd-gen/main.go b/hack/crd-gen/v1beta1/main.go similarity index 93% rename from hack/crd-gen/main.go rename to hack/crd-gen/v1beta1/main.go index 4b44990aa..2f204a0d2 100644 --- a/hack/crd-gen/main.go +++ b/hack/crd-gen/v1beta1/main.go @@ -1,5 +1,5 @@ /* -Copyright 2019 the Velero contributors. +Copyright the Velero contributors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -// This code embeds the CRD manifests in config/crd/bases in -// config/crd/crds/crds.go. +// This code embeds the CRD manifests in config/crd/v1beta1/bases in +// config/crd/v1beta1/crds/crds.go. package main @@ -31,7 +31,7 @@ import ( ) // This is relative to config/crd/crds -const goHeaderFile = "../../../hack/boilerplate.go.txt" +const goHeaderFile = "../../../../hack/boilerplate.go.txt" const tpl = `{{.GoHeader}} // Code generated by crds_generate.go; DO NOT EDIT. diff --git a/hack/restore-crd-patch-v1.json b/hack/restore-crd-patch-v1.json new file mode 100644 index 000000000..b8b729d0d --- /dev/null +++ b/hack/restore-crd-patch-v1.json @@ -0,0 +1,3 @@ +[ + { "op": "replace", "path": "/spec/versions/0/schema/openAPIV3Schema/properties/spec/properties/hooks/properties/resources/items/properties/postHooks/items/properties/init/properties/initContainers/items/properties/ports/items/required", "value": [ "containerPort", "protocol"] } +] diff --git a/hack/restore-crd-patch.json b/hack/restore-crd-patch-v1beta1.json similarity index 100% rename from hack/restore-crd-patch.json rename to hack/restore-crd-patch-v1beta1.json diff --git a/hack/update-generated-crd-code.sh b/hack/update-generated-crd-code.sh index 193fa121c..35bd93927 100755 --- a/hack/update-generated-crd-code.sh +++ b/hack/update-generated-crd-code.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright 2017 the Velero contributors. +# Copyright the Velero contributors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -44,20 +44,24 @@ ${GOPATH}/src/k8s.io/code-generator/generate-groups.sh \ --output-base ../../.. \ $@ -# Generate manifests e.g. CRD, RBAC etc. -controller-gen \ - crd:crdVersions=v1beta1,preserveUnknownFields=false,trivialVersions=true \ - paths=./pkg/apis/velero/v1/... \ - paths=./pkg/controller/... \ - output:crd:artifacts:config=config/crd/bases +# Generate both apiextensions.k8s.io/v1beta1 and apiextensions.k8s.io/v1 +for version in v1beta1 v1 +do + # Generate manifests e.g. CRD, RBAC etc. + controller-gen \ + crd:crdVersions=$version,preserveUnknownFields=false,trivialVersions=true \ + paths=./pkg/apis/velero/v1/... \ + paths=./pkg/controller/... \ + output:crd:artifacts:config=config/crd/$version/bases -# this is a super hacky workaround for https://github.com/kubernetes/kubernetes/issues/91395 -# which a result of fixing the validation on CRD objects. The validation ensures the fields that are list map keys, are either marked -# as required or have default values to ensure merging of list map items work as expected. -# With "containerPort" and "protocol" being considered as x-kubernetes-list-map-keys in the container ports, and "protocol" was not -# a required field, the CRD would fail validation with errors similar to the one reported in https://github.com/kubernetes/kubernetes/issues/91395. -# once controller-gen (above) is able to generate CRDs with `protocol` as a required field, this hack can be removed. -kubectl patch -f config/crd/bases/velero.io_restores.yaml -p "$(cat hack/restore-crd-patch.json)" --type=json --local=true -o yaml > /tmp/velero.io_restores-yaml.patched -mv /tmp/velero.io_restores-yaml.patched config/crd/bases/velero.io_restores.yaml + # this is a super hacky workaround for https://github.com/kubernetes/kubernetes/issues/91395 + # which a result of fixing the validation on CRD objects. The validation ensures the fields that are list map keys, are either marked + # as required or have default values to ensure merging of list map items work as expected. + # With "containerPort" and "protocol" being considered as x-kubernetes-list-map-keys in the container ports, and "protocol" was not + # a required field, the CRD would fail validation with errors similar to the one reported in https://github.com/kubernetes/kubernetes/issues/91395. + # once controller-gen (above) is able to generate CRDs with `protocol` as a required field, this hack can be removed. + kubectl patch -f config/crd/$version/bases/velero.io_restores.yaml -p "$(cat hack/restore-crd-patch-$version.json)" --type=json --local=true -o yaml > /tmp/velero.io_restores-yaml.patched + mv /tmp/velero.io_restores-yaml.patched config/crd/$version/bases/velero.io_restores.yaml -go generate ./config/crd/crds + go generate ./config/crd/$version/crds +done diff --git a/hack/verify-generated-crd-code.sh b/hack/verify-generated-crd-code.sh index 287522db3..90d1f04b9 100755 --- a/hack/verify-generated-crd-code.sh +++ b/hack/verify-generated-crd-code.sh @@ -1,6 +1,6 @@ #!/bin/bash -e # -# Copyright 2017 the Velero contributors. +# Copyright the Velero contributors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,11 +19,14 @@ HACK_DIR=$(dirname "${BASH_SOURCE}") ${HACK_DIR}/update-generated-crd-code.sh --verify-only # ensure no changes to generated CRDs -if ! git diff --exit-code config/crd/crds/crds.go >/dev/null; then - # revert changes to state before running CRD generation to stay consistent - # with code-generator `--verify-only` option which discards generated changes - git checkout config/crd +for version in v1beta1 v1 +do + if ! git diff --exit-code config/crd/$version/crds/crds.go >/dev/null; then + # revert changes to state before running CRD generation to stay consistent + # with code-generator `--verify-only` option which discards generated changes + git checkout config/crd - echo "CRD verification - failed! Generated CRDs are out-of-date, please run 'make update' and 'git add' the generated file(s)." - exit 1 -fi \ No newline at end of file + echo "CRD verification - failed! Generated CRDs are out-of-date, please run 'make update' and 'git add' the generated file(s)." + exit 1 + fi +done diff --git a/pkg/cmd/cli/install/install.go b/pkg/cmd/cli/install/install.go index 037fca2f7..d07051f5e 100644 --- a/pkg/cmd/cli/install/install.go +++ b/pkg/cmd/cli/install/install.go @@ -25,9 +25,11 @@ import ( "time" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" "github.com/vmware-tanzu/velero/internal/velero" velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" @@ -35,6 +37,7 @@ import ( "github.com/vmware-tanzu/velero/pkg/cmd" "github.com/vmware-tanzu/velero/pkg/cmd/util/flag" "github.com/vmware-tanzu/velero/pkg/cmd/util/output" + velerodiscovery "github.com/vmware-tanzu/velero/pkg/discovery" "github.com/vmware-tanzu/velero/pkg/install" kubeutil "github.com/vmware-tanzu/velero/pkg/util/kube" ) @@ -69,6 +72,7 @@ type InstallOptions struct { Plugins flag.StringArray NoDefaultBackupLocation bool CRDsOnly bool + CRDsVersion string CACertFile string Features string DefaultVolumesToRestic bool @@ -103,6 +107,7 @@ func (o *InstallOptions) BindFlags(flags *pflag.FlagSet) { flags.DurationVar(&o.DefaultResticMaintenanceFrequency, "default-restic-prune-frequency", o.DefaultResticMaintenanceFrequency, "How often 'restic prune' is run for restic repositories by default. Optional.") flags.Var(&o.Plugins, "plugins", "Plugin container images to install into the Velero Deployment") flags.BoolVar(&o.CRDsOnly, "crds-only", o.CRDsOnly, "Only generate CustomResourceDefinition resources. Useful for updating CRDs for an existing Velero install.") + flags.StringVar(&o.CRDsVersion, "crds-version", o.CRDsVersion, "The version to generate CustomResourceDefinition resources if Velero can't discover the Kubernetes preferred CRD API version. Optional.") flags.StringVar(&o.CACertFile, "cacert", o.CACertFile, "File containing a certificate bundle to use when verifying TLS connections to the object store. Optional.") flags.StringVar(&o.Features, "features", o.Features, "Comma separated list of Velero feature flags to be set on the Velero deployment and the restic daemonset, if restic is enabled") flags.BoolVar(&o.DefaultVolumesToRestic, "default-volumes-to-restic", o.DefaultVolumesToRestic, "Bool flag to configure Velero server to use restic by default to backup all pod volumes on all backups. Optional.") @@ -129,6 +134,7 @@ func NewInstallOptions() *InstallOptions { UseVolumeSnapshots: true, NoDefaultBackupLocation: false, CRDsOnly: false, + CRDsVersion: "v1", DefaultVolumesToRestic: false, } } @@ -187,6 +193,7 @@ func (o *InstallOptions) AsVeleroOptions() (*install.VeleroOptions, error) { NoDefaultBackupLocation: o.NoDefaultBackupLocation, CACertData: caCertData, Features: strings.Split(o.Features, ","), + CRDsVersion: o.CRDsVersion, DefaultVolumesToRestic: o.DefaultVolumesToRestic, }, nil } @@ -247,9 +254,30 @@ This is useful as a starting point for more customized installations. // Run executes a command in the context of the provided arguments. func (o *InstallOptions) Run(c *cobra.Command, f client.Factory) error { + // Find the kube-apiserver group apiextensions.k8s.io preferred API version + clientset, err := f.KubeClient() + if err == nil { + // kubeconfig available + discoveryHelper, err := velerodiscovery.NewHelper(clientset.Discovery(), &logrus.Logger{}) + if err == nil { + // kubernetes apiserver available + gvr, _, err := discoveryHelper.ResourceFor( + schema.GroupVersionResource{ + Group: "apiextensions.k8s.io", + Resource: "customresourcedefinitions", + }) + if err != nil { + return err + } + + // Update the group apiextensions.k8s.io preferred API version + o.CRDsVersion = gvr.Version + } + } + var resources *unstructured.UnstructuredList if o.CRDsOnly { - resources = install.AllCRDs() + resources = install.AllCRDs(o.CRDsVersion) } else { vo, err := o.AsVeleroOptions() if err != nil { @@ -316,6 +344,11 @@ func (o *InstallOptions) Validate(c *cobra.Command, args []string, f client.Fact return err } + // Check the CRD version is valid. + if o.CRDsVersion != "v1beta1" && o.CRDsVersion != "v1" { + return errors.Errorf("CRD version must be v1beta1 or v1") + } + // If we're only installing CRDs, we can skip the rest of the validation. if o.CRDsOnly { return nil diff --git a/pkg/install/resources.go b/pkg/install/resources.go index 16d89e01f..dbe19fba9 100644 --- a/pkg/install/resources.go +++ b/pkg/install/resources.go @@ -19,8 +19,6 @@ package install import ( "time" - velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" - corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -28,7 +26,9 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - "github.com/vmware-tanzu/velero/config/crd/crds" + v1crds "github.com/vmware-tanzu/velero/config/crd/v1/crds" + v1beta1crds "github.com/vmware-tanzu/velero/config/crd/v1beta1/crds" + velerov1api "github.com/vmware-tanzu/velero/pkg/apis/velero/v1" ) var ( @@ -216,17 +216,26 @@ type VeleroOptions struct { NoDefaultBackupLocation bool CACertData []byte Features []string + CRDsVersion string DefaultVolumesToRestic bool } -func AllCRDs() *unstructured.UnstructuredList { +func AllCRDs(perferredAPIVersion string) *unstructured.UnstructuredList { resources := new(unstructured.UnstructuredList) // Set the GVK so that the serialization framework outputs the list properly resources.SetGroupVersionKind(schema.GroupVersionKind{Group: "", Version: "v1", Kind: "List"}) - for _, crd := range crds.CRDs { - crd.SetLabels(Labels()) - appendUnstructured(resources, crd) + switch perferredAPIVersion { + case "v1beta1": + for _, crd := range v1beta1crds.CRDs { + crd.SetLabels(Labels()) + appendUnstructured(resources, crd) + } + case "v1": + for _, crd := range v1crds.CRDs { + crd.SetLabels(Labels()) + appendUnstructured(resources, crd) + } } return resources @@ -235,7 +244,7 @@ func AllCRDs() *unstructured.UnstructuredList { // AllResources returns a list of all resources necessary to install Velero, in the appropriate order, into a Kubernetes cluster. // Items are unstructured, since there are different data types returned. func AllResources(o *VeleroOptions) *unstructured.UnstructuredList { - resources := AllCRDs() + resources := AllCRDs(o.CRDsVersion) ns := Namespace(o.Namespace) appendUnstructured(resources, ns) diff --git a/site/content/docs/main/development.md b/site/content/docs/main/development.md index 0a9596188..f23ab03e7 100644 --- a/site/content/docs/main/development.md +++ b/site/content/docs/main/development.md @@ -43,4 +43,14 @@ To run unit tests, use `make test`. If you need to add or update the vendored dependencies, see [Vendoring dependencies][11]. +## Using the main branch + +If you are developing or using the main branch, note that you may need to update the Velero CRDs to get new changes as other development work is completed. + +```bash +velero install --crds-only --dry-run -o yaml | kubectl apply -f - +``` + +**NOTE:** You could change the default CRD API version (v1beta1 _or_ v1) if Velero CLI can't discover the Kubernetes preferred CRD API version. The Kubernetes version < 1.16 preferred CRD API version is v1beta1; the Kubernetes version >= 1.16 preferred CRD API version is v1. + [11]: vendoring-dependencies.md diff --git a/site/content/docs/main/upgrade-to-1.6.md b/site/content/docs/main/upgrade-to-1.6.md index fe85a1f64..3e55e3c67 100644 --- a/site/content/docs/main/upgrade-to-1.6.md +++ b/site/content/docs/main/upgrade-to-1.6.md @@ -39,6 +39,8 @@ If you're not yet running at least Velero v1.5, see the following: velero install --crds-only --dry-run -o yaml | kubectl apply -f - ``` + **NOTE:** You could change the default CRD API version (v1beta1 _or_ v1) if Velero CLI can't discover the Kubernetes preferred CRD API version. The Kubernetes version < 1.16 preferred CRD API version is v1beta1; the Kubernetes version >= 1.16 preferred CRD API version is v1. + **NOTE:** If you are upgrading Velero in Kubernetes 1.14.x or earlier, you will need to use `kubectl apply`'s `--validate=false` option when applying the CRD configuration above. See [issue 2077][6] and [issue 2311][7] for more context. 1. Update the container image used by the Velero deployment and, optionally, the restic daemon set: