From 0d430c5645ff58ba0049a9bbdbb3ee1cea257fb0 Mon Sep 17 00:00:00 2001 From: Alan Clucas Date: Wed, 11 Sep 2024 14:10:56 +0100 Subject: [PATCH 1/5] feat!: multiple mutexes and semaphores Fixes #5022 Fixes #11859 This is mostly backwards compatbile. It is minorly breaking only in as much as semaphore + mutex at the same time will now require both, whereas before it ignored the mutex. As a workflows users I would like to be able to use more than one sync option in a workflow or template. Added `mutexes` and `semaphores` to the `synchronization` block in workflow types as lists. Legacy `mutex` and `semaphore` kept in and continue to work (will be added to the mutexes/semaphores list) but marked for deprecation. Logic changed to acquire a full list of all synchronization items (`syncItem`) when `TryAcquire` and `Release` from sync manager. `TryAcquire` from sync_manager` calls a new `checkAcquire` method, whilst holding the sync_manager internal golang `sync.Mutex` to check if they are all acquirable before acquiring them. This honors priority. `TryAcquire` also returns the failed lock name in the case of failure to acquire to reduce the number of exported `package sync` methods and complexity outside of `sync`. The interface to the workflow status block has not changed. Reduced the exported types and methods from the sync module as far as possible (lower case instead of upper case). Removed the internal golang sync mutex from `PrioritySemaphore` as all methods are called from `sync_manager.go` when under it's own lock. The alternative was unnecessarily complicating the calls inside semaphore.go. This is faster, but less clean in case someone wants to reuse the PrioritySemaphore type. Renamed the manager in `sync_manager.go` where used: `cm`->`sm` and `concurrencyManager`->`syncManager`. New and updated unit tests. New and updated e2e smoke tests. Signed-off-by: Alan Clucas --- api/jsonschema/schema.json | 18 +- api/openapi-spec/swagger.json | 18 +- docs/executor_swagger.md | 2 + docs/fields.md | 22 +- docs/synchronization.md | 72 +- .../synchronization-mutex-tmpl-level.yaml | 10 +- examples/synchronization-mutex-wf-level.yaml | 4 +- examples/synchronization-tmpl-level.yaml | 8 +- examples/synchronization-wf-level.yaml | 8 +- .../argoproj.io_clusterworkflowtemplates.yaml | 84 + .../crds/full/argoproj.io_cronworkflows.yaml | 84 + .../base/crds/full/argoproj.io_workflows.yaml | 196 +++ .../full/argoproj.io_workflowtasksets.yaml | 28 + .../full/argoproj.io_workflowtemplates.yaml | 84 + pkg/apis/api-rules/violation_exceptions.list | 2 + pkg/apis/workflow/v1alpha1/generated.pb.go | 1470 +++++++++-------- pkg/apis/workflow/v1alpha1/generated.proto | 10 +- .../workflow/v1alpha1/openapi_generated.go | 30 +- pkg/apis/workflow/v1alpha1/workflow_types.go | 33 +- .../v1alpha1/zz_generated.deepcopy.go | 22 + pkg/plugins/executor/swagger.yml | 10 + ...ArgoprojWorkflowV1alpha1Synchronization.md | 2 + ...oproj_workflow_v1alpha1_synchronization.py | 8 + .../docs/ClusterWorkflowTemplateServiceApi.md | 144 ++ .../client/docs/CronWorkflowServiceApi.md | 144 ++ ...ArgoprojWorkflowV1alpha1Synchronization.md | 2 + sdks/python/client/docs/WorkflowServiceApi.md | 224 +++ .../client/docs/WorkflowTemplateServiceApi.md | 144 ++ ...ynchronization-legacy-mutex-semaphore.yaml | 31 + .../functional/synchronization-multiple.yaml | 39 + .../synchronization-mutex-tmpl-level.yaml | 8 +- .../synchronization-mutex-wf-level-1.yaml | 4 +- .../synchronization-mutex-wf-level.yaml | 4 +- ...ronization-tmpl-level-mutex-semaphore.yaml | 20 +- test/e2e/hooks_test.go | 4 +- test/e2e/semaphore_test.go | 19 + test/e2e/testdata/semaphore-tmpl-level.yaml | 8 +- test/e2e/testdata/semaphore-wf-level-1.yaml | 8 +- test/e2e/testdata/semaphore-wf-level.yaml | 8 +- workflow/controller/operator.go | 17 +- workflow/controller/operator_test.go | 6 +- workflow/sync/common.go | 3 +- workflow/sync/lock_name.go | 84 +- workflow/sync/lock_name_test.go | 20 +- workflow/sync/multiple_test.go | 424 +++++ workflow/sync/mutex.go | 2 +- workflow/sync/mutex_test.go | 121 +- workflow/sync/semaphore.go | 82 +- workflow/sync/sync_manager.go | 260 +-- workflow/sync/sync_manager_test.go | 214 +-- workflow/sync/syncitems.go | 52 + workflow/sync/syncitems_test.go | 142 ++ 52 files changed, 3336 insertions(+), 1127 deletions(-) create mode 100644 test/e2e/functional/synchronization-legacy-mutex-semaphore.yaml create mode 100644 test/e2e/functional/synchronization-multiple.yaml create mode 100644 workflow/sync/multiple_test.go create mode 100644 workflow/sync/syncitems.go create mode 100644 workflow/sync/syncitems_test.go diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index 18c4d417aed6..4cc5094f0971 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -6952,11 +6952,25 @@ "properties": { "mutex": { "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Mutex", - "description": "Mutex holds the Mutex lock details" + "description": "Mutex holds the Mutex lock details - deprecated, use mutexes instead" + }, + "mutexes": { + "description": "Mutexes holds the list of Mutex lock details", + "items": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Mutex" + }, + "type": "array" }, "semaphore": { "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.SemaphoreRef", - "description": "Semaphore holds the Semaphore configuration" + "description": "Semaphore holds the Semaphore configuration - deprecated, use semaphores instead" + }, + "semaphores": { + "description": "Semaphores holds the list of Semaphores configuration", + "items": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.SemaphoreRef" + }, + "type": "array" } }, "type": "object" diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 09277be9a891..b5753e95f546 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -10970,12 +10970,26 @@ "type": "object", "properties": { "mutex": { - "description": "Mutex holds the Mutex lock details", + "description": "Mutex holds the Mutex lock details - deprecated, use mutexes instead", "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Mutex" }, + "mutexes": { + "description": "Mutexes holds the list of Mutex lock details", + "type": "array", + "items": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Mutex" + } + }, "semaphore": { - "description": "Semaphore holds the Semaphore configuration", + "description": "Semaphore holds the Semaphore configuration - deprecated, use semaphores instead", "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.SemaphoreRef" + }, + "semaphores": { + "description": "Semaphores holds the list of Semaphores configuration", + "type": "array", + "items": { + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.SemaphoreRef" + } } } }, diff --git a/docs/executor_swagger.md b/docs/executor_swagger.md index 45e157397538..183c89d14a28 100644 --- a/docs/executor_swagger.md +++ b/docs/executor_swagger.md @@ -3683,7 +3683,9 @@ otherwise). | Name | Type | Go type | Required | Default | Description | Example | |------|------|---------|:--------:| ------- |-------------|---------| | mutex | [Mutex](#mutex)| `Mutex` | | | | | +| mutexes | [][Mutex](#mutex)| `[]*Mutex` | | | Mutexes holds the list of Mutex lock details | | | semaphore | [SemaphoreRef](#semaphore-ref)| `SemaphoreRef` | | | | | +| semaphores | [][SemaphoreRef](#semaphore-ref)| `[]*SemaphoreRef` | | | Semaphores holds the list of Semaphores configuration | | diff --git a/docs/fields.md b/docs/fields.md index 8e80b6f2f03c..40c208ab0b3a 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -1645,8 +1645,10 @@ Synchronization holds synchronization lock configuration ### Fields | Field Name | Field Type | Description | |:----------:|:----------:|---------------| -|`mutex`|[`Mutex`](#mutex)|Mutex holds the Mutex lock details| -|`semaphore`|[`SemaphoreRef`](#semaphoreref)|Semaphore holds the Semaphore configuration| +|`mutex`|[`Mutex`](#mutex)|Mutex holds the Mutex lock details - deprecated, use mutexes instead| +|`mutexes`|`Array<`[`Mutex`](#mutex)`>`|Mutexes holds the list of Mutex lock details| +|`semaphore`|[`SemaphoreRef`](#semaphoreref)|Semaphore holds the Semaphore configuration - deprecated, use semaphores instead| +|`semaphores`|`Array<`[`SemaphoreRef`](#semaphoreref)`>`|Semaphores holds the list of Semaphores configuration| ## Template @@ -2362,14 +2364,6 @@ Backoff is a backoff strategy to use within retryStrategy Mutex holds Mutex configuration -
-Examples with this field (click to open) - -- [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) - -- [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) -
- ### Fields | Field Name | Field Type | Description | |:----------:|:----------:|---------------| @@ -3250,14 +3244,6 @@ NodeSynchronizationStatus stores the status of a node MutexStatus contains which objects hold mutex locks, and which objects this workflow is waiting on to release locks. -
-Examples with this field (click to open) - -- [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) - -- [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) -
- ### Fields | Field Name | Field Type | Description | |:----------:|:----------:|---------------| diff --git a/docs/synchronization.md b/docs/synchronization.md index 480952cb0221..94f8891e4d4e 100644 --- a/docs/synchronization.md +++ b/docs/synchronization.md @@ -1,6 +1,7 @@ # Synchronization > v2.10 and after +> v3.6 for multiple You can limit the parallel execution of workflows or templates: @@ -44,10 +45,10 @@ metadata: spec: entrypoint: hello-world synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: workflow + semaphores: + - configMapKeyRef: + name: my-config + key: workflow templates: - name: hello-world container: @@ -66,8 +67,8 @@ metadata: spec: entrypoint: hello-world synchronization: - mutex: - name: workflow + mutexes: + - name: workflow templates: - name: hello-world container: @@ -105,10 +106,10 @@ spec: - name: acquire-lock synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: template + semaphores: + - configMapKeyRef: + name: my-config + key: template container: image: alpine:latest command: [sh, -c] @@ -137,8 +138,8 @@ spec: - name: acquire-lock synchronization: - mutex: - name: template + mutexes: + - name: template container: image: alpine:latest command: [sh, -c] @@ -162,6 +163,26 @@ The queue is then ordered by `creationTimestamp`: older workflows are placed bef Workflows can only acquire a lock if they are at the front of the queue for that lock. +## Multiple locks + +You can specify multiple locks in a single workflow or template. + +```yaml +synchronization: + mutexes: + - name: alpha + - name: beta + semaphores: + - configMapKeyRef: + key: foo + name: my-config + - configMapKeyRef: + key: bar + name: my-config +``` + +The workflow will block until all of these locks are available. + ## Workflow-level parallelism You can use `parallelism` within a workflow or template to restrict the total concurrent executions of steps or tasks. @@ -175,6 +196,33 @@ Examples: 1. [`parallelism-nested-workflow.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/parallelism-nested-workflow.yaml) shows how parallelism is inherited by children 1. [`parallelism-template-limit.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/parallelism-template-limit.yaml) shows how parallelism of looped templates is also restricted +!!! Warning + If a Workflow is at the front of the queue and it needs to acquire multiple locks, all other Workflows that also need those same locks will wait. This applies even if the other Workflows only wish to acquire a subset of those locks. + +## Legacy + +In workflows prior to 3.6 you can only specify one lock in any one workflow or template using either a mutex: + +```yaml + synchronization: + mutex: + ... +``` + +or a semaphore: + +```yaml + synchronizaion: + semamphore: + ... +``` + +Specifying both would not work in <3.6, only the semaphore would be used. + +The single `mutex` and `semaphore` syntax still works in version 3.6 but is considered deprecated. +Both the `mutex` and the `semaphore` will be taken in version 3.6 with this syntax. +This syntax can be mixed with `mutexes` and `semaphores`, all locks will be required. + ## Other Parallelism support You can also [restrict parallelism at the Controller-level](parallelism.md). diff --git a/examples/synchronization-mutex-tmpl-level.yaml b/examples/synchronization-mutex-tmpl-level.yaml index 9652e48a7d0a..c2368cca835d 100644 --- a/examples/synchronization-mutex-tmpl-level.yaml +++ b/examples/synchronization-mutex-tmpl-level.yaml @@ -28,8 +28,8 @@ spec: - name: acquire-lock synchronization: - mutex: - name: welcome + mutexes: + - name: welcome container: image: alpine:latest command: [sh, -c] @@ -37,9 +37,9 @@ spec: - name: acquire-lock-1 synchronization: - mutex: - name: test + mutexes: + - name: test container: image: alpine:latest command: [sh, -c] - args: ["sleep 50; echo acquired lock"] \ No newline at end of file + args: ["sleep 50; echo acquired lock"] diff --git a/examples/synchronization-mutex-wf-level.yaml b/examples/synchronization-mutex-wf-level.yaml index f13b199c6aaa..00494c3a8cd0 100644 --- a/examples/synchronization-mutex-wf-level.yaml +++ b/examples/synchronization-mutex-wf-level.yaml @@ -7,8 +7,8 @@ metadata: spec: entrypoint: hello-world synchronization: - mutex: - name: test + mutexes: + - name: test templates: - name: hello-world container: diff --git a/examples/synchronization-tmpl-level.yaml b/examples/synchronization-tmpl-level.yaml index b8c0f79c6c6f..d9eafd230ca1 100644 --- a/examples/synchronization-tmpl-level.yaml +++ b/examples/synchronization-tmpl-level.yaml @@ -27,10 +27,10 @@ spec: - name: acquire-lock synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: template + semaphores: + - configMapKeyRef: + name: my-config + key: template container: image: alpine:latest command: [sh, -c] diff --git a/examples/synchronization-wf-level.yaml b/examples/synchronization-wf-level.yaml index b7ed90a092ca..33a8e11f7eb2 100644 --- a/examples/synchronization-wf-level.yaml +++ b/examples/synchronization-wf-level.yaml @@ -16,10 +16,10 @@ metadata: spec: entrypoint: hello-world synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: workflow + semaphores: + - configMapKeyRef: + name: my-config + key: workflow templates: - name: hello-world container: diff --git a/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml b/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml index 8aa8eecf678d..c9afdfafe375 100644 --- a/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml +++ b/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml @@ -2113,6 +2113,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -2131,6 +2140,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object templateDefaults: properties: @@ -10581,6 +10609,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -10599,6 +10636,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string @@ -19835,6 +19891,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -19853,6 +19918,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string diff --git a/manifests/base/crds/full/argoproj.io_cronworkflows.yaml b/manifests/base/crds/full/argoproj.io_cronworkflows.yaml index 611e28aca096..d9b19ee4b4be 100644 --- a/manifests/base/crds/full/argoproj.io_cronworkflows.yaml +++ b/manifests/base/crds/full/argoproj.io_cronworkflows.yaml @@ -2147,6 +2147,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -2165,6 +2174,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object templateDefaults: properties: @@ -10615,6 +10643,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -10633,6 +10670,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string @@ -19869,6 +19925,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -19887,6 +19952,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string diff --git a/manifests/base/crds/full/argoproj.io_workflows.yaml b/manifests/base/crds/full/argoproj.io_workflows.yaml index 2d6a8a02405e..b501d969e6e8 100644 --- a/manifests/base/crds/full/argoproj.io_workflows.yaml +++ b/manifests/base/crds/full/argoproj.io_workflows.yaml @@ -2127,6 +2127,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -2145,6 +2154,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object templateDefaults: properties: @@ -10595,6 +10623,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -10613,6 +10650,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string @@ -19849,6 +19905,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -19867,6 +19932,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string @@ -33180,6 +33264,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -33198,6 +33291,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string @@ -36073,6 +36185,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -36091,6 +36212,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object templateDefaults: properties: @@ -44541,6 +44681,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -44559,6 +44708,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string @@ -53795,6 +53963,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -53813,6 +53990,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string diff --git a/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml b/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml index 087c4fb484b2..e58713d8b69f 100644 --- a/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml +++ b/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml @@ -8476,6 +8476,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -8494,6 +8503,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string diff --git a/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml b/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml index 33c51b31775f..124cb6dd17f5 100644 --- a/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml +++ b/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml @@ -2112,6 +2112,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -2130,6 +2139,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object templateDefaults: properties: @@ -10580,6 +10608,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -10598,6 +10635,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string @@ -19834,6 +19890,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -19852,6 +19917,25 @@ spec: namespace: type: string type: object + semaphores: + items: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + namespace: + type: string + type: object + type: array type: object timeout: type: string diff --git a/pkg/apis/api-rules/violation_exceptions.list b/pkg/apis/api-rules/violation_exceptions.list index ccf495af1bfb..dc3b89a0917c 100644 --- a/pkg/apis/api-rules/violation_exceptions.list +++ b/pkg/apis/api-rules/violation_exceptions.list @@ -28,6 +28,8 @@ API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/ API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,SemaphoreStatus,Holding API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,SemaphoreStatus,Waiting API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,SubmitOpts,Parameters +API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,Synchronization,Mutexes +API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,Synchronization,Semaphores API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,Template,HostAliases API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,Template,InitContainers API rule violation: list_type_missing,github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1,Template,Sidecars diff --git a/pkg/apis/workflow/v1alpha1/generated.pb.go b/pkg/apis/workflow/v1alpha1/generated.pb.go index bac8a6e05c23..a75856f9a30a 100644 --- a/pkg/apis/workflow/v1alpha1/generated.pb.go +++ b/pkg/apis/workflow/v1alpha1/generated.pb.go @@ -4448,702 +4448,704 @@ func init() { } var fileDescriptor_724696e352c3df5f = []byte{ - // 11111 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0xbd, 0x6b, 0x70, 0x64, 0xc7, - 0x75, 0x18, 0xcc, 0x3b, 0xc0, 0xe0, 0x71, 0x06, 0xc0, 0x62, 0x7b, 0x5f, 0x43, 0x2c, 0xb9, 0xa0, - 0x2f, 0x45, 0x7e, 0xa4, 0x4d, 0x61, 0xcd, 0xa5, 0xf4, 0x85, 0x91, 0x12, 0x49, 0x78, 0x2c, 0xb0, - 0x4b, 0x2c, 0x16, 0x60, 0x0f, 0x76, 0xd7, 0xa4, 0x68, 0x49, 0x17, 0x33, 0x8d, 0x99, 0x4b, 0xcc, - 0xdc, 0x3b, 0xbc, 0xf7, 0x0e, 0x76, 0xc1, 0x87, 0xa4, 0x50, 0xef, 0x58, 0xb6, 0x62, 0x59, 0x92, - 0x25, 0x25, 0xa9, 0x52, 0x14, 0x29, 0x61, 0xc9, 0xae, 0xa4, 0xec, 0x5f, 0x29, 0xfb, 0x5f, 0x2a, - 0xe5, 0x52, 0xca, 0xa9, 0x44, 0xae, 0x28, 0x25, 0xfd, 0xb0, 0xc1, 0x68, 0x93, 0xe8, 0x47, 0x12, - 0x55, 0xc5, 0xaa, 0x38, 0xb1, 0x37, 0x8f, 0x4a, 0xf5, 0xf3, 0x76, 0xdf, 0xb9, 0x83, 0x1d, 0x60, - 0x1b, 0x58, 0x95, 0xfd, 0x0b, 0x98, 0xd3, 0xdd, 0xe7, 0x74, 0xf7, 0xed, 0x3e, 0x7d, 0x5e, 0x7d, - 0x1a, 0xd6, 0xea, 0x7e, 0xd2, 0xe8, 0x6c, 0xcc, 0x54, 0xc3, 0xd6, 0x79, 0x2f, 0xaa, 0x87, 0xed, - 0x28, 0x7c, 0x99, 0xfd, 0xf3, 0xce, 0x9b, 0x61, 0xb4, 0xb5, 0xd9, 0x0c, 0x6f, 0xc6, 0xe7, 0xb7, - 0x9f, 0x39, 0xdf, 0xde, 0xaa, 0x9f, 0xf7, 0xda, 0x7e, 0x7c, 0x5e, 0x42, 0xcf, 0x6f, 0x3f, 0xed, - 0x35, 0xdb, 0x0d, 0xef, 0xe9, 0xf3, 0x75, 0x12, 0x90, 0xc8, 0x4b, 0x48, 0x6d, 0xa6, 0x1d, 0x85, - 0x49, 0x88, 0x3e, 0x90, 0x62, 0x9c, 0x91, 0x18, 0xd9, 0x3f, 0x1f, 0x56, 0x18, 0x67, 0xb6, 0x9f, - 0x99, 0x69, 0x6f, 0xd5, 0x67, 0x28, 0xc6, 0x19, 0x09, 0x9d, 0x91, 0x18, 0xa7, 0xde, 0xa9, 0xf5, - 0xa9, 0x1e, 0xd6, 0xc3, 0xf3, 0x0c, 0xf1, 0x46, 0x67, 0x93, 0xfd, 0x62, 0x3f, 0xd8, 0x7f, 0x9c, - 0xe0, 0x94, 0xbb, 0xf5, 0x6c, 0x3c, 0xe3, 0x87, 0xb4, 0x7f, 0xe7, 0xab, 0x61, 0x44, 0xce, 0x6f, - 0x77, 0x75, 0x6a, 0xea, 0x1d, 0x5a, 0x9d, 0x76, 0xd8, 0xf4, 0xab, 0x3b, 0x79, 0xb5, 0xde, 0x95, - 0xd6, 0x6a, 0x79, 0xd5, 0x86, 0x1f, 0x90, 0x68, 0x27, 0x1d, 0x7a, 0x8b, 0x24, 0x5e, 0x5e, 0xab, - 0xf3, 0xbd, 0x5a, 0x45, 0x9d, 0x20, 0xf1, 0x5b, 0xa4, 0xab, 0xc1, 0xff, 0x7f, 0xb7, 0x06, 0x71, - 0xb5, 0x41, 0x5a, 0x5e, 0x57, 0xbb, 0x67, 0x7a, 0xb5, 0xeb, 0x24, 0x7e, 0xf3, 0xbc, 0x1f, 0x24, - 0x71, 0x12, 0x65, 0x1b, 0xb9, 0x17, 0x61, 0x68, 0xb6, 0x15, 0x76, 0x82, 0x04, 0xbd, 0x17, 0x8a, - 0xdb, 0x5e, 0xb3, 0x43, 0xca, 0xce, 0x23, 0xce, 0x13, 0xa3, 0x73, 0x8f, 0x7d, 0x77, 0x77, 0xfa, - 0x81, 0xdb, 0xbb, 0xd3, 0xc5, 0xeb, 0x14, 0x78, 0x67, 0x77, 0xfa, 0x24, 0x09, 0xaa, 0x61, 0xcd, - 0x0f, 0xea, 0xe7, 0x5f, 0x8e, 0xc3, 0x60, 0xe6, 0x6a, 0xa7, 0xb5, 0x41, 0x22, 0xcc, 0xdb, 0xb8, - 0xff, 0xb6, 0x00, 0xc7, 0x66, 0xa3, 0x6a, 0xc3, 0xdf, 0x26, 0x95, 0x84, 0xe2, 0xaf, 0xef, 0xa0, - 0x06, 0x0c, 0x24, 0x5e, 0xc4, 0xd0, 0x95, 0x2e, 0xac, 0xcc, 0xdc, 0xeb, 0x77, 0x9f, 0x59, 0xf7, - 0x22, 0x89, 0x7b, 0x6e, 0xf8, 0xf6, 0xee, 0xf4, 0xc0, 0xba, 0x17, 0x61, 0x4a, 0x02, 0x35, 0x61, - 0x30, 0x08, 0x03, 0x52, 0x2e, 0x30, 0x52, 0x57, 0xef, 0x9d, 0xd4, 0xd5, 0x30, 0x50, 0xe3, 0x98, - 0x1b, 0xb9, 0xbd, 0x3b, 0x3d, 0x48, 0x21, 0x98, 0x51, 0xa1, 0xe3, 0x7a, 0xd5, 0x6f, 0x97, 0x07, - 0x6c, 0x8d, 0xeb, 0x45, 0xbf, 0x6d, 0x8e, 0xeb, 0x45, 0xbf, 0x8d, 0x29, 0x09, 0xf7, 0x73, 0x05, - 0x18, 0x9d, 0x8d, 0xea, 0x9d, 0x16, 0x09, 0x92, 0x18, 0x7d, 0x0c, 0xa0, 0xed, 0x45, 0x5e, 0x8b, - 0x24, 0x24, 0x8a, 0xcb, 0xce, 0x23, 0x03, 0x4f, 0x94, 0x2e, 0x2c, 0xdf, 0x3b, 0xf9, 0x35, 0x89, - 0x73, 0x0e, 0x89, 0x4f, 0x0e, 0x0a, 0x14, 0x63, 0x8d, 0x24, 0x7a, 0x0d, 0x46, 0xbd, 0x28, 0xf1, - 0x37, 0xbd, 0x6a, 0x12, 0x97, 0x0b, 0x8c, 0xfe, 0x73, 0xf7, 0x4e, 0x7f, 0x56, 0xa0, 0x9c, 0x3b, - 0x2e, 0xc8, 0x8f, 0x4a, 0x48, 0x8c, 0x53, 0x7a, 0xee, 0xef, 0x0d, 0x42, 0x69, 0x36, 0x4a, 0x96, - 0xe6, 0x2b, 0x89, 0x97, 0x74, 0x62, 0xf4, 0x87, 0x0e, 0x9c, 0x88, 0xf9, 0xb4, 0xf9, 0x24, 0x5e, - 0x8b, 0xc2, 0x2a, 0x89, 0x63, 0x52, 0x13, 0xf3, 0xb2, 0x69, 0xa5, 0x5f, 0x92, 0xd8, 0x4c, 0xa5, - 0x9b, 0xd0, 0xc5, 0x20, 0x89, 0x76, 0xe6, 0x9e, 0x16, 0x7d, 0x3e, 0x91, 0x53, 0xe3, 0xcd, 0xb7, - 0xa7, 0x91, 0x1c, 0x0a, 0xc5, 0xc4, 0x3f, 0x31, 0xce, 0xeb, 0x35, 0xfa, 0x9a, 0x03, 0x63, 0xed, - 0xb0, 0x16, 0x63, 0x52, 0x0d, 0x3b, 0x6d, 0x52, 0x13, 0xd3, 0xfb, 0x61, 0xbb, 0xc3, 0x58, 0xd3, - 0x28, 0xf0, 0xfe, 0x9f, 0x14, 0xfd, 0x1f, 0xd3, 0x8b, 0xb0, 0xd1, 0x15, 0xf4, 0x2c, 0x8c, 0x05, - 0x61, 0x52, 0x69, 0x93, 0xaa, 0xbf, 0xe9, 0x93, 0x1a, 0x5b, 0xf8, 0x23, 0x69, 0xcb, 0xab, 0x5a, - 0x19, 0x36, 0x6a, 0x4e, 0x2d, 0x42, 0xb9, 0xd7, 0xcc, 0xa1, 0x49, 0x18, 0xd8, 0x22, 0x3b, 0x9c, - 0xd9, 0x60, 0xfa, 0x2f, 0x3a, 0x29, 0x19, 0x10, 0xdd, 0xc6, 0x23, 0x82, 0xb3, 0xbc, 0xa7, 0xf0, - 0xac, 0x33, 0xf5, 0x7e, 0x38, 0xde, 0xd5, 0xf5, 0xfd, 0x20, 0x70, 0xbf, 0x37, 0x04, 0x23, 0xf2, - 0x53, 0xa0, 0x47, 0x60, 0x30, 0xf0, 0x5a, 0x92, 0xcf, 0x8d, 0x89, 0x71, 0x0c, 0x5e, 0xf5, 0x5a, - 0x74, 0x87, 0x7b, 0x2d, 0x42, 0x6b, 0xb4, 0xbd, 0xa4, 0xc1, 0xf0, 0x68, 0x35, 0xd6, 0xbc, 0xa4, - 0x81, 0x59, 0x09, 0x7a, 0x08, 0x06, 0x5b, 0x61, 0x8d, 0xb0, 0xb9, 0x28, 0x72, 0x0e, 0xb1, 0x12, - 0xd6, 0x08, 0x66, 0x50, 0xda, 0x7e, 0x33, 0x0a, 0x5b, 0xe5, 0x41, 0xb3, 0xfd, 0x62, 0x14, 0xb6, - 0x30, 0x2b, 0x41, 0x5f, 0x75, 0x60, 0x52, 0xae, 0xed, 0x2b, 0x61, 0xd5, 0x4b, 0xfc, 0x30, 0x28, - 0x17, 0x19, 0x47, 0xc1, 0xf6, 0xb6, 0x94, 0xc4, 0x3c, 0x57, 0x16, 0x5d, 0x98, 0xcc, 0x96, 0xe0, - 0xae, 0x5e, 0xa0, 0x0b, 0x00, 0xf5, 0x66, 0xb8, 0xe1, 0x35, 0xe9, 0x84, 0x94, 0x87, 0xd8, 0x10, - 0x14, 0x67, 0x58, 0x52, 0x25, 0x58, 0xab, 0x85, 0x6e, 0xc1, 0xb0, 0xc7, 0xb9, 0x7f, 0x79, 0x98, - 0x0d, 0xe2, 0x79, 0x1b, 0x83, 0x30, 0x8e, 0x93, 0xb9, 0xd2, 0xed, 0xdd, 0xe9, 0x61, 0x01, 0xc4, - 0x92, 0x1c, 0x7a, 0x0a, 0x46, 0xc2, 0x36, 0xed, 0xb7, 0xd7, 0x2c, 0x8f, 0xb0, 0x85, 0x39, 0x29, - 0xfa, 0x3a, 0xb2, 0x2a, 0xe0, 0x58, 0xd5, 0x40, 0x4f, 0xc2, 0x70, 0xdc, 0xd9, 0xa0, 0xdf, 0xb1, - 0x3c, 0xca, 0x06, 0x76, 0x4c, 0x54, 0x1e, 0xae, 0x70, 0x30, 0x96, 0xe5, 0xe8, 0xdd, 0x50, 0x8a, - 0x48, 0xb5, 0x13, 0xc5, 0x84, 0x7e, 0xd8, 0x32, 0x30, 0xdc, 0x27, 0x44, 0xf5, 0x12, 0x4e, 0x8b, - 0xb0, 0x5e, 0x0f, 0xbd, 0x0f, 0x26, 0xe8, 0x07, 0xbe, 0x78, 0xab, 0x1d, 0x91, 0x38, 0xa6, 0x5f, - 0xb5, 0xc4, 0x08, 0x9d, 0x16, 0x2d, 0x27, 0x16, 0x8d, 0x52, 0x9c, 0xa9, 0x8d, 0x5e, 0x07, 0xf0, - 0x14, 0xcf, 0x28, 0x8f, 0xb1, 0xc9, 0xbc, 0x62, 0x6f, 0x45, 0x2c, 0xcd, 0xcf, 0x4d, 0xd0, 0xef, + // 11152 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0xbd, 0x7b, 0x70, 0x24, 0xc7, + 0x79, 0x18, 0xce, 0x59, 0x60, 0xf1, 0xf8, 0x16, 0xc0, 0xe1, 0xfa, 0x5e, 0x4b, 0x1c, 0x79, 0xa0, + 0x87, 0x22, 0x7f, 0xa4, 0x4d, 0xe1, 0xcc, 0xa3, 0xf4, 0x0b, 0x23, 0x25, 0x92, 0xf0, 0x38, 0xe0, + 0x8e, 0x00, 0x0e, 0x60, 0x2f, 0xee, 0xce, 0xa4, 0x68, 0x49, 0x83, 0xdd, 0xc6, 0xee, 0x10, 0xbb, + 0x33, 0xcb, 0x99, 0x59, 0xdc, 0x81, 0x0f, 0x49, 0xa1, 0xde, 0xb1, 0x6c, 0xc5, 0xb2, 0x24, 0x4b, + 0x4a, 0x52, 0xa5, 0x28, 0x52, 0xc2, 0x92, 0x5d, 0x49, 0xd9, 0x7f, 0xa5, 0xec, 0xff, 0x52, 0x29, + 0x97, 0x52, 0x4e, 0x25, 0x72, 0x45, 0x29, 0xe9, 0x0f, 0x1b, 0x8c, 0x2e, 0x89, 0x2a, 0x95, 0x44, + 0x55, 0xb1, 0x2a, 0x4e, 0xe2, 0xcb, 0xa3, 0x52, 0xfd, 0x9c, 0xee, 0xd9, 0x59, 0xdc, 0xe2, 0xae, + 0x81, 0x53, 0xd9, 0x7f, 0x01, 0xfb, 0x75, 0xf7, 0xf7, 0x75, 0xf7, 0x74, 0x7f, 0xfd, 0xbd, 0xfa, + 0x6b, 0x58, 0xaf, 0xfb, 0x49, 0xa3, 0xb3, 0x39, 0x53, 0x0d, 0x5b, 0xe7, 0xbd, 0xa8, 0x1e, 0xb6, + 0xa3, 0xf0, 0x65, 0xf6, 0xcf, 0x3b, 0x6f, 0x84, 0xd1, 0xf6, 0x56, 0x33, 0xbc, 0x11, 0x9f, 0xdf, + 0x79, 0xe6, 0x7c, 0x7b, 0xbb, 0x7e, 0xde, 0x6b, 0xfb, 0xf1, 0x79, 0x09, 0x3d, 0xbf, 0xf3, 0xb4, + 0xd7, 0x6c, 0x37, 0xbc, 0xa7, 0xcf, 0xd7, 0x49, 0x40, 0x22, 0x2f, 0x21, 0xb5, 0x99, 0x76, 0x14, + 0x26, 0x21, 0xfa, 0x40, 0x8a, 0x71, 0x46, 0x62, 0x64, 0xff, 0x7c, 0x58, 0x61, 0x9c, 0xd9, 0x79, + 0x66, 0xa6, 0xbd, 0x5d, 0x9f, 0xa1, 0x18, 0x67, 0x24, 0x74, 0x46, 0x62, 0x9c, 0x7a, 0xa7, 0xd6, + 0xa7, 0x7a, 0x58, 0x0f, 0xcf, 0x33, 0xc4, 0x9b, 0x9d, 0x2d, 0xf6, 0x8b, 0xfd, 0x60, 0xff, 0x71, + 0x82, 0x53, 0xee, 0xf6, 0xb3, 0xf1, 0x8c, 0x1f, 0xd2, 0xfe, 0x9d, 0xaf, 0x86, 0x11, 0x39, 0xbf, + 0xd3, 0xd5, 0xa9, 0xa9, 0x77, 0x68, 0x75, 0xda, 0x61, 0xd3, 0xaf, 0xee, 0xe6, 0xd5, 0x7a, 0x57, + 0x5a, 0xab, 0xe5, 0x55, 0x1b, 0x7e, 0x40, 0xa2, 0xdd, 0x74, 0xe8, 0x2d, 0x92, 0x78, 0x79, 0xad, + 0xce, 0xf7, 0x6a, 0x15, 0x75, 0x82, 0xc4, 0x6f, 0x91, 0xae, 0x06, 0xff, 0xff, 0x9d, 0x1a, 0xc4, + 0xd5, 0x06, 0x69, 0x79, 0x5d, 0xed, 0x9e, 0xe9, 0xd5, 0xae, 0x93, 0xf8, 0xcd, 0xf3, 0x7e, 0x90, + 0xc4, 0x49, 0x94, 0x6d, 0xe4, 0x5e, 0x84, 0xa1, 0xd9, 0x56, 0xd8, 0x09, 0x12, 0xf4, 0x5e, 0x28, + 0xee, 0x78, 0xcd, 0x0e, 0x29, 0x3b, 0x8f, 0x38, 0x4f, 0x8c, 0xce, 0x3d, 0xf6, 0xdd, 0xbd, 0xe9, + 0x07, 0x6e, 0xed, 0x4d, 0x17, 0xaf, 0x51, 0xe0, 0xed, 0xbd, 0xe9, 0x93, 0x24, 0xa8, 0x86, 0x35, + 0x3f, 0xa8, 0x9f, 0x7f, 0x39, 0x0e, 0x83, 0x99, 0x2b, 0x9d, 0xd6, 0x26, 0x89, 0x30, 0x6f, 0xe3, + 0xfe, 0xeb, 0x02, 0x1c, 0x9b, 0x8d, 0xaa, 0x0d, 0x7f, 0x87, 0x54, 0x12, 0x8a, 0xbf, 0xbe, 0x8b, + 0x1a, 0x30, 0x90, 0x78, 0x11, 0x43, 0x57, 0xba, 0xb0, 0x3a, 0x73, 0xaf, 0xdf, 0x7d, 0x66, 0xc3, + 0x8b, 0x24, 0xee, 0xb9, 0xe1, 0x5b, 0x7b, 0xd3, 0x03, 0x1b, 0x5e, 0x84, 0x29, 0x09, 0xd4, 0x84, + 0xc1, 0x20, 0x0c, 0x48, 0xb9, 0xc0, 0x48, 0x5d, 0xb9, 0x77, 0x52, 0x57, 0xc2, 0x40, 0x8d, 0x63, + 0x6e, 0xe4, 0xd6, 0xde, 0xf4, 0x20, 0x85, 0x60, 0x46, 0x85, 0x8e, 0xeb, 0x55, 0xbf, 0x5d, 0x1e, + 0xb0, 0x35, 0xae, 0x17, 0xfd, 0xb6, 0x39, 0xae, 0x17, 0xfd, 0x36, 0xa6, 0x24, 0xdc, 0xcf, 0x15, + 0x60, 0x74, 0x36, 0xaa, 0x77, 0x5a, 0x24, 0x48, 0x62, 0xf4, 0x31, 0x80, 0xb6, 0x17, 0x79, 0x2d, + 0x92, 0x90, 0x28, 0x2e, 0x3b, 0x8f, 0x0c, 0x3c, 0x51, 0xba, 0xb0, 0x7c, 0xef, 0xe4, 0xd7, 0x25, + 0xce, 0x39, 0x24, 0x3e, 0x39, 0x28, 0x50, 0x8c, 0x35, 0x92, 0xe8, 0x35, 0x18, 0xf5, 0xa2, 0xc4, + 0xdf, 0xf2, 0xaa, 0x49, 0x5c, 0x2e, 0x30, 0xfa, 0xcf, 0xdd, 0x3b, 0xfd, 0x59, 0x81, 0x72, 0xee, + 0xb8, 0x20, 0x3f, 0x2a, 0x21, 0x31, 0x4e, 0xe9, 0xb9, 0xbf, 0x37, 0x08, 0xa5, 0xd9, 0x28, 0x59, + 0x9a, 0xaf, 0x24, 0x5e, 0xd2, 0x89, 0xd1, 0x1f, 0x3a, 0x70, 0x22, 0xe6, 0xd3, 0xe6, 0x93, 0x78, + 0x3d, 0x0a, 0xab, 0x24, 0x8e, 0x49, 0x4d, 0xcc, 0xcb, 0x96, 0x95, 0x7e, 0x49, 0x62, 0x33, 0x95, + 0x6e, 0x42, 0x17, 0x83, 0x24, 0xda, 0x9d, 0x7b, 0x5a, 0xf4, 0xf9, 0x44, 0x4e, 0x8d, 0x37, 0xdf, + 0x9e, 0x46, 0x72, 0x28, 0x14, 0x13, 0xff, 0xc4, 0x38, 0xaf, 0xd7, 0xe8, 0x6b, 0x0e, 0x8c, 0xb5, + 0xc3, 0x5a, 0x8c, 0x49, 0x35, 0xec, 0xb4, 0x49, 0x4d, 0x4c, 0xef, 0x87, 0xed, 0x0e, 0x63, 0x5d, + 0xa3, 0xc0, 0xfb, 0x7f, 0x52, 0xf4, 0x7f, 0x4c, 0x2f, 0xc2, 0x46, 0x57, 0xd0, 0xb3, 0x30, 0x16, + 0x84, 0x49, 0xa5, 0x4d, 0xaa, 0xfe, 0x96, 0x4f, 0x6a, 0x6c, 0xe1, 0x8f, 0xa4, 0x2d, 0xaf, 0x68, + 0x65, 0xd8, 0xa8, 0x39, 0xb5, 0x08, 0xe5, 0x5e, 0x33, 0x87, 0x26, 0x61, 0x60, 0x9b, 0xec, 0x72, + 0x66, 0x83, 0xe9, 0xbf, 0xe8, 0xa4, 0x64, 0x40, 0x74, 0x1b, 0x8f, 0x08, 0xce, 0xf2, 0x9e, 0xc2, + 0xb3, 0xce, 0xd4, 0xfb, 0xe1, 0x78, 0x57, 0xd7, 0x0f, 0x82, 0xc0, 0xfd, 0xde, 0x10, 0x8c, 0xc8, + 0x4f, 0x81, 0x1e, 0x81, 0xc1, 0xc0, 0x6b, 0x49, 0x3e, 0x37, 0x26, 0xc6, 0x31, 0x78, 0xc5, 0x6b, + 0xd1, 0x1d, 0xee, 0xb5, 0x08, 0xad, 0xd1, 0xf6, 0x92, 0x06, 0xc3, 0xa3, 0xd5, 0x58, 0xf7, 0x92, + 0x06, 0x66, 0x25, 0xe8, 0x21, 0x18, 0x6c, 0x85, 0x35, 0xc2, 0xe6, 0xa2, 0xc8, 0x39, 0xc4, 0x6a, + 0x58, 0x23, 0x98, 0x41, 0x69, 0xfb, 0xad, 0x28, 0x6c, 0x95, 0x07, 0xcd, 0xf6, 0x8b, 0x51, 0xd8, + 0xc2, 0xac, 0x04, 0x7d, 0xd5, 0x81, 0x49, 0xb9, 0xb6, 0x57, 0xc2, 0xaa, 0x97, 0xf8, 0x61, 0x50, + 0x2e, 0x32, 0x8e, 0x82, 0xed, 0x6d, 0x29, 0x89, 0x79, 0xae, 0x2c, 0xba, 0x30, 0x99, 0x2d, 0xc1, + 0x5d, 0xbd, 0x40, 0x17, 0x00, 0xea, 0xcd, 0x70, 0xd3, 0x6b, 0xd2, 0x09, 0x29, 0x0f, 0xb1, 0x21, + 0x28, 0xce, 0xb0, 0xa4, 0x4a, 0xb0, 0x56, 0x0b, 0xdd, 0x84, 0x61, 0x8f, 0x73, 0xff, 0xf2, 0x30, + 0x1b, 0xc4, 0xf3, 0x36, 0x06, 0x61, 0x1c, 0x27, 0x73, 0xa5, 0x5b, 0x7b, 0xd3, 0xc3, 0x02, 0x88, + 0x25, 0x39, 0xf4, 0x14, 0x8c, 0x84, 0x6d, 0xda, 0x6f, 0xaf, 0x59, 0x1e, 0x61, 0x0b, 0x73, 0x52, + 0xf4, 0x75, 0x64, 0x4d, 0xc0, 0xb1, 0xaa, 0x81, 0x9e, 0x84, 0xe1, 0xb8, 0xb3, 0x49, 0xbf, 0x63, + 0x79, 0x94, 0x0d, 0xec, 0x98, 0xa8, 0x3c, 0x5c, 0xe1, 0x60, 0x2c, 0xcb, 0xd1, 0xbb, 0xa1, 0x14, + 0x91, 0x6a, 0x27, 0x8a, 0x09, 0xfd, 0xb0, 0x65, 0x60, 0xb8, 0x4f, 0x88, 0xea, 0x25, 0x9c, 0x16, + 0x61, 0xbd, 0x1e, 0x7a, 0x1f, 0x4c, 0xd0, 0x0f, 0x7c, 0xf1, 0x66, 0x3b, 0x22, 0x71, 0x4c, 0xbf, + 0x6a, 0x89, 0x11, 0x3a, 0x2d, 0x5a, 0x4e, 0x2c, 0x1a, 0xa5, 0x38, 0x53, 0x1b, 0xbd, 0x0e, 0xe0, + 0x29, 0x9e, 0x51, 0x1e, 0x63, 0x93, 0xb9, 0x62, 0x6f, 0x45, 0x2c, 0xcd, 0xcf, 0x4d, 0xd0, 0xef, 0x98, 0xfe, 0xc6, 0x1a, 0x3d, 0x3a, 0x3f, 0x35, 0xd2, 0x24, 0x09, 0xa9, 0x95, 0xc7, 0xd9, 0x80, - 0xd5, 0xfc, 0x2c, 0x70, 0x30, 0x96, 0xe5, 0xee, 0xdf, 0x2d, 0x80, 0x86, 0x05, 0xcd, 0xc1, 0x88, - 0xe0, 0x6b, 0x62, 0x4b, 0xce, 0x3d, 0x2e, 0xbf, 0x83, 0xfc, 0x82, 0x77, 0x76, 0x73, 0xf9, 0xa1, - 0x6a, 0x87, 0xde, 0x80, 0x52, 0x3b, 0xac, 0xad, 0x90, 0xc4, 0xab, 0x79, 0x89, 0x27, 0x4e, 0x73, - 0x0b, 0x27, 0x8c, 0xc4, 0x38, 0x77, 0x8c, 0x7e, 0xba, 0xb5, 0x94, 0x04, 0xd6, 0xe9, 0xa1, 0xe7, - 0x00, 0xc5, 0x24, 0xda, 0xf6, 0xab, 0x64, 0xb6, 0x5a, 0xa5, 0x22, 0x11, 0xdb, 0x00, 0x03, 0x6c, + 0xd5, 0xfc, 0x2c, 0x70, 0x30, 0x96, 0xe5, 0xee, 0xdf, 0x2e, 0x80, 0x86, 0x05, 0xcd, 0xc1, 0x88, + 0xe0, 0x6b, 0x62, 0x4b, 0xce, 0x3d, 0x2e, 0xbf, 0x83, 0xfc, 0x82, 0xb7, 0xf7, 0x72, 0xf9, 0xa1, + 0x6a, 0x87, 0xde, 0x80, 0x52, 0x3b, 0xac, 0xad, 0x92, 0xc4, 0xab, 0x79, 0x89, 0x27, 0x4e, 0x73, + 0x0b, 0x27, 0x8c, 0xc4, 0x38, 0x77, 0x8c, 0x7e, 0xba, 0xf5, 0x94, 0x04, 0xd6, 0xe9, 0xa1, 0xe7, + 0x00, 0xc5, 0x24, 0xda, 0xf1, 0xab, 0x64, 0xb6, 0x5a, 0xa5, 0x22, 0x11, 0xdb, 0x00, 0x03, 0x6c, 0x30, 0x53, 0x62, 0x30, 0xa8, 0xd2, 0x55, 0x03, 0xe7, 0xb4, 0x72, 0xbf, 0x5f, 0x80, 0x09, 0x6d, - 0xac, 0x6d, 0x52, 0x45, 0x6f, 0x39, 0x70, 0x4c, 0x1d, 0x67, 0x73, 0x3b, 0x57, 0xe9, 0xaa, 0xe2, + 0xac, 0x6d, 0x52, 0x45, 0x6f, 0x39, 0x70, 0x4c, 0x1d, 0x67, 0x73, 0xbb, 0x57, 0xe8, 0xaa, 0xe2, 0x87, 0x15, 0xb1, 0xf9, 0x7d, 0x29, 0x2d, 0xf5, 0x53, 0xd0, 0xe1, 0xbc, 0xfe, 0x8c, 0x18, 0xc3, 0xb1, 0x4c, 0x29, 0xce, 0x76, 0x6b, 0xea, 0x2b, 0x0e, 0x9c, 0xcc, 0x43, 0x91, 0xc3, 0x73, 0x1b, 0x3a, 0xcf, 0xb5, 0xca, 0xbc, 0x28, 0x55, 0x3a, 0x18, 0x9d, 0x8f, 0xff, 0xdf, 0x02, 0x4c, 0xea, - 0x4b, 0x88, 0x49, 0x02, 0xff, 0xdc, 0x81, 0x53, 0x72, 0x04, 0x98, 0xc4, 0x9d, 0x66, 0x66, 0x7a, + 0x4b, 0x88, 0x49, 0x02, 0xff, 0xd4, 0x81, 0x53, 0x72, 0x04, 0x98, 0xc4, 0x9d, 0x66, 0x66, 0x7a, 0x5b, 0x56, 0xa7, 0x97, 0x9f, 0xa4, 0xb3, 0x79, 0xf4, 0xf8, 0x34, 0x3f, 0x2c, 0xa6, 0xf9, 0x54, 0x6e, 0x1d, 0x9c, 0xdf, 0xd5, 0xa9, 0x6f, 0x39, 0x30, 0xd5, 0x1b, 0x69, 0xce, 0xc4, 0xb7, 0xcd, 0x89, 0x7f, 0xd1, 0xde, 0x20, 0x39, 0x79, 0x36, 0xfd, 0x6c, 0xb0, 0xfa, 0x07, 0xf8, 0xed, 0x11, - 0xe8, 0x3a, 0x43, 0xd0, 0xd3, 0x50, 0x12, 0xec, 0xf8, 0x4a, 0x58, 0x8f, 0x59, 0x27, 0x47, 0xf8, - 0x5e, 0x9b, 0x4d, 0xc1, 0x58, 0xaf, 0x83, 0x6a, 0x50, 0x88, 0x9f, 0x11, 0x5d, 0xb7, 0xc0, 0xde, - 0x2a, 0xcf, 0x28, 0x29, 0x72, 0xe8, 0xf6, 0xee, 0x74, 0xa1, 0xf2, 0x0c, 0x2e, 0xc4, 0xcf, 0x50, - 0x49, 0xbd, 0xee, 0x27, 0xf6, 0x24, 0xf5, 0x25, 0x3f, 0x51, 0x74, 0x98, 0xa4, 0xbe, 0xe4, 0x27, - 0x98, 0x92, 0xa0, 0x1a, 0x48, 0x23, 0x49, 0xda, 0xec, 0xc4, 0xb7, 0xa2, 0x81, 0x5c, 0x5a, 0x5f, - 0x5f, 0x53, 0xb4, 0x98, 0x7c, 0x41, 0x21, 0x98, 0x51, 0x41, 0x9f, 0x75, 0xe8, 0x8c, 0xf3, 0xc2, - 0x30, 0xda, 0x11, 0x82, 0xc3, 0x35, 0x7b, 0x4b, 0x20, 0x8c, 0x76, 0x14, 0x71, 0xf1, 0x21, 0x55, - 0x01, 0xd6, 0x49, 0xb3, 0x81, 0xd7, 0x36, 0x63, 0x26, 0x27, 0xd8, 0x19, 0xf8, 0xc2, 0x62, 0x25, - 0x33, 0xf0, 0x85, 0xc5, 0x0a, 0x66, 0x54, 0xe8, 0x07, 0x8d, 0xbc, 0x9b, 0x42, 0xc6, 0xb0, 0xf0, - 0x41, 0xb1, 0x77, 0xd3, 0xfc, 0xa0, 0xd8, 0xbb, 0x89, 0x29, 0x09, 0x4a, 0x29, 0x8c, 0x63, 0x26, - 0x52, 0x58, 0xa1, 0xb4, 0x5a, 0xa9, 0x98, 0x94, 0x56, 0x2b, 0x15, 0x4c, 0x49, 0xb0, 0x45, 0x5a, - 0x8d, 0x99, 0x3c, 0x62, 0x67, 0x91, 0xce, 0x67, 0x28, 0x2d, 0xcd, 0x57, 0x30, 0x25, 0x41, 0x59, - 0x86, 0xf7, 0x6a, 0x27, 0xe2, 0xc2, 0x4c, 0xe9, 0xc2, 0xaa, 0x85, 0xf5, 0x42, 0xd1, 0x29, 0x6a, - 0xa3, 0xb7, 0x77, 0xa7, 0x8b, 0x0c, 0x84, 0x39, 0x21, 0xf7, 0x0f, 0x06, 0x52, 0x76, 0x21, 0xf9, - 0x39, 0xfa, 0x75, 0x76, 0x10, 0x0a, 0x5e, 0x20, 0x44, 0x5f, 0xe7, 0xd0, 0x44, 0xdf, 0x13, 0xfc, - 0xc4, 0x33, 0xc8, 0xe1, 0x2c, 0x7d, 0xf4, 0x45, 0xa7, 0x5b, 0xb7, 0xf5, 0xec, 0x9f, 0x65, 0xe9, - 0xc1, 0xcc, 0xcf, 0x8a, 0x3d, 0x55, 0xde, 0xa9, 0xcf, 0x3a, 0xa9, 0x10, 0x11, 0xf7, 0x3a, 0x07, - 0x3e, 0x62, 0x9e, 0x03, 0x16, 0x15, 0x72, 0x9d, 0xef, 0x7f, 0xce, 0x81, 0x71, 0x09, 0xa7, 0xe2, - 0x71, 0x8c, 0x6e, 0xc1, 0x88, 0xec, 0xa9, 0xf8, 0x7a, 0x36, 0x6d, 0x01, 0x4a, 0x88, 0x57, 0x9d, - 0x51, 0xd4, 0xdc, 0xb7, 0x86, 0x00, 0xa5, 0x67, 0x55, 0x3b, 0x8c, 0x7d, 0xc6, 0x89, 0x0e, 0x70, - 0x0a, 0x05, 0xda, 0x29, 0x74, 0xdd, 0xe6, 0x29, 0x94, 0x76, 0xcb, 0x38, 0x8f, 0xbe, 0x98, 0xe1, - 0xdb, 0xfc, 0x60, 0xfa, 0xf0, 0xa1, 0xf0, 0x6d, 0xad, 0x0b, 0x7b, 0x73, 0xf0, 0x6d, 0xc1, 0xc1, + 0xe8, 0x3a, 0x43, 0xd0, 0xd3, 0x50, 0x12, 0xec, 0x78, 0x25, 0xac, 0xc7, 0xac, 0x93, 0x23, 0x7c, + 0xaf, 0xcd, 0xa6, 0x60, 0xac, 0xd7, 0x41, 0x35, 0x28, 0xc4, 0xcf, 0x88, 0xae, 0x5b, 0x60, 0x6f, + 0x95, 0x67, 0x94, 0x14, 0x39, 0x74, 0x6b, 0x6f, 0xba, 0x50, 0x79, 0x06, 0x17, 0xe2, 0x67, 0xa8, + 0xa4, 0x5e, 0xf7, 0x13, 0x7b, 0x92, 0xfa, 0x92, 0x9f, 0x28, 0x3a, 0x4c, 0x52, 0x5f, 0xf2, 0x13, + 0x4c, 0x49, 0x50, 0x0d, 0xa4, 0x91, 0x24, 0x6d, 0x76, 0xe2, 0x5b, 0xd1, 0x40, 0x2e, 0x6d, 0x6c, + 0xac, 0x2b, 0x5a, 0x4c, 0xbe, 0xa0, 0x10, 0xcc, 0xa8, 0xa0, 0xcf, 0x3a, 0x74, 0xc6, 0x79, 0x61, + 0x18, 0xed, 0x0a, 0xc1, 0xe1, 0xaa, 0xbd, 0x25, 0x10, 0x46, 0xbb, 0x8a, 0xb8, 0xf8, 0x90, 0xaa, + 0x00, 0xeb, 0xa4, 0xd9, 0xc0, 0x6b, 0x5b, 0x31, 0x93, 0x13, 0xec, 0x0c, 0x7c, 0x61, 0xb1, 0x92, + 0x19, 0xf8, 0xc2, 0x62, 0x05, 0x33, 0x2a, 0xf4, 0x83, 0x46, 0xde, 0x0d, 0x21, 0x63, 0x58, 0xf8, + 0xa0, 0xd8, 0xbb, 0x61, 0x7e, 0x50, 0xec, 0xdd, 0xc0, 0x94, 0x04, 0xa5, 0x14, 0xc6, 0x31, 0x13, + 0x29, 0xac, 0x50, 0x5a, 0xab, 0x54, 0x4c, 0x4a, 0x6b, 0x95, 0x0a, 0xa6, 0x24, 0xd8, 0x22, 0xad, + 0xc6, 0x4c, 0x1e, 0xb1, 0xb3, 0x48, 0xe7, 0x33, 0x94, 0x96, 0xe6, 0x2b, 0x98, 0x92, 0xa0, 0x2c, + 0xc3, 0x7b, 0xb5, 0x13, 0x71, 0x61, 0xa6, 0x74, 0x61, 0xcd, 0xc2, 0x7a, 0xa1, 0xe8, 0x14, 0xb5, + 0xd1, 0x5b, 0x7b, 0xd3, 0x45, 0x06, 0xc2, 0x9c, 0x90, 0xfb, 0x07, 0x03, 0x29, 0xbb, 0x90, 0xfc, + 0x1c, 0xfd, 0x3a, 0x3b, 0x08, 0x05, 0x2f, 0x10, 0xa2, 0xaf, 0x73, 0x68, 0xa2, 0xef, 0x09, 0x7e, + 0xe2, 0x19, 0xe4, 0x70, 0x96, 0x3e, 0xfa, 0xa2, 0xd3, 0xad, 0xdb, 0x7a, 0xf6, 0xcf, 0xb2, 0xf4, + 0x60, 0xe6, 0x67, 0xc5, 0xbe, 0x2a, 0xef, 0xd4, 0x67, 0x9d, 0x54, 0x88, 0x88, 0x7b, 0x9d, 0x03, + 0x1f, 0x31, 0xcf, 0x01, 0x8b, 0x0a, 0xb9, 0xce, 0xf7, 0x3f, 0xe7, 0xc0, 0xb8, 0x84, 0x53, 0xf1, + 0x38, 0x46, 0x37, 0x61, 0x44, 0xf6, 0x54, 0x7c, 0x3d, 0x9b, 0xb6, 0x00, 0x25, 0xc4, 0xab, 0xce, + 0x28, 0x6a, 0xee, 0x5b, 0x43, 0x80, 0xd2, 0xb3, 0xaa, 0x1d, 0xc6, 0x3e, 0xe3, 0x44, 0x77, 0x71, + 0x0a, 0x05, 0xda, 0x29, 0x74, 0xcd, 0xe6, 0x29, 0x94, 0x76, 0xcb, 0x38, 0x8f, 0xbe, 0x98, 0xe1, + 0xdb, 0xfc, 0x60, 0xfa, 0xf0, 0xa1, 0xf0, 0x6d, 0xad, 0x0b, 0xfb, 0x73, 0xf0, 0x1d, 0xc1, 0xc1, 0xf9, 0xd1, 0xf5, 0x4b, 0x76, 0x39, 0xb8, 0xd6, 0x8b, 0x2c, 0x2f, 0x8f, 0x38, 0x87, 0xe5, 0x67, - 0xd7, 0x0d, 0xab, 0x1c, 0x56, 0xa3, 0x6a, 0xf2, 0xda, 0x88, 0xf3, 0xda, 0x21, 0x5b, 0x34, 0x35, + 0xd7, 0x75, 0xab, 0x1c, 0x56, 0xa3, 0x6a, 0xf2, 0xda, 0x88, 0xf3, 0xda, 0x21, 0x5b, 0x34, 0x35, 0x5e, 0x9b, 0xa5, 0xa9, 0xb8, 0xee, 0xab, 0x92, 0xeb, 0xf2, 0x53, 0xeb, 0x05, 0xcb, 0x5c, 0x57, - 0xa3, 0xdb, 0xcd, 0x7f, 0x5f, 0x81, 0x53, 0xdd, 0xf5, 0x30, 0xd9, 0x44, 0xe7, 0x61, 0xb4, 0x1a, - 0x06, 0x9b, 0x7e, 0x7d, 0xc5, 0x6b, 0x0b, 0x7d, 0x4d, 0xf1, 0xa2, 0x79, 0x59, 0x80, 0xd3, 0x3a, - 0xe8, 0x61, 0xce, 0x78, 0xb8, 0x45, 0xa4, 0x24, 0xaa, 0x0e, 0x2c, 0x93, 0x1d, 0xc6, 0x85, 0xde, + 0xa3, 0xdb, 0xcd, 0x7f, 0x5f, 0x81, 0x53, 0xdd, 0xf5, 0x30, 0xd9, 0x42, 0xe7, 0x61, 0xb4, 0x1a, + 0x06, 0x5b, 0x7e, 0x7d, 0xd5, 0x6b, 0x0b, 0x7d, 0x4d, 0xf1, 0xa2, 0x79, 0x59, 0x80, 0xd3, 0x3a, + 0xe8, 0x61, 0xce, 0x78, 0xb8, 0x45, 0xa4, 0x24, 0xaa, 0x0e, 0x2c, 0x93, 0x5d, 0xc6, 0x85, 0xde, 0x33, 0xf2, 0xd5, 0x6f, 0x4c, 0x3f, 0xf0, 0xf1, 0x3f, 0x7e, 0xe4, 0x01, 0xf7, 0x8f, 0x06, 0xe0, - 0x6c, 0x2e, 0x4d, 0x21, 0xad, 0xff, 0xb6, 0x21, 0xad, 0x6b, 0xe5, 0x82, 0x8b, 0xdc, 0xb0, 0x29, + 0x6c, 0x2e, 0x4d, 0x21, 0xad, 0xff, 0xb6, 0x21, 0xad, 0x6b, 0xe5, 0x82, 0x8b, 0x5c, 0xb7, 0x29, 0xc8, 0x6a, 0xe8, 0xf3, 0xe4, 0x72, 0xad, 0x18, 0xe7, 0x77, 0x8a, 0x4e, 0x54, 0xe0, 0xb5, 0x48, - 0xdc, 0xf6, 0xaa, 0x44, 0x8c, 0x5e, 0x4d, 0xd4, 0x55, 0x59, 0x80, 0xd3, 0x3a, 0x5c, 0x85, 0xde, - 0xf4, 0x3a, 0xcd, 0x44, 0x18, 0xca, 0x34, 0x15, 0x9a, 0x81, 0xb1, 0x2c, 0x47, 0x7f, 0xcf, 0x01, - 0xd4, 0x4d, 0x55, 0x6c, 0xc4, 0xf5, 0xc3, 0x98, 0x87, 0xb9, 0xd3, 0xb7, 0x35, 0x25, 0x5c, 0x1b, + 0xdc, 0xf6, 0xaa, 0x44, 0x8c, 0x5e, 0x4d, 0xd4, 0x15, 0x59, 0x80, 0xd3, 0x3a, 0x5c, 0x85, 0xde, + 0xf2, 0x3a, 0xcd, 0x44, 0x18, 0xca, 0x34, 0x15, 0x9a, 0x81, 0xb1, 0x2c, 0x47, 0x7f, 0xc7, 0x01, + 0xd4, 0x4d, 0x55, 0x6c, 0xc4, 0x8d, 0xc3, 0x98, 0x87, 0xb9, 0xd3, 0xb7, 0x34, 0x25, 0x5c, 0x1b, 0x69, 0x4e, 0x3f, 0xb4, 0x6f, 0xfa, 0xd1, 0xf4, 0x1c, 0xe2, 0xca, 0x41, 0x1f, 0x36, 0x34, 0x66, 0x6a, 0xa9, 0x56, 0x49, 0x1c, 0x73, 0x73, 0x9c, 0x6e, 0x6a, 0x61, 0x60, 0x2c, 0xcb, 0xd1, 0x34, 0x14, 0x49, 0x14, 0x85, 0x91, 0xd0, 0xb5, 0xd9, 0x32, 0xbe, 0x48, 0x01, 0x98, 0xc3, 0xdd, 0x1f, 0x17, 0xa0, 0xdc, 0x4b, 0x3b, 0x41, 0xbf, 0xab, 0xe9, 0xd5, 0x42, 0x73, 0x12, 0x8a, 0x5f, 0x78, 0x78, 0x3a, 0x51, 0x56, 0x01, 0xec, 0xa1, 0x61, 0x8b, 0x52, 0x9c, 0xed, 0xe0, 0xd4, 0x97, 0x34, - 0x0d, 0x5b, 0x47, 0x91, 0x73, 0xc0, 0x6f, 0x9a, 0x07, 0xfc, 0x9a, 0xed, 0x41, 0xe9, 0xc7, 0xfc, - 0x9f, 0x14, 0xe1, 0x84, 0x2c, 0xad, 0x10, 0x7a, 0x54, 0x3e, 0xdf, 0x21, 0xd1, 0x0e, 0xfa, 0x81, + 0x0d, 0x5b, 0x47, 0x91, 0x73, 0xc0, 0x6f, 0x99, 0x07, 0xfc, 0xba, 0xed, 0x41, 0xe9, 0xc7, 0xfc, + 0x9f, 0x14, 0xe1, 0x84, 0x2c, 0xad, 0x10, 0x7a, 0x54, 0x3e, 0xdf, 0x21, 0xd1, 0x2e, 0xfa, 0x81, 0x03, 0x27, 0xbd, 0xac, 0xe9, 0xc6, 0x27, 0x87, 0x30, 0xd1, 0x1a, 0xd5, 0x99, 0xd9, 0x1c, 0x8a, 0x7c, 0xa2, 0x2f, 0x88, 0x89, 0x3e, 0x99, 0x57, 0xa5, 0x87, 0xdd, 0x3d, 0x77, 0x00, 0xe8, 0x59, 0x18, 0x93, 0x70, 0x66, 0xee, 0xe1, 0x5b, 0x5c, 0x19, 0xb7, 0x67, 0xb5, 0x32, 0x6c, 0xd4, 0xa4, - 0x2d, 0x13, 0xd2, 0x6a, 0x37, 0xbd, 0x84, 0x68, 0x86, 0x22, 0xd5, 0x72, 0x5d, 0x2b, 0xc3, 0x46, + 0x2d, 0x13, 0xd2, 0x6a, 0x37, 0xbd, 0x84, 0x68, 0x86, 0x22, 0xd5, 0x72, 0x43, 0x2b, 0xc3, 0x46, 0x4d, 0xf4, 0x38, 0x0c, 0x05, 0x61, 0x8d, 0x5c, 0xae, 0x09, 0x03, 0xf1, 0x84, 0x68, 0x33, 0x74, - 0x95, 0x41, 0xb1, 0x28, 0x45, 0x8f, 0xa5, 0xd6, 0xb8, 0x22, 0xdb, 0x42, 0xa5, 0x3c, 0x4b, 0x1c, - 0xfa, 0x07, 0x0e, 0x8c, 0xd2, 0x16, 0xeb, 0x3b, 0x6d, 0x42, 0xcf, 0x36, 0xfa, 0x45, 0x6a, 0x87, - 0xf3, 0x45, 0xae, 0x4a, 0x32, 0xa6, 0xa9, 0x63, 0x54, 0xc1, 0xdf, 0x7c, 0x7b, 0x7a, 0x44, 0xfe, - 0xc0, 0x69, 0xaf, 0xa6, 0x96, 0xe0, 0xc1, 0x9e, 0x5f, 0x73, 0x5f, 0xae, 0x80, 0xbf, 0x01, 0x13, - 0x66, 0x27, 0xf6, 0xe5, 0x07, 0xf8, 0x67, 0xda, 0xb6, 0xe3, 0xe3, 0x12, 0xfc, 0xec, 0xbe, 0x49, + 0x85, 0x41, 0xb1, 0x28, 0x45, 0x8f, 0xa5, 0xd6, 0xb8, 0x22, 0xdb, 0x42, 0xa5, 0x3c, 0x4b, 0x1c, + 0xfa, 0x7b, 0x0e, 0x8c, 0xd2, 0x16, 0x1b, 0xbb, 0x6d, 0x42, 0xcf, 0x36, 0xfa, 0x45, 0x6a, 0x87, + 0xf3, 0x45, 0xae, 0x48, 0x32, 0xa6, 0xa9, 0x63, 0x54, 0xc1, 0xdf, 0x7c, 0x7b, 0x7a, 0x44, 0xfe, + 0xc0, 0x69, 0xaf, 0xa6, 0x96, 0xe0, 0xc1, 0x9e, 0x5f, 0xf3, 0x40, 0xae, 0x80, 0xbf, 0x06, 0x13, + 0x66, 0x27, 0x0e, 0xe4, 0x07, 0xf8, 0x27, 0xda, 0xb6, 0xe3, 0xe3, 0x12, 0xfc, 0xec, 0xbe, 0x49, 0xb3, 0x6a, 0x31, 0x2c, 0x88, 0xa5, 0x67, 0x2e, 0x86, 0x05, 0xb1, 0x18, 0x16, 0xdc, 0x3f, 0x74, - 0xd2, 0xad, 0xa9, 0x89, 0x79, 0xf4, 0x60, 0xee, 0x44, 0x4d, 0xc1, 0x88, 0xd5, 0xc1, 0x7c, 0x0d, - 0x5f, 0xc1, 0x14, 0x8e, 0xbe, 0xa4, 0x71, 0x47, 0xda, 0xac, 0x23, 0xdc, 0x1a, 0x96, 0x4c, 0xf4, - 0x06, 0xe2, 0x6e, 0xfe, 0x27, 0x0a, 0x70, 0xb6, 0x0b, 0xee, 0x17, 0x0b, 0xf0, 0xf0, 0x9e, 0x42, - 0x6b, 0x6e, 0xc7, 0x9d, 0xfb, 0xde, 0x71, 0x7a, 0xac, 0x45, 0xa4, 0x1d, 0x5e, 0xc3, 0x57, 0xc4, - 0xf7, 0x52, 0xc7, 0x1a, 0xe6, 0x60, 0x2c, 0xcb, 0xa9, 0xe8, 0xb0, 0x45, 0x76, 0x16, 0xc3, 0xa8, - 0xe5, 0x25, 0x82, 0x3b, 0x28, 0xd1, 0x61, 0x59, 0x16, 0xe0, 0xb4, 0x8e, 0xfb, 0x03, 0x07, 0xb2, - 0x1d, 0x40, 0x1e, 0x4c, 0x74, 0x62, 0x12, 0xd1, 0x23, 0xb5, 0x42, 0xaa, 0x11, 0x91, 0xcb, 0xf3, - 0xb1, 0x19, 0xee, 0xed, 0xa7, 0x23, 0x9c, 0xa9, 0x86, 0x11, 0x99, 0xd9, 0x7e, 0x7a, 0x86, 0xd7, - 0x58, 0x26, 0x3b, 0x15, 0xd2, 0x24, 0x14, 0xc7, 0x1c, 0xba, 0xbd, 0x3b, 0x3d, 0x71, 0xcd, 0x40, - 0x80, 0x33, 0x08, 0x29, 0x89, 0xb6, 0x17, 0xc7, 0x37, 0xc3, 0xa8, 0x26, 0x48, 0x14, 0xf6, 0x4d, - 0x62, 0xcd, 0x40, 0x80, 0x33, 0x08, 0xdd, 0xef, 0x53, 0xf5, 0x51, 0x97, 0x5a, 0xd1, 0x37, 0xa8, - 0xec, 0x43, 0x21, 0x73, 0xcd, 0x70, 0x63, 0x3e, 0x0c, 0x12, 0xcf, 0x0f, 0x88, 0x0c, 0x16, 0x58, - 0xb7, 0x24, 0x23, 0x1b, 0xb8, 0x53, 0x1b, 0x7e, 0x77, 0x19, 0xce, 0xe9, 0x0b, 0x95, 0x71, 0x36, - 0x9a, 0xe1, 0x46, 0xd6, 0x0b, 0x48, 0x2b, 0x61, 0x56, 0xe2, 0xfe, 0xd4, 0x81, 0x33, 0x3d, 0x84, - 0x71, 0xf4, 0x15, 0x07, 0xc6, 0x37, 0x7e, 0x26, 0xc6, 0x66, 0x76, 0x03, 0xbd, 0x0f, 0x26, 0x28, - 0x80, 0x9e, 0x44, 0x62, 0x6d, 0x16, 0x4c, 0x0f, 0xd5, 0x9c, 0x51, 0x8a, 0x33, 0xb5, 0xdd, 0xdf, - 0x28, 0x40, 0x0e, 0x15, 0xf4, 0x14, 0x8c, 0x90, 0xa0, 0xd6, 0x0e, 0xfd, 0x20, 0x11, 0xcc, 0x48, - 0x71, 0xbd, 0x8b, 0x02, 0x8e, 0x55, 0x0d, 0xa1, 0x7f, 0x88, 0x89, 0x29, 0x74, 0xe9, 0x1f, 0xa2, - 0xe7, 0x69, 0x1d, 0x54, 0x87, 0x49, 0x8f, 0xfb, 0x57, 0xd8, 0xda, 0x63, 0xcb, 0x74, 0x60, 0x3f, - 0xcb, 0xf4, 0x24, 0x73, 0x7f, 0x66, 0x50, 0xe0, 0x2e, 0xa4, 0xe8, 0xdd, 0x50, 0xea, 0xc4, 0xa4, - 0xb2, 0xb0, 0x3c, 0x1f, 0x91, 0x1a, 0xd7, 0x8a, 0x35, 0xbf, 0xdf, 0xb5, 0xb4, 0x08, 0xeb, 0xf5, - 0xdc, 0x7f, 0xe1, 0xc0, 0xf0, 0x9c, 0x57, 0xdd, 0x0a, 0x37, 0x37, 0xe9, 0x54, 0xd4, 0x3a, 0x51, - 0x6a, 0xd8, 0xd2, 0xa6, 0x62, 0x41, 0xc0, 0xb1, 0xaa, 0x81, 0xd6, 0x61, 0x88, 0x6f, 0x78, 0xb1, - 0xed, 0x7e, 0x51, 0x1b, 0x8f, 0x8a, 0xe3, 0x61, 0xcb, 0xa1, 0x93, 0xf8, 0xcd, 0x19, 0x1e, 0xc7, - 0x33, 0x73, 0x39, 0x48, 0x56, 0xa3, 0x4a, 0x12, 0xf9, 0x41, 0x7d, 0x0e, 0xe8, 0x71, 0xb1, 0xc8, - 0x70, 0x60, 0x81, 0x8b, 0x0e, 0xa3, 0xe5, 0xdd, 0x92, 0xe4, 0x04, 0xfb, 0x51, 0xc3, 0x58, 0x49, - 0x8b, 0xb0, 0x5e, 0xcf, 0xfd, 0x23, 0x07, 0x46, 0xe7, 0xbc, 0xd8, 0xaf, 0xfe, 0x25, 0x62, 0x3e, - 0x1f, 0x82, 0xe2, 0xbc, 0x57, 0x6d, 0x10, 0x74, 0x2d, 0xab, 0xf4, 0x96, 0x2e, 0x3c, 0x91, 0x47, - 0x46, 0x29, 0xc0, 0x3a, 0xa5, 0xf1, 0x5e, 0xaa, 0xb1, 0xfb, 0xb6, 0x03, 0x13, 0xf3, 0x4d, 0x9f, - 0x04, 0xc9, 0x3c, 0x89, 0x12, 0x36, 0x71, 0x75, 0x98, 0xac, 0x2a, 0xc8, 0x41, 0xa6, 0x8e, 0xad, - 0xd6, 0xf9, 0x0c, 0x0a, 0xdc, 0x85, 0x14, 0xd5, 0xe0, 0x18, 0x87, 0xa5, 0xbb, 0x62, 0x5f, 0xf3, - 0xc7, 0xac, 0xa3, 0xf3, 0x26, 0x06, 0x9c, 0x45, 0xe9, 0xfe, 0xc4, 0x81, 0x33, 0xf3, 0xcd, 0x4e, - 0x9c, 0x90, 0xe8, 0x86, 0xe0, 0x46, 0x52, 0xbc, 0x45, 0x1f, 0x81, 0x91, 0x96, 0xf4, 0xd8, 0x3a, - 0x77, 0x59, 0xc0, 0x8c, 0x9f, 0xd1, 0xda, 0xb4, 0x33, 0xab, 0x1b, 0x2f, 0x93, 0x6a, 0xb2, 0x42, - 0x12, 0x2f, 0x0d, 0x2f, 0x48, 0x61, 0x58, 0x61, 0x45, 0x6d, 0x18, 0x8c, 0xdb, 0xa4, 0x6a, 0x2f, - 0xba, 0x4b, 0x8e, 0xa1, 0xd2, 0x26, 0xd5, 0x94, 0xaf, 0x33, 0x5f, 0x23, 0xa3, 0xe4, 0xfe, 0x2f, - 0x07, 0xce, 0xf6, 0x18, 0xef, 0x15, 0x3f, 0x4e, 0xd0, 0x4b, 0x5d, 0x63, 0x9e, 0xe9, 0x6f, 0xcc, - 0xb4, 0x35, 0x1b, 0xb1, 0x62, 0x08, 0x12, 0xa2, 0x8d, 0xf7, 0xa3, 0x50, 0xf4, 0x13, 0xd2, 0x92, - 0x66, 0x68, 0x0b, 0x06, 0xa3, 0x1e, 0x63, 0x99, 0x1b, 0x97, 0x31, 0x7e, 0x97, 0x29, 0x3d, 0xcc, - 0xc9, 0xba, 0x5b, 0x30, 0x34, 0x1f, 0x36, 0x3b, 0xad, 0xa0, 0xbf, 0x48, 0x99, 0x64, 0xa7, 0x4d, - 0xb2, 0x67, 0x24, 0x13, 0xff, 0x59, 0x89, 0x34, 0x1c, 0x0d, 0xe4, 0x1b, 0x8e, 0xdc, 0x7f, 0xe9, - 0x00, 0xdd, 0x55, 0x35, 0x5f, 0x78, 0x12, 0x39, 0x3a, 0x4e, 0xf0, 0x61, 0x1d, 0xdd, 0x9d, 0xdd, - 0xe9, 0x71, 0x55, 0x51, 0xc3, 0xff, 0x21, 0x18, 0x8a, 0x99, 0x4a, 0x2e, 0xfa, 0xb0, 0x28, 0xe5, - 0x67, 0xae, 0xa8, 0xdf, 0xd9, 0x9d, 0xee, 0x2b, 0x6c, 0x73, 0x46, 0xe1, 0x16, 0x4e, 0x4f, 0x81, - 0x95, 0x0a, 0x7c, 0x2d, 0x12, 0xc7, 0x5e, 0x5d, 0x6a, 0x78, 0x4a, 0xe0, 0x5b, 0xe1, 0x60, 0x2c, - 0xcb, 0xdd, 0x2f, 0x3b, 0x30, 0xae, 0x0e, 0x2f, 0x2a, 0xbe, 0xa3, 0xab, 0xfa, 0x31, 0xc7, 0x57, - 0xca, 0xc3, 0x3d, 0x38, 0x8e, 0x38, 0xc8, 0xf7, 0x3e, 0x05, 0xdf, 0x05, 0x63, 0x35, 0xd2, 0x26, - 0x41, 0x8d, 0x04, 0x55, 0xaa, 0x7e, 0xd3, 0x15, 0x32, 0x3a, 0x37, 0x49, 0xf5, 0xcd, 0x05, 0x0d, - 0x8e, 0x8d, 0x5a, 0xee, 0x37, 0x1d, 0x78, 0x50, 0xa1, 0xab, 0x90, 0x04, 0x93, 0x24, 0xda, 0x51, - 0x61, 0x9a, 0xfb, 0x3b, 0xad, 0x6e, 0x50, 0xf9, 0x37, 0x89, 0x38, 0xf1, 0x83, 0x1d, 0x57, 0x25, - 0x2e, 0x2d, 0x33, 0x24, 0x58, 0x62, 0x73, 0x7f, 0x6d, 0x00, 0x4e, 0xea, 0x9d, 0x54, 0x0c, 0xe6, - 0x13, 0x0e, 0x80, 0x9a, 0x01, 0x7a, 0x20, 0x0f, 0xd8, 0xf1, 0x5d, 0x19, 0x5f, 0x2a, 0x65, 0x41, - 0x0a, 0x1c, 0x63, 0x8d, 0x2c, 0x7a, 0x01, 0xc6, 0xb6, 0xe9, 0xa6, 0x20, 0x2b, 0x54, 0x5c, 0x88, - 0xcb, 0x03, 0xac, 0x1b, 0xd3, 0x79, 0x1f, 0xf3, 0x7a, 0x5a, 0x2f, 0x35, 0x07, 0x68, 0xc0, 0x18, - 0x1b, 0xa8, 0xa8, 0xa6, 0x33, 0x1e, 0xe9, 0x9f, 0x44, 0xd8, 0xc4, 0x3f, 0x68, 0x71, 0x8c, 0xd9, - 0xaf, 0x3e, 0x77, 0xfc, 0xf6, 0xee, 0xf4, 0xb8, 0x01, 0xc2, 0x66, 0x27, 0xdc, 0x17, 0x80, 0xcd, - 0x85, 0x1f, 0x74, 0xc8, 0x6a, 0x80, 0x1e, 0x95, 0x36, 0x3a, 0xee, 0x57, 0x51, 0x9c, 0x43, 0xb7, - 0xd3, 0x51, 0x5d, 0x76, 0xd3, 0xf3, 0x9b, 0x2c, 0x7c, 0x91, 0xd6, 0x52, 0xba, 0xec, 0x22, 0x83, - 0x62, 0x51, 0xea, 0xce, 0xc0, 0xf0, 0x3c, 0x1d, 0x3b, 0x89, 0x28, 0x5e, 0x3d, 0xea, 0x78, 0xdc, - 0x88, 0x3a, 0x96, 0xd1, 0xc5, 0xeb, 0x70, 0x6a, 0x3e, 0x22, 0x5e, 0x42, 0x2a, 0xcf, 0xcc, 0x75, - 0xaa, 0x5b, 0x24, 0xe1, 0xa1, 0x5d, 0x31, 0x7a, 0x2f, 0x8c, 0x87, 0xec, 0xc8, 0xb8, 0x12, 0x56, - 0xb7, 0xfc, 0xa0, 0x2e, 0x4c, 0xae, 0xa7, 0x04, 0x96, 0xf1, 0x55, 0xbd, 0x10, 0x9b, 0x75, 0xdd, - 0xff, 0x58, 0x80, 0xb1, 0xf9, 0x28, 0x0c, 0x24, 0x5b, 0x3c, 0x82, 0xa3, 0x2c, 0x31, 0x8e, 0x32, - 0x0b, 0xee, 0x4e, 0xbd, 0xff, 0xbd, 0x8e, 0x33, 0xf4, 0xba, 0x62, 0x91, 0x03, 0xb6, 0x54, 0x10, - 0x83, 0x2e, 0xc3, 0x9d, 0x7e, 0x6c, 0x93, 0x81, 0xba, 0xff, 0xc9, 0x81, 0x49, 0xbd, 0xfa, 0x11, - 0x9c, 0xa0, 0xb1, 0x79, 0x82, 0x5e, 0xb5, 0x3b, 0xde, 0x1e, 0xc7, 0xe6, 0xdb, 0xc3, 0xe6, 0x38, - 0x99, 0xaf, 0xfb, 0xab, 0x0e, 0x8c, 0xdd, 0xd4, 0x00, 0x62, 0xb0, 0xb6, 0x85, 0x98, 0x77, 0x48, - 0x36, 0xa3, 0x43, 0xef, 0x64, 0x7e, 0x63, 0xa3, 0x27, 0x94, 0xef, 0xc7, 0xd5, 0x06, 0xa9, 0x75, - 0x9a, 0xf2, 0xf8, 0x56, 0x53, 0x5a, 0x11, 0x70, 0xac, 0x6a, 0xa0, 0x97, 0xe0, 0x78, 0x35, 0x0c, - 0xaa, 0x9d, 0x28, 0x22, 0x41, 0x75, 0x67, 0x8d, 0xdd, 0x91, 0x10, 0x07, 0xe2, 0x8c, 0x68, 0x76, - 0x7c, 0x3e, 0x5b, 0xe1, 0x4e, 0x1e, 0x10, 0x77, 0x23, 0xe2, 0xce, 0x82, 0x98, 0x1e, 0x59, 0x42, - 0xe1, 0xd2, 0x9c, 0x05, 0x0c, 0x8c, 0x65, 0x39, 0xba, 0x06, 0x67, 0xe2, 0xc4, 0x8b, 0x12, 0x3f, - 0xa8, 0x2f, 0x10, 0xaf, 0xd6, 0xf4, 0x03, 0xaa, 0x4a, 0x84, 0x41, 0x8d, 0xbb, 0x12, 0x07, 0xe6, - 0xce, 0xde, 0xde, 0x9d, 0x3e, 0x53, 0xc9, 0xaf, 0x82, 0x7b, 0xb5, 0x45, 0x1f, 0x82, 0x29, 0xe1, - 0x8e, 0xd8, 0xec, 0x34, 0x9f, 0x0b, 0x37, 0xe2, 0x4b, 0x7e, 0x4c, 0xf5, 0xf8, 0x2b, 0x7e, 0xcb, - 0x4f, 0x98, 0xc3, 0xb0, 0x38, 0x77, 0xee, 0xf6, 0xee, 0xf4, 0x54, 0xa5, 0x67, 0x2d, 0xbc, 0x07, - 0x06, 0x84, 0xe1, 0x34, 0x67, 0x7e, 0x5d, 0xb8, 0x87, 0x19, 0xee, 0xa9, 0xdb, 0xbb, 0xd3, 0xa7, - 0x17, 0x73, 0x6b, 0xe0, 0x1e, 0x2d, 0xe9, 0x17, 0x4c, 0xfc, 0x16, 0x79, 0x35, 0x0c, 0x08, 0x0b, - 0x54, 0xd1, 0xbe, 0xe0, 0xba, 0x80, 0x63, 0x55, 0x03, 0xbd, 0x9c, 0xae, 0x44, 0xba, 0x5d, 0x44, - 0xc0, 0xc9, 0xfe, 0x39, 0x1c, 0x53, 0x4d, 0x6e, 0x68, 0x98, 0x58, 0x24, 0xa5, 0x81, 0x1b, 0x7d, - 0xd2, 0x81, 0xb1, 0x38, 0x09, 0xd5, 0xbd, 0x06, 0x11, 0x71, 0x62, 0x61, 0xd9, 0x57, 0x34, 0xac, - 0x5c, 0xf0, 0xd1, 0x21, 0xd8, 0xa0, 0x8a, 0x7e, 0x01, 0x46, 0xe5, 0x02, 0x8e, 0xcb, 0x25, 0x26, - 0x2b, 0x31, 0x35, 0x4e, 0xae, 0xef, 0x18, 0xa7, 0xe5, 0x54, 0x94, 0xbd, 0xd9, 0x20, 0x01, 0x8b, - 0xb9, 0xd5, 0x44, 0xd9, 0x1b, 0x0d, 0x12, 0x60, 0x56, 0xe2, 0xfe, 0x78, 0x00, 0x50, 0x37, 0xe3, - 0x43, 0xcb, 0x30, 0xe4, 0x55, 0x13, 0x7f, 0x5b, 0xc6, 0x1b, 0x3e, 0x9a, 0x27, 0x14, 0xf0, 0x09, - 0xc4, 0x64, 0x93, 0xd0, 0x75, 0x4f, 0x52, 0x6e, 0x39, 0xcb, 0x9a, 0x62, 0x81, 0x02, 0x85, 0x70, - 0xbc, 0xe9, 0xc5, 0x89, 0xec, 0x61, 0x8d, 0x7e, 0x48, 0x71, 0x5c, 0xfc, 0x7c, 0x7f, 0x9f, 0x8a, - 0xb6, 0x98, 0x3b, 0x45, 0xf7, 0xe3, 0x95, 0x2c, 0x22, 0xdc, 0x8d, 0x1b, 0x7d, 0x8c, 0x49, 0x57, - 0x5c, 0xf4, 0x95, 0x62, 0xcd, 0xb2, 0x15, 0xc9, 0x83, 0xe3, 0x34, 0x24, 0x2b, 0x41, 0x06, 0x6b, - 0x24, 0xd1, 0x79, 0x18, 0x65, 0xfb, 0x86, 0xd4, 0x08, 0xdf, 0xfd, 0x03, 0xa9, 0x10, 0x5c, 0x91, - 0x05, 0x38, 0xad, 0xa3, 0x49, 0x19, 0x7c, 0xc3, 0xf7, 0x90, 0x32, 0xd0, 0xb3, 0x50, 0x6c, 0x37, - 0xbc, 0x58, 0xc6, 0xb0, 0xbb, 0x92, 0x6b, 0xaf, 0x51, 0x20, 0x63, 0x4d, 0xda, 0xb7, 0x64, 0x40, - 0xcc, 0x1b, 0xb8, 0xff, 0x0a, 0x60, 0x78, 0x61, 0x76, 0x69, 0xdd, 0x8b, 0xb7, 0xfa, 0xd0, 0x81, - 0xe8, 0x36, 0x14, 0xc2, 0x6a, 0x96, 0x91, 0x4a, 0x21, 0x16, 0xab, 0x1a, 0x28, 0x80, 0x21, 0x3f, - 0xa0, 0x9c, 0xa7, 0x3c, 0x61, 0xcb, 0xcf, 0xa0, 0xf4, 0x39, 0x66, 0x08, 0xba, 0xcc, 0xb0, 0x63, - 0x41, 0x05, 0xbd, 0x0e, 0xa3, 0x9e, 0xbc, 0x42, 0x24, 0xce, 0xff, 0x65, 0x1b, 0x06, 0x74, 0x81, - 0x52, 0x0f, 0x61, 0x12, 0x20, 0x9c, 0x12, 0x44, 0x1f, 0x77, 0xa0, 0x24, 0x87, 0x8e, 0xc9, 0xa6, - 0xf0, 0x6d, 0xaf, 0xd8, 0x1b, 0x33, 0x26, 0x9b, 0x3c, 0xbe, 0x45, 0x03, 0x60, 0x9d, 0x64, 0x97, - 0xce, 0x54, 0xec, 0x47, 0x67, 0x42, 0x37, 0x61, 0xf4, 0xa6, 0x9f, 0x34, 0xd8, 0x09, 0x2f, 0x7c, - 0x6a, 0x8b, 0xf7, 0xde, 0x6b, 0x8a, 0x2e, 0x9d, 0xb1, 0x1b, 0x92, 0x00, 0x4e, 0x69, 0xd1, 0xed, - 0x40, 0x7f, 0xb0, 0x2b, 0x58, 0xec, 0x6c, 0x18, 0x35, 0x1b, 0xb0, 0x02, 0x9c, 0xd6, 0xa1, 0x53, - 0x3c, 0x46, 0x7f, 0x55, 0xc8, 0x2b, 0x1d, 0xca, 0x5a, 0x44, 0xcc, 0xa2, 0x85, 0x75, 0x25, 0x31, - 0xf2, 0xc9, 0xba, 0xa1, 0xd1, 0xc0, 0x06, 0x45, 0xc5, 0x3a, 0x47, 0x7b, 0xb1, 0x4e, 0xf4, 0x3a, - 0xd7, 0xe1, 0xb8, 0x32, 0x21, 0x4e, 0x83, 0x2b, 0x76, 0xf4, 0x1b, 0x8e, 0x93, 0x5f, 0x6b, 0x48, - 0x7f, 0x63, 0x8d, 0x1e, 0xe5, 0x18, 0x61, 0x70, 0xf1, 0x96, 0x9f, 0x88, 0xcb, 0x18, 0x8a, 0x63, - 0xac, 0x32, 0x28, 0x16, 0xa5, 0x3c, 0x76, 0x83, 0x2e, 0x82, 0x58, 0x9c, 0x02, 0x5a, 0xec, 0x06, - 0x03, 0x63, 0x59, 0x8e, 0xfe, 0xbe, 0x03, 0xc5, 0x46, 0x18, 0x6e, 0xc5, 0xe5, 0x71, 0xb6, 0x38, - 0x2c, 0xc8, 0xd4, 0x82, 0xe3, 0xcc, 0x5c, 0xa2, 0x68, 0xcd, 0xeb, 0x65, 0x45, 0x06, 0xbb, 0xb3, - 0x3b, 0x3d, 0x71, 0xc5, 0xdf, 0x24, 0xd5, 0x9d, 0x6a, 0x93, 0x30, 0xc8, 0x9b, 0x6f, 0x6b, 0x90, - 0x8b, 0xdb, 0x24, 0x48, 0x30, 0xef, 0xd5, 0xd4, 0xe7, 0x1c, 0x80, 0x14, 0x51, 0x8e, 0x93, 0x94, - 0x98, 0x61, 0x05, 0x16, 0x14, 0x6a, 0xa3, 0x6b, 0xba, 0xd7, 0xf5, 0xdf, 0x38, 0x50, 0xa2, 0x83, - 0x93, 0x2c, 0xf0, 0x71, 0x18, 0x4a, 0xbc, 0xa8, 0x4e, 0xa4, 0xa3, 0x40, 0x7d, 0x8e, 0x75, 0x06, - 0xc5, 0xa2, 0x14, 0x05, 0x50, 0x4c, 0xbc, 0x78, 0x4b, 0x8a, 0xf1, 0x97, 0xad, 0x4d, 0x71, 0x2a, - 0xc1, 0xd3, 0x5f, 0x31, 0xe6, 0x64, 0xd0, 0x13, 0x30, 0x42, 0x8f, 0x8e, 0x45, 0x2f, 0x96, 0xb1, - 0x3b, 0x63, 0x94, 0x89, 0x2f, 0x0a, 0x18, 0x56, 0xa5, 0xee, 0x6f, 0x14, 0x60, 0x70, 0x81, 0x2b, - 0x74, 0x43, 0x71, 0xd8, 0x89, 0xaa, 0x44, 0x08, 0xf6, 0x16, 0xd6, 0x34, 0xc5, 0x5b, 0x61, 0x38, - 0x35, 0x95, 0x8a, 0xfd, 0xc6, 0x82, 0x16, 0xfa, 0x92, 0x03, 0x13, 0x49, 0xe4, 0x05, 0xf1, 0x26, - 0x73, 0xc9, 0xf8, 0x61, 0x20, 0xa6, 0xc8, 0xc2, 0x2a, 0x5c, 0x37, 0xf0, 0x56, 0x12, 0xd2, 0x4e, - 0x3d, 0x43, 0x66, 0x19, 0xce, 0xf4, 0xc1, 0xfd, 0x4d, 0x07, 0x20, 0xed, 0x3d, 0xfa, 0xac, 0x03, - 0xe3, 0x9e, 0x1e, 0x33, 0x2a, 0xe6, 0x68, 0xd5, 0x9e, 0xff, 0x96, 0xa1, 0xe5, 0xb6, 0x0c, 0x03, - 0x84, 0x4d, 0xc2, 0xee, 0xbb, 0xa1, 0xc8, 0x76, 0x07, 0x53, 0x7a, 0x84, 0xed, 0x3b, 0x6b, 0xec, - 0x92, 0x36, 0x71, 0xac, 0x6a, 0xb8, 0x2f, 0xc1, 0xc4, 0xc5, 0x5b, 0xa4, 0xda, 0x49, 0xc2, 0x88, - 0x5b, 0xfe, 0x7b, 0xdc, 0x11, 0x72, 0x0e, 0x74, 0x47, 0xe8, 0x3b, 0x0e, 0x94, 0xb4, 0x00, 0x42, - 0x7a, 0x52, 0xd7, 0xe7, 0x2b, 0xdc, 0xc0, 0x21, 0xa6, 0x6a, 0xd9, 0x4a, 0x88, 0x22, 0x47, 0x99, - 0x1e, 0x23, 0x0a, 0x84, 0x53, 0x82, 0x77, 0x09, 0xf0, 0x73, 0xff, 0xc0, 0x81, 0x53, 0xb9, 0xd1, - 0x8e, 0xf7, 0xb9, 0xdb, 0x86, 0x93, 0xbd, 0xd0, 0x87, 0x93, 0xfd, 0x77, 0x1c, 0x48, 0x31, 0x51, - 0x56, 0xb4, 0x91, 0xf6, 0x5c, 0x63, 0x45, 0x82, 0x92, 0x28, 0x45, 0xaf, 0xc3, 0x19, 0xf3, 0x0b, - 0x1e, 0xd0, 0xdf, 0xc2, 0x95, 0xd3, 0x7c, 0x4c, 0xb8, 0x17, 0x09, 0xf7, 0x6b, 0x0e, 0x14, 0x97, - 0xbc, 0x4e, 0x9d, 0xf4, 0x65, 0x2e, 0xa3, 0x7c, 0x2c, 0x22, 0x5e, 0x33, 0x91, 0xaa, 0x83, 0xe0, - 0x63, 0x58, 0xc0, 0xb0, 0x2a, 0x45, 0xb3, 0x30, 0x1a, 0xb6, 0x89, 0xe1, 0x23, 0x7c, 0x54, 0xce, - 0xde, 0xaa, 0x2c, 0xa0, 0xc7, 0x0e, 0xa3, 0xae, 0x20, 0x38, 0x6d, 0xe5, 0xfe, 0xa0, 0x08, 0x25, - 0xed, 0x5e, 0x0c, 0x95, 0x05, 0x22, 0xd2, 0x0e, 0xb3, 0xf2, 0x32, 0x5d, 0x30, 0x98, 0x95, 0xd0, - 0x3d, 0x18, 0x91, 0x6d, 0x3f, 0xe6, 0x6c, 0xcb, 0xd8, 0x83, 0x58, 0xc0, 0xb1, 0xaa, 0x81, 0xa6, - 0xa1, 0x58, 0x23, 0xed, 0xa4, 0xc1, 0xba, 0x37, 0xc8, 0x83, 0x03, 0x17, 0x28, 0x00, 0x73, 0x38, - 0xad, 0xb0, 0x49, 0x92, 0x6a, 0x83, 0x59, 0x86, 0x45, 0xf4, 0xe0, 0x22, 0x05, 0x60, 0x0e, 0xcf, - 0xf1, 0x62, 0x16, 0x0f, 0xdf, 0x8b, 0x39, 0x64, 0xd9, 0x8b, 0x89, 0xda, 0x70, 0x22, 0x8e, 0x1b, - 0x6b, 0x91, 0xbf, 0xed, 0x25, 0x24, 0x5d, 0x7d, 0xc3, 0xfb, 0xa1, 0x73, 0x86, 0xdd, 0x54, 0xaf, - 0x5c, 0xca, 0x62, 0xc1, 0x79, 0xa8, 0x51, 0x05, 0x4e, 0xf9, 0x41, 0x4c, 0xaa, 0x9d, 0x88, 0x5c, - 0xae, 0x07, 0x61, 0x44, 0x2e, 0x85, 0x31, 0x45, 0x27, 0xee, 0xd9, 0xaa, 0x78, 0xda, 0xcb, 0x79, - 0x95, 0x70, 0x7e, 0x5b, 0xb4, 0x04, 0xc7, 0x6b, 0x7e, 0xec, 0x6d, 0x34, 0x49, 0xa5, 0xb3, 0xd1, - 0x0a, 0xb9, 0x6a, 0x3e, 0xca, 0x10, 0x3e, 0x28, 0xed, 0x48, 0x0b, 0xd9, 0x0a, 0xb8, 0xbb, 0x0d, - 0x7a, 0x16, 0xc6, 0x62, 0x3f, 0xa8, 0x37, 0xc9, 0x5c, 0xe4, 0x05, 0xd5, 0x86, 0xb8, 0xa0, 0xab, - 0xec, 0xed, 0x15, 0xad, 0x0c, 0x1b, 0x35, 0xd9, 0x9e, 0xe7, 0x6d, 0x32, 0xd2, 0xa0, 0xa8, 0x2d, - 0x4a, 0xdd, 0x1f, 0x3a, 0x30, 0xa6, 0xc7, 0xb2, 0x53, 0x49, 0x1b, 0x1a, 0x0b, 0x8b, 0x15, 0x7e, - 0x16, 0xd8, 0x3b, 0xf1, 0x2f, 0x29, 0x9c, 0xa9, 0xb2, 0x9c, 0xc2, 0xb0, 0x46, 0xb3, 0x8f, 0x9b, - 0xe9, 0x8f, 0x42, 0x71, 0x33, 0xa4, 0x02, 0xc9, 0x80, 0x69, 0xa8, 0x5f, 0xa4, 0x40, 0xcc, 0xcb, - 0xdc, 0xff, 0xee, 0xc0, 0xe9, 0xfc, 0x30, 0xfd, 0x9f, 0x85, 0x41, 0x5e, 0x00, 0xa0, 0x43, 0x31, - 0x98, 0xba, 0x96, 0x9b, 0x42, 0x96, 0x60, 0xad, 0x56, 0x7f, 0xc3, 0xfe, 0xd7, 0x05, 0xd0, 0x68, - 0xa2, 0xcf, 0x3b, 0x30, 0x4e, 0xc9, 0x2e, 0x47, 0x1b, 0xc6, 0x68, 0x57, 0xed, 0x8c, 0x56, 0xa1, - 0x4d, 0xfd, 0x11, 0x06, 0x18, 0x9b, 0xc4, 0xd1, 0x2f, 0xc0, 0xa8, 0x57, 0xab, 0x45, 0x24, 0x8e, - 0x95, 0x67, 0x8f, 0x59, 0xab, 0x66, 0x25, 0x10, 0xa7, 0xe5, 0x94, 0x89, 0x36, 0x6a, 0x9b, 0x31, - 0xe5, 0x4b, 0x82, 0x71, 0x2b, 0x26, 0x4a, 0x89, 0x50, 0x38, 0x56, 0x35, 0xd0, 0x75, 0x38, 0x5d, - 0xf3, 0x12, 0x8f, 0xcb, 0x6f, 0x24, 0x5a, 0x8b, 0xc2, 0x84, 0x54, 0x19, 0xd3, 0xe7, 0x11, 0xa8, - 0xe7, 0x44, 0xdb, 0xd3, 0x0b, 0xb9, 0xb5, 0x70, 0x8f, 0xd6, 0xee, 0xaf, 0x0e, 0x82, 0x39, 0x26, - 0x54, 0x83, 0x63, 0x5b, 0xd1, 0xc6, 0x3c, 0x0b, 0xb8, 0x38, 0x48, 0xe0, 0x03, 0x0b, 0x48, 0x58, - 0x36, 0x31, 0xe0, 0x2c, 0x4a, 0x41, 0x65, 0x99, 0xec, 0x24, 0xde, 0xc6, 0x81, 0xc3, 0x1e, 0x96, - 0x4d, 0x0c, 0x38, 0x8b, 0x12, 0xbd, 0x1b, 0x4a, 0x5b, 0xd1, 0x86, 0x64, 0xfd, 0xd9, 0x18, 0x9a, - 0xe5, 0xb4, 0x08, 0xeb, 0xf5, 0xe8, 0xa7, 0xd9, 0x8a, 0x36, 0xe8, 0x69, 0x2b, 0x33, 0x40, 0xa8, - 0x4f, 0xb3, 0x2c, 0xe0, 0x58, 0xd5, 0x40, 0x6d, 0x40, 0x5b, 0x72, 0xf6, 0x54, 0x78, 0x89, 0x38, - 0xa1, 0xfa, 0x8f, 0x4e, 0x61, 0x71, 0xfd, 0xcb, 0x5d, 0x78, 0x70, 0x0e, 0x6e, 0xf4, 0x02, 0x9c, - 0xd9, 0x8a, 0x36, 0x84, 0x10, 0xb2, 0x16, 0xf9, 0x41, 0xd5, 0x6f, 0x1b, 0xd9, 0x1e, 0xa6, 0x45, - 0x77, 0xcf, 0x2c, 0xe7, 0x57, 0xc3, 0xbd, 0xda, 0xbb, 0xbf, 0x3b, 0x08, 0xec, 0x9e, 0x2a, 0xe5, - 0xb1, 0x2d, 0x92, 0x34, 0xc2, 0x5a, 0x56, 0xae, 0x5a, 0x61, 0x50, 0x2c, 0x4a, 0x65, 0xf4, 0x6a, - 0xa1, 0x47, 0xf4, 0xea, 0x4d, 0x18, 0x6e, 0x10, 0xaf, 0x46, 0x22, 0x69, 0x99, 0xbc, 0x62, 0xe7, - 0x66, 0xed, 0x25, 0x86, 0x34, 0x55, 0xef, 0xf9, 0xef, 0x18, 0x4b, 0x6a, 0xe8, 0x3d, 0x30, 0x41, - 0x05, 0xa4, 0xb0, 0x93, 0x48, 0xe7, 0x02, 0xb7, 0x4c, 0xb2, 0x93, 0x7a, 0xdd, 0x28, 0xc1, 0x99, - 0x9a, 0x68, 0x01, 0x26, 0x85, 0x23, 0x40, 0x59, 0x3c, 0xc5, 0xc4, 0xaa, 0x34, 0x1c, 0x95, 0x4c, - 0x39, 0xee, 0x6a, 0xc1, 0xa2, 0x0f, 0xc3, 0x1a, 0xf7, 0x05, 0xeb, 0xd1, 0x87, 0x61, 0x6d, 0x07, - 0xb3, 0x12, 0xf4, 0x2a, 0x8c, 0xd0, 0xbf, 0x8b, 0x51, 0xd8, 0x12, 0x36, 0x9f, 0x35, 0x3b, 0xb3, - 0x43, 0x69, 0x08, 0x0d, 0x94, 0x09, 0x8e, 0x73, 0x82, 0x0a, 0x56, 0xf4, 0xa8, 0x1e, 0x24, 0xcf, - 0xf7, 0xca, 0x96, 0xdf, 0xbe, 0x4e, 0x22, 0x7f, 0x73, 0x87, 0x09, 0x23, 0x23, 0xa9, 0x1e, 0x74, - 0xb9, 0xab, 0x06, 0xce, 0x69, 0xe5, 0x7e, 0xbe, 0x00, 0x63, 0xfa, 0x75, 0xe7, 0xbb, 0x85, 0x34, - 0xc7, 0xe9, 0xa2, 0xe0, 0x5a, 0xef, 0x25, 0x0b, 0xc3, 0xbe, 0xdb, 0x82, 0x68, 0xc0, 0xa0, 0xd7, - 0x11, 0x52, 0xa8, 0x15, 0xe3, 0x1a, 0x1b, 0x71, 0x27, 0x69, 0xf0, 0x7b, 0x71, 0x2c, 0xd8, 0x98, - 0x51, 0x70, 0x3f, 0x35, 0x00, 0x23, 0xb2, 0x10, 0x7d, 0xd2, 0x01, 0x48, 0x83, 0xbe, 0x04, 0x2b, - 0x5d, 0xb3, 0x11, 0x11, 0xa4, 0xc7, 0xab, 0x69, 0x36, 0x7a, 0x05, 0xc7, 0x1a, 0x5d, 0x94, 0xc0, - 0x50, 0x48, 0x3b, 0x77, 0xc1, 0xde, 0x95, 0xfd, 0x55, 0x4a, 0xf8, 0x02, 0xa3, 0x9e, 0x9a, 0xe3, - 0x18, 0x0c, 0x0b, 0x5a, 0x54, 0xb3, 0xdc, 0x90, 0xb1, 0x88, 0xf6, 0x4c, 0xd7, 0x2a, 0xbc, 0x31, - 0x55, 0x14, 0x15, 0x08, 0xa7, 0x04, 0xdd, 0xa7, 0x61, 0xc2, 0xdc, 0x0c, 0x54, 0xd3, 0xd8, 0xd8, - 0x49, 0x08, 0xb7, 0x63, 0x8c, 0x71, 0x4d, 0x63, 0x8e, 0x02, 0x30, 0x87, 0xbb, 0xdf, 0x77, 0x00, - 0x52, 0xf6, 0xd2, 0x87, 0xeb, 0xe0, 0x51, 0xdd, 0x08, 0xd7, 0x4b, 0x9d, 0xfb, 0x18, 0x8c, 0xb2, - 0x7f, 0xd8, 0x46, 0x1f, 0xb0, 0x15, 0x39, 0x90, 0xf6, 0x53, 0x6c, 0x75, 0x26, 0x6b, 0x5c, 0x97, - 0x84, 0x70, 0x4a, 0xd3, 0x0d, 0x61, 0x32, 0x5b, 0x1b, 0x7d, 0x10, 0xc6, 0x62, 0x79, 0xac, 0xa6, - 0x97, 0xf7, 0xfa, 0x3c, 0x7e, 0xb9, 0xdf, 0x4e, 0x6b, 0x8e, 0x0d, 0x64, 0xee, 0x2a, 0x0c, 0x59, - 0x9d, 0x42, 0xf7, 0xdb, 0x0e, 0x8c, 0x32, 0xd7, 0x69, 0x3d, 0xf2, 0x5a, 0x69, 0x93, 0x81, 0x3d, - 0x66, 0x3d, 0x86, 0x61, 0xae, 0xfb, 0xcb, 0x90, 0x23, 0x0b, 0x5c, 0x86, 0x67, 0xda, 0x4b, 0xb9, - 0x0c, 0x37, 0x32, 0xc4, 0x58, 0x52, 0x72, 0x3f, 0x5d, 0x80, 0xa1, 0xcb, 0x41, 0xbb, 0xf3, 0x57, - 0x3e, 0xdb, 0xdb, 0x0a, 0x0c, 0x5e, 0x4e, 0x48, 0xcb, 0x4c, 0x4a, 0x38, 0x36, 0xf7, 0x98, 0x9e, - 0x90, 0xb0, 0x6c, 0x26, 0x24, 0xc4, 0xde, 0x4d, 0x19, 0x91, 0x27, 0x6c, 0xcf, 0xe9, 0x05, 0xc6, - 0xa7, 0x60, 0xf4, 0x8a, 0xb7, 0x41, 0x9a, 0xcb, 0x64, 0x87, 0x5d, 0x37, 0xe4, 0xd1, 0x21, 0x4e, - 0x6a, 0x30, 0x30, 0x22, 0x39, 0x16, 0x60, 0x82, 0xd5, 0x56, 0x9b, 0x81, 0x6a, 0x24, 0x24, 0xcd, - 0xe8, 0xe4, 0x98, 0x1a, 0x89, 0x96, 0xcd, 0x49, 0xab, 0xe5, 0xce, 0x40, 0x29, 0xc5, 0xd2, 0x07, - 0xd5, 0x9f, 0x16, 0x60, 0xdc, 0x30, 0xa1, 0x1b, 0x8e, 0x45, 0xe7, 0xae, 0x8e, 0x45, 0xc3, 0xd1, - 0x57, 0xb8, 0xdf, 0x8e, 0xbe, 0x81, 0xa3, 0x77, 0xf4, 0x99, 0x1f, 0x69, 0xb0, 0xaf, 0x8f, 0xd4, - 0x84, 0xc1, 0x2b, 0x7e, 0xb0, 0xd5, 0x1f, 0x9f, 0x89, 0xab, 0x61, 0xbb, 0x8b, 0xcf, 0x54, 0x28, - 0x10, 0xf3, 0x32, 0x29, 0xb9, 0x0c, 0xe4, 0x4b, 0x2e, 0xee, 0x27, 0x1d, 0x18, 0x5b, 0xf1, 0x02, - 0x7f, 0x93, 0xc4, 0x09, 0x5b, 0x57, 0xc9, 0xa1, 0x5e, 0x3b, 0x1b, 0xeb, 0x91, 0x40, 0xe1, 0x4d, - 0x07, 0x8e, 0xaf, 0x90, 0x56, 0xe8, 0xbf, 0xea, 0xa5, 0x01, 0xaf, 0xb4, 0xef, 0x0d, 0x3f, 0x11, - 0xf1, 0x7d, 0xaa, 0xef, 0x97, 0xfc, 0x04, 0x53, 0xf8, 0x5d, 0xec, 0xc3, 0xec, 0x42, 0x07, 0x55, - 0xd0, 0xb4, 0xab, 0x90, 0x69, 0x28, 0xab, 0x2c, 0xc0, 0x69, 0x1d, 0xf7, 0xf7, 0x1c, 0x18, 0xe6, - 0x9d, 0x50, 0x31, 0xc2, 0x4e, 0x0f, 0xdc, 0x0d, 0x28, 0xb2, 0x76, 0x62, 0x55, 0x2f, 0x59, 0x10, - 0x7f, 0x28, 0x3a, 0xbe, 0x07, 0xd9, 0xbf, 0x98, 0x13, 0x60, 0x6a, 0x8b, 0x77, 0x6b, 0x56, 0xc5, - 0xfa, 0xa6, 0x6a, 0x0b, 0x83, 0x62, 0x51, 0xea, 0x7e, 0x7d, 0x00, 0x46, 0x54, 0xde, 0x30, 0x96, - 0xd5, 0x21, 0x08, 0xc2, 0xc4, 0xe3, 0x31, 0x14, 0x9c, 0x57, 0x7f, 0xd0, 0x5e, 0xde, 0xb2, 0x99, - 0xd9, 0x14, 0x3b, 0xf7, 0x0b, 0x2a, 0x25, 0x54, 0x2b, 0xc1, 0x7a, 0x27, 0xd0, 0x47, 0x61, 0xa8, - 0x49, 0xb9, 0x8f, 0x64, 0xdd, 0xd7, 0x2d, 0x76, 0x87, 0xb1, 0x35, 0xd1, 0x13, 0x35, 0x43, 0x1c, - 0x88, 0x05, 0xd5, 0xa9, 0xf7, 0xc1, 0x64, 0xb6, 0xd7, 0x77, 0xbb, 0xa9, 0x39, 0xaa, 0xdf, 0xf3, - 0xfc, 0xeb, 0x82, 0x7b, 0xee, 0xbf, 0xa9, 0xfb, 0x3c, 0x94, 0x56, 0x48, 0x12, 0xf9, 0x55, 0x86, - 0xe0, 0x6e, 0x8b, 0xab, 0x2f, 0xf9, 0xe1, 0x33, 0x6c, 0xb1, 0x52, 0x9c, 0x31, 0x7a, 0x1d, 0xa0, - 0x1d, 0x85, 0x54, 0x7f, 0x25, 0x1d, 0xf9, 0xb1, 0x2d, 0xc8, 0xc3, 0x6b, 0x0a, 0x27, 0x77, 0x65, - 0xa7, 0xbf, 0xb1, 0x46, 0xcf, 0x7d, 0x11, 0x8a, 0x2b, 0x9d, 0x84, 0xdc, 0xea, 0x83, 0x63, 0xed, - 0x37, 0x75, 0x81, 0xfb, 0x41, 0x18, 0x63, 0xb8, 0x2f, 0x85, 0x4d, 0x7a, 0xac, 0xd2, 0xa9, 0x69, - 0xd1, 0xdf, 0x59, 0x67, 0x03, 0xab, 0x84, 0x79, 0x19, 0xdd, 0x32, 0x8d, 0xb0, 0x59, 0x53, 0xd7, - 0xb8, 0xd4, 0x82, 0xb8, 0xc4, 0xa0, 0x58, 0x94, 0xba, 0x9f, 0x28, 0x40, 0x89, 0x35, 0x14, 0xec, - 0x66, 0x07, 0x86, 0x1b, 0x9c, 0x8e, 0x98, 0x43, 0x0b, 0xc1, 0x61, 0x7a, 0xef, 0x35, 0x5d, 0x8e, - 0x03, 0xb0, 0xa4, 0x47, 0x49, 0xdf, 0xf4, 0xfc, 0x84, 0x92, 0x2e, 0x1c, 0x2e, 0xe9, 0x1b, 0x9c, - 0x0c, 0x96, 0xf4, 0xdc, 0x5f, 0x06, 0x76, 0x3d, 0x7a, 0xb1, 0xe9, 0xd5, 0xf9, 0xcc, 0x85, 0x5b, - 0xa4, 0x26, 0x78, 0xae, 0x36, 0x73, 0x14, 0x8a, 0x45, 0x29, 0xbf, 0x72, 0x9a, 0x44, 0xbe, 0x0a, - 0xab, 0xd6, 0xae, 0x9c, 0x32, 0xb0, 0x0c, 0xa2, 0xaf, 0xb9, 0x5f, 0x2e, 0x00, 0xb0, 0x2c, 0x73, - 0xfc, 0x56, 0xf3, 0x2f, 0xca, 0x08, 0x28, 0xd3, 0x41, 0xa9, 0x22, 0xa0, 0xd8, 0xbd, 0x6d, 0x3d, - 0xf2, 0x49, 0xbf, 0xed, 0x50, 0xd8, 0xfb, 0xb6, 0x03, 0x6a, 0xc3, 0x70, 0xd8, 0x49, 0xa8, 0xac, - 0x2a, 0x0e, 0x7b, 0x0b, 0xfe, 0xf9, 0x55, 0x8e, 0x90, 0x5f, 0x11, 0x10, 0x3f, 0xb0, 0x24, 0x83, - 0x9e, 0x85, 0x91, 0x76, 0x14, 0xd6, 0xe9, 0xd9, 0x2d, 0x8e, 0xf7, 0x87, 0xa4, 0x3c, 0xb4, 0x26, - 0xe0, 0x77, 0xb4, 0xff, 0xb1, 0xaa, 0xed, 0xfe, 0xf1, 0x24, 0x9f, 0x17, 0xb1, 0xf6, 0xa6, 0xa0, - 0xe0, 0x4b, 0xcb, 0x14, 0x08, 0x14, 0x85, 0xcb, 0x0b, 0xb8, 0xe0, 0xd7, 0xd4, 0xbe, 0x2a, 0xf4, - 0xdc, 0x57, 0xef, 0x86, 0x52, 0xcd, 0x8f, 0xdb, 0x4d, 0x6f, 0xe7, 0x6a, 0x8e, 0x59, 0x70, 0x21, - 0x2d, 0xc2, 0x7a, 0x3d, 0xf4, 0x94, 0xb8, 0xdb, 0x32, 0x68, 0x98, 0x82, 0xe4, 0xdd, 0x96, 0xf4, - 0xd6, 0x3c, 0xbf, 0xd6, 0x92, 0xcd, 0x2e, 0x50, 0xec, 0x3b, 0xbb, 0x40, 0x56, 0x12, 0x1b, 0x3a, - 0x7a, 0x49, 0xec, 0xbd, 0x30, 0x2e, 0x7f, 0x32, 0xf1, 0xa8, 0x7c, 0x92, 0xf5, 0x5e, 0x99, 0xc1, - 0xd7, 0xf5, 0x42, 0x6c, 0xd6, 0x4d, 0x17, 0xed, 0x70, 0xbf, 0x8b, 0xf6, 0x02, 0xc0, 0x46, 0xd8, - 0x09, 0x6a, 0x5e, 0xb4, 0x73, 0x79, 0x41, 0x44, 0xc2, 0x2a, 0xc1, 0x6f, 0x4e, 0x95, 0x60, 0xad, - 0x96, 0xbe, 0xd0, 0x47, 0xef, 0xb2, 0xd0, 0x3f, 0x08, 0xa3, 0x2c, 0x6a, 0x98, 0xd4, 0x66, 0x13, - 0x11, 0xba, 0xb4, 0x9f, 0x50, 0xcc, 0x34, 0x98, 0x51, 0x22, 0xc1, 0x29, 0x3e, 0xf4, 0x21, 0x80, - 0x4d, 0x3f, 0xf0, 0xe3, 0x06, 0xc3, 0x5e, 0xda, 0x37, 0x76, 0x35, 0xce, 0x45, 0x85, 0x05, 0x6b, - 0x18, 0xd1, 0x4b, 0x70, 0x9c, 0xc4, 0x89, 0xdf, 0xf2, 0x12, 0x52, 0x53, 0xb7, 0x41, 0xcb, 0xcc, - 0x96, 0xa9, 0xe2, 0xb6, 0x2f, 0x66, 0x2b, 0xdc, 0xc9, 0x03, 0xe2, 0x6e, 0x44, 0xc6, 0x8e, 0x9c, - 0xda, 0xcf, 0x8e, 0x44, 0x7f, 0xee, 0xc0, 0xf1, 0x88, 0xf0, 0x78, 0x96, 0x58, 0x75, 0xec, 0x14, - 0x63, 0xc7, 0x55, 0x1b, 0x09, 0xdc, 0x55, 0xa6, 0x16, 0x9c, 0xa5, 0xc2, 0x05, 0x17, 0x22, 0x47, - 0xdf, 0x55, 0x7e, 0x27, 0x0f, 0xf8, 0xe6, 0xdb, 0xd3, 0xd3, 0xdd, 0x0f, 0x09, 0x28, 0xe4, 0x74, - 0xe7, 0xfd, 0xed, 0xb7, 0xa7, 0x27, 0xe5, 0xef, 0x74, 0xd2, 0xba, 0x06, 0x49, 0x8f, 0xd5, 0x76, - 0x58, 0xbb, 0xbc, 0x26, 0x62, 0xcc, 0xd4, 0xb1, 0xba, 0x46, 0x81, 0x98, 0x97, 0xa1, 0x27, 0x60, - 0xa4, 0xe6, 0x91, 0x56, 0x18, 0xa8, 0x54, 0xbc, 0x4c, 0x9a, 0x5f, 0x10, 0x30, 0xac, 0x4a, 0xa9, - 0x0e, 0x11, 0x88, 0x23, 0xa5, 0x7c, 0xd6, 0x96, 0x0e, 0x21, 0x0f, 0x29, 0x4e, 0x55, 0xfe, 0xc2, - 0x8a, 0x12, 0x6a, 0xc2, 0x90, 0xcf, 0x0c, 0x15, 0x22, 0x8c, 0xd5, 0x82, 0x75, 0x84, 0x1b, 0x3e, - 0x64, 0x10, 0x2b, 0x63, 0xfd, 0x82, 0x86, 0x7e, 0xd6, 0x1c, 0x3b, 0x9a, 0xb3, 0xe6, 0x09, 0x18, - 0xa9, 0x36, 0xfc, 0x66, 0x2d, 0x22, 0x41, 0x79, 0x92, 0x69, 0xec, 0x6c, 0x26, 0xe6, 0x05, 0x0c, - 0xab, 0x52, 0xf4, 0xd7, 0x60, 0x3c, 0xec, 0x24, 0x8c, 0xb5, 0xd0, 0x79, 0x8a, 0xcb, 0xc7, 0x59, - 0x75, 0x16, 0x94, 0xb4, 0xaa, 0x17, 0x60, 0xb3, 0x1e, 0x65, 0xf1, 0x8d, 0x30, 0x66, 0x49, 0x85, - 0x18, 0x8b, 0x3f, 0x6d, 0xb2, 0xf8, 0x4b, 0x5a, 0x19, 0x36, 0x6a, 0xa2, 0xaf, 0x3a, 0x70, 0xbc, - 0x95, 0x55, 0xe0, 0xca, 0x67, 0xd8, 0xcc, 0x54, 0x6c, 0x08, 0xfa, 0x19, 0xd4, 0x3c, 0x9c, 0xbc, - 0x0b, 0x8c, 0xbb, 0x3b, 0xc1, 0xd2, 0x7b, 0xc5, 0x3b, 0x41, 0xb5, 0x11, 0x85, 0x81, 0xd9, 0xbd, - 0x07, 0x6d, 0x5d, 0x6a, 0x63, 0x7b, 0x3b, 0x8f, 0xc4, 0xdc, 0x83, 0xb7, 0x77, 0xa7, 0x4f, 0xe5, - 0x16, 0xe1, 0xfc, 0x4e, 0x4d, 0x2d, 0xc0, 0xe9, 0x7c, 0xfe, 0x70, 0x37, 0x8d, 0x63, 0x40, 0xd7, - 0x38, 0x16, 0xe1, 0xc1, 0x9e, 0x9d, 0xa2, 0x27, 0x8d, 0x94, 0x36, 0x1d, 0xf3, 0xa4, 0xe9, 0x92, - 0x0e, 0x27, 0x60, 0x4c, 0x7f, 0x79, 0xc2, 0xfd, 0x3f, 0x03, 0x00, 0xa9, 0x9d, 0x1c, 0x79, 0x30, - 0xc1, 0x6d, 0xf2, 0x97, 0x17, 0x0e, 0x7c, 0x1d, 0x7f, 0xde, 0x40, 0x80, 0x33, 0x08, 0x51, 0x0b, - 0x10, 0x87, 0xf0, 0xdf, 0x07, 0xf1, 0xad, 0x32, 0x57, 0xe4, 0x7c, 0x17, 0x12, 0x9c, 0x83, 0x98, - 0x8e, 0x28, 0x09, 0xb7, 0x48, 0x70, 0x0d, 0x5f, 0x39, 0x48, 0x4e, 0x07, 0xee, 0x8d, 0x33, 0x10, - 0xe0, 0x0c, 0x42, 0xe4, 0xc2, 0x10, 0xb3, 0xcd, 0xc8, 0xc0, 0x6f, 0xc6, 0x5e, 0x98, 0xa4, 0x11, - 0x63, 0x51, 0x82, 0xbe, 0xec, 0xc0, 0x84, 0x4c, 0x4d, 0xc1, 0xac, 0xa1, 0x32, 0xe4, 0xfb, 0x9a, - 0x2d, 0x3f, 0xc7, 0x45, 0x1d, 0x7b, 0x1a, 0x50, 0x69, 0x80, 0x63, 0x9c, 0xe9, 0x84, 0xfb, 0x02, - 0x9c, 0xc8, 0x69, 0x6e, 0x45, 0xa3, 0xfd, 0x8e, 0x03, 0x25, 0x2d, 0x63, 0x22, 0x7a, 0x1d, 0x46, - 0xc3, 0x8a, 0xf5, 0x28, 0xbe, 0xd5, 0x4a, 0x57, 0x14, 0x9f, 0x02, 0xe1, 0x94, 0x60, 0x3f, 0xc1, - 0x87, 0xb9, 0xe9, 0x1d, 0xef, 0x73, 0xb7, 0xf7, 0x1d, 0x7c, 0xf8, 0xab, 0x45, 0x48, 0x31, 0xed, - 0x33, 0x65, 0x4a, 0x1a, 0xaa, 0x58, 0xd8, 0x33, 0x54, 0xb1, 0x06, 0xc7, 0x3c, 0xe6, 0x4b, 0x3e, - 0x60, 0xa2, 0x14, 0x9e, 0x30, 0xd7, 0xc4, 0x80, 0xb3, 0x28, 0x29, 0x95, 0x38, 0x6d, 0xca, 0xa8, - 0x0c, 0xee, 0x9b, 0x4a, 0xc5, 0xc4, 0x80, 0xb3, 0x28, 0xd1, 0x4b, 0x50, 0xae, 0xb2, 0x8b, 0xbf, - 0x7c, 0x8c, 0x97, 0x37, 0xaf, 0x86, 0xc9, 0x5a, 0x44, 0x62, 0x12, 0x24, 0x22, 0x25, 0xda, 0x23, - 0x62, 0x16, 0xca, 0xf3, 0x3d, 0xea, 0xe1, 0x9e, 0x18, 0xa8, 0x9a, 0xc2, 0x9c, 0xd1, 0x7e, 0xb2, - 0xc3, 0x98, 0x88, 0xf0, 0xd2, 0x2b, 0x35, 0xa5, 0xa2, 0x17, 0x62, 0xb3, 0x2e, 0xfa, 0x15, 0x07, - 0xc6, 0x9b, 0xd2, 0x5c, 0x8f, 0x3b, 0x4d, 0x99, 0xdf, 0x13, 0x5b, 0x59, 0x7e, 0x57, 0x74, 0xcc, - 0x5c, 0x96, 0x30, 0x40, 0xd8, 0xa4, 0x9d, 0xcd, 0x5a, 0x33, 0xd2, 0x67, 0xd6, 0x9a, 0xef, 0x3b, - 0x30, 0x99, 0xa5, 0x86, 0xb6, 0xe0, 0xe1, 0x96, 0x17, 0x6d, 0x5d, 0x0e, 0x36, 0x23, 0x76, 0xc1, - 0x23, 0xe1, 0x8b, 0x61, 0x76, 0x33, 0x21, 0xd1, 0x82, 0xb7, 0xc3, 0xdd, 0x9f, 0x45, 0xf5, 0x40, - 0xd4, 0xc3, 0x2b, 0x7b, 0x55, 0xc6, 0x7b, 0xe3, 0x42, 0x15, 0x38, 0x45, 0x2b, 0xb0, 0xa4, 0x76, - 0x7e, 0x18, 0xa4, 0x44, 0x0a, 0x8c, 0x88, 0x0a, 0x32, 0x5c, 0xc9, 0xab, 0x84, 0xf3, 0xdb, 0xba, - 0x17, 0x61, 0x88, 0xdf, 0xb7, 0xbb, 0x27, 0xff, 0x91, 0xfb, 0xef, 0x0a, 0x20, 0x05, 0xc3, 0xbf, - 0xda, 0xee, 0x38, 0x7a, 0x88, 0x46, 0xcc, 0xa4, 0x24, 0xac, 0x1d, 0xec, 0x10, 0x15, 0xe9, 0x23, - 0x45, 0x09, 0x95, 0x98, 0xc9, 0x2d, 0x3f, 0x99, 0x0f, 0x6b, 0xd2, 0xc6, 0xc1, 0x24, 0xe6, 0x8b, - 0x02, 0x86, 0x55, 0xa9, 0xfb, 0x49, 0x07, 0xc6, 0xe9, 0x28, 0x9b, 0x4d, 0xd2, 0xac, 0x24, 0xa4, - 0x1d, 0xa3, 0x18, 0x8a, 0x31, 0xfd, 0xc7, 0x9e, 0x29, 0x30, 0xbd, 0xa3, 0x49, 0xda, 0x9a, 0xb3, - 0x86, 0x12, 0xc1, 0x9c, 0x96, 0xfb, 0xd6, 0x00, 0x8c, 0xaa, 0xc9, 0xee, 0xc3, 0x9e, 0x7a, 0x21, - 0xcd, 0xec, 0xca, 0x39, 0x70, 0x59, 0xcb, 0xea, 0x7a, 0x87, 0x4e, 0x5d, 0xb0, 0xc3, 0x53, 0x5c, - 0xa4, 0x29, 0x5e, 0x9f, 0x32, 0x5d, 0xcd, 0xa7, 0xf5, 0xf5, 0xa7, 0xd5, 0x17, 0x3e, 0xe7, 0x5b, - 0xba, 0xa7, 0x7f, 0xd0, 0xd6, 0x69, 0xa6, 0xdc, 0x98, 0xbd, 0x5d, 0xfc, 0x99, 0x47, 0x7f, 0x8a, - 0x7d, 0x3d, 0xfa, 0xf3, 0x24, 0x0c, 0x92, 0xa0, 0xd3, 0x62, 0xa2, 0xd2, 0x28, 0x53, 0x11, 0x06, - 0x2f, 0x06, 0x9d, 0x96, 0x39, 0x32, 0x56, 0x05, 0xbd, 0x0f, 0x4a, 0x35, 0x12, 0x57, 0x23, 0x9f, - 0xe5, 0x6d, 0x10, 0x96, 0x9d, 0x87, 0x98, 0xb9, 0x2c, 0x05, 0x9b, 0x0d, 0xf5, 0x06, 0xee, 0xab, - 0x30, 0xb4, 0xd6, 0xec, 0xd4, 0xfd, 0x00, 0xb5, 0x61, 0x88, 0x67, 0x71, 0x10, 0xa7, 0xbd, 0x05, - 0xbd, 0x93, 0xb3, 0x0a, 0x2d, 0x0a, 0x85, 0x5f, 0xd5, 0x15, 0x74, 0xdc, 0x4f, 0x14, 0x80, 0xaa, - 0xe6, 0x4b, 0xf3, 0xe8, 0x6f, 0x76, 0xbd, 0x71, 0xf3, 0x73, 0x39, 0x6f, 0xdc, 0x8c, 0xb3, 0xca, - 0x39, 0xcf, 0xdb, 0x34, 0x61, 0x9c, 0x39, 0x47, 0xe4, 0x19, 0x28, 0xc4, 0xea, 0x67, 0xfa, 0x4c, - 0x7c, 0xa0, 0x37, 0x15, 0x27, 0x82, 0x0e, 0xc2, 0x26, 0x72, 0xb4, 0x02, 0x27, 0x78, 0x82, 0xd0, - 0x05, 0xd2, 0xf4, 0x76, 0x32, 0x89, 0xc0, 0xce, 0xca, 0x67, 0xcb, 0x16, 0xba, 0xab, 0xe0, 0xbc, - 0x76, 0xee, 0xef, 0x0f, 0x82, 0xe6, 0x92, 0xe8, 0x63, 0xb7, 0xbc, 0x92, 0x71, 0x40, 0xad, 0x58, - 0x71, 0x40, 0x49, 0xaf, 0x0e, 0xe7, 0x40, 0xa6, 0xcf, 0x89, 0x76, 0xaa, 0x41, 0x9a, 0x6d, 0x31, - 0x46, 0xd5, 0xa9, 0x4b, 0xa4, 0xd9, 0xc6, 0xac, 0x44, 0x5d, 0x54, 0x1c, 0xec, 0x79, 0x51, 0xb1, - 0x01, 0xc5, 0xba, 0xd7, 0xa9, 0x13, 0x11, 0x81, 0x69, 0xc1, 0xd7, 0xc8, 0xae, 0x4e, 0x70, 0x5f, - 0x23, 0xfb, 0x17, 0x73, 0x02, 0x74, 0xb3, 0x37, 0x64, 0x48, 0x8a, 0x30, 0xd2, 0x5a, 0xd8, 0xec, - 0x2a, 0xca, 0x85, 0x6f, 0x76, 0xf5, 0x13, 0xa7, 0xc4, 0x50, 0x1b, 0x86, 0xab, 0x3c, 0xfd, 0x8a, - 0x90, 0x59, 0x2e, 0xdb, 0xb8, 0x89, 0xc9, 0x10, 0x72, 0x6b, 0x8a, 0xf8, 0x81, 0x25, 0x19, 0xf7, - 0x3c, 0x94, 0xb4, 0xa7, 0x36, 0xe8, 0x67, 0x50, 0x99, 0x3f, 0xb4, 0xcf, 0xb0, 0xe0, 0x25, 0x1e, - 0x66, 0x25, 0xee, 0x37, 0x07, 0x41, 0xd9, 0xd2, 0xf4, 0x7b, 0x83, 0x5e, 0x55, 0xcb, 0x53, 0x64, - 0xdc, 0xa1, 0x0f, 0x03, 0x2c, 0x4a, 0xa9, 0x5c, 0xd7, 0x22, 0x51, 0x5d, 0xe9, 0xd1, 0x82, 0x5d, - 0x2b, 0xb9, 0x6e, 0x45, 0x2f, 0xc4, 0x66, 0x5d, 0x2a, 0x94, 0xb7, 0x84, 0x8b, 0x3e, 0x1b, 0x58, - 0x2d, 0x5d, 0xf7, 0x58, 0xd5, 0x60, 0x89, 0x0e, 0x5a, 0x9a, 0x47, 0x5f, 0x04, 0x62, 0xda, 0x70, - 0x28, 0x69, 0x58, 0x79, 0xc0, 0x94, 0x0e, 0xc1, 0x06, 0x55, 0xb4, 0x04, 0xc7, 0x63, 0x92, 0xac, - 0xde, 0x0c, 0x48, 0xa4, 0x52, 0x0c, 0x88, 0x4c, 0x1a, 0xea, 0x56, 0x45, 0x25, 0x5b, 0x01, 0x77, - 0xb7, 0xc9, 0x8d, 0x5d, 0x2d, 0xee, 0x3b, 0x76, 0x75, 0x01, 0x26, 0x37, 0x3d, 0xbf, 0xd9, 0x89, - 0x48, 0xcf, 0x08, 0xd8, 0xc5, 0x4c, 0x39, 0xee, 0x6a, 0xc1, 0x2e, 0xf6, 0x34, 0xbd, 0x7a, 0x5c, - 0x1e, 0xd6, 0x2e, 0xf6, 0x50, 0x00, 0xe6, 0x70, 0xf7, 0xb7, 0x1c, 0xe0, 0x29, 0x8c, 0x66, 0x37, - 0x37, 0xfd, 0xc0, 0x4f, 0x76, 0xd0, 0xd7, 0x1c, 0x98, 0x0c, 0xc2, 0x1a, 0x99, 0x0d, 0x12, 0x5f, - 0x02, 0xed, 0xe5, 0x95, 0x67, 0xb4, 0xae, 0x66, 0xd0, 0xf3, 0x7c, 0x18, 0x59, 0x28, 0xee, 0xea, - 0x86, 0x7b, 0x06, 0x4e, 0xe5, 0x22, 0x70, 0xbf, 0x3f, 0x00, 0x66, 0x26, 0x26, 0xf4, 0x3c, 0x14, - 0x9b, 0x2c, 0x37, 0x88, 0x73, 0xc0, 0x14, 0x5b, 0x6c, 0xae, 0x78, 0xf2, 0x10, 0x8e, 0x09, 0x2d, - 0x40, 0x89, 0xa5, 0x77, 0x12, 0x99, 0x5b, 0x0a, 0x46, 0x4a, 0x84, 0x12, 0x4e, 0x8b, 0xee, 0x98, - 0x3f, 0xb1, 0xde, 0x0c, 0xbd, 0x06, 0xc3, 0x1b, 0x3c, 0xc9, 0xa5, 0x3d, 0x9f, 0x9f, 0xc8, 0x9a, - 0xc9, 0x64, 0x23, 0x99, 0x42, 0xf3, 0x4e, 0xfa, 0x2f, 0x96, 0x14, 0xd1, 0x0e, 0x8c, 0x78, 0xf2, - 0x9b, 0x0e, 0xda, 0xba, 0xa8, 0x61, 0xac, 0x1f, 0x11, 0x31, 0x23, 0xbf, 0xa1, 0x22, 0x97, 0x09, - 0x2d, 0x2a, 0xf6, 0x15, 0x5a, 0xf4, 0x6d, 0x07, 0x20, 0x7d, 0x11, 0x04, 0xdd, 0x82, 0x91, 0xf8, - 0x19, 0xc3, 0x50, 0x61, 0xe3, 0x86, 0xbe, 0xc0, 0xa8, 0xdd, 0x62, 0x15, 0x10, 0xac, 0xa8, 0xdd, - 0xcd, 0xb8, 0xf2, 0x53, 0x07, 0x4e, 0xe6, 0xbd, 0x5c, 0x72, 0x1f, 0x7b, 0xbc, 0x5f, 0xbb, 0x8a, - 0x68, 0xb0, 0x16, 0x91, 0x4d, 0xff, 0x56, 0x4e, 0xaa, 0x65, 0x5e, 0x80, 0xd3, 0x3a, 0xee, 0x9f, - 0x0e, 0x83, 0x22, 0x7c, 0x48, 0x76, 0x98, 0xc7, 0xa9, 0xce, 0x54, 0x4f, 0x65, 0x2e, 0x55, 0x0f, - 0x33, 0x28, 0x16, 0xa5, 0x54, 0x6f, 0x92, 0x41, 0xf1, 0x82, 0x65, 0xb3, 0x55, 0x28, 0x83, 0xe7, - 0xb1, 0x2a, 0xcd, 0xb3, 0xec, 0x14, 0x8f, 0xc4, 0xb2, 0x33, 0x64, 0xdf, 0xb2, 0xd3, 0x02, 0x14, - 0xf3, 0x8d, 0xc2, 0xcc, 0x29, 0x82, 0xd0, 0xd8, 0xbe, 0x0d, 0xcd, 0x95, 0x2e, 0x24, 0x38, 0x07, - 0x31, 0x8b, 0xa1, 0x08, 0x9b, 0x64, 0x16, 0x5f, 0x15, 0xca, 0x47, 0x1a, 0x43, 0xc1, 0xc1, 0x58, - 0x96, 0x1f, 0xd0, 0x94, 0x82, 0x7e, 0xc7, 0xd9, 0xc3, 0x56, 0x35, 0x6a, 0xeb, 0x08, 0xca, 0x4d, - 0x83, 0xc7, 0x34, 0xa9, 0x83, 0x18, 0xc0, 0xbe, 0xee, 0xc0, 0x71, 0x12, 0x54, 0xa3, 0x1d, 0x86, - 0x47, 0x60, 0x13, 0x2e, 0xee, 0x6b, 0x36, 0xf6, 0xfa, 0xc5, 0x2c, 0x72, 0xee, 0x49, 0xea, 0x02, - 0xe3, 0xee, 0x6e, 0xa0, 0x55, 0x18, 0xa9, 0x7a, 0x62, 0x5d, 0x94, 0xf6, 0xb3, 0x2e, 0xb8, 0xa3, - 0x6e, 0x56, 0xac, 0x06, 0x85, 0xc4, 0xfd, 0x71, 0x01, 0x4e, 0xe4, 0x74, 0x89, 0xdd, 0xd7, 0x6a, - 0xd1, 0x0d, 0x70, 0xb9, 0x96, 0xdd, 0xfe, 0xcb, 0x02, 0x8e, 0x55, 0x0d, 0xb4, 0x06, 0x27, 0xb7, - 0x5a, 0x71, 0x8a, 0x65, 0x3e, 0x0c, 0x12, 0x72, 0x4b, 0x32, 0x03, 0xe9, 0xfe, 0x3e, 0xb9, 0x9c, - 0x53, 0x07, 0xe7, 0xb6, 0xa4, 0xd2, 0x12, 0x09, 0xbc, 0x8d, 0x26, 0x49, 0x8b, 0xc4, 0x2d, 0x46, - 0x25, 0x2d, 0x5d, 0xcc, 0x94, 0xe3, 0xae, 0x16, 0xe8, 0xb3, 0x0e, 0x9c, 0x8d, 0x49, 0xb4, 0x4d, - 0xa2, 0x8a, 0x5f, 0x23, 0xf3, 0x9d, 0x38, 0x09, 0x5b, 0x24, 0x3a, 0xa0, 0x75, 0x76, 0xfa, 0xf6, - 0xee, 0xf4, 0xd9, 0x4a, 0x6f, 0x6c, 0x78, 0x2f, 0x52, 0xee, 0x67, 0x1d, 0x98, 0xa8, 0x30, 0xdd, - 0x5d, 0x89, 0xee, 0xb6, 0x13, 0xa1, 0x3e, 0xae, 0xf2, 0x6e, 0x64, 0x98, 0xb0, 0x99, 0x29, 0xc3, - 0x7d, 0x19, 0x26, 0x2b, 0xa4, 0xe5, 0xb5, 0x1b, 0xec, 0x0a, 0x32, 0x0f, 0xff, 0x3a, 0x0f, 0xa3, - 0xb1, 0x84, 0x65, 0xdf, 0x3e, 0x52, 0x95, 0x71, 0x5a, 0x07, 0x3d, 0xc6, 0x43, 0xd5, 0xe4, 0x85, - 0xa3, 0x51, 0xae, 0xe4, 0xf0, 0xf8, 0xb6, 0x18, 0xcb, 0x32, 0xf7, 0x2d, 0x07, 0xc6, 0xd2, 0xf6, - 0x64, 0x13, 0xd5, 0xe1, 0x58, 0x55, 0xbb, 0xac, 0x97, 0x5e, 0x93, 0xe8, 0xff, 0x5e, 0x1f, 0xcf, - 0xcf, 0x6c, 0x22, 0xc1, 0x59, 0xac, 0xfb, 0x8f, 0xf4, 0xfb, 0x42, 0x01, 0x8e, 0xa9, 0xae, 0x0a, - 0x3f, 0xe5, 0x1b, 0xd9, 0x80, 0x3c, 0x6c, 0x23, 0x83, 0x90, 0x39, 0xf7, 0x7b, 0x04, 0xe5, 0xbd, - 0x91, 0x0d, 0xca, 0x3b, 0x54, 0xf2, 0x5d, 0xae, 0xd7, 0x6f, 0x17, 0x60, 0x44, 0xe5, 0x33, 0x7a, - 0x1e, 0x8a, 0x4c, 0x73, 0xbd, 0x37, 0xf9, 0x9b, 0x69, 0xc1, 0x98, 0x63, 0xa2, 0x28, 0x59, 0xd0, - 0xcf, 0x81, 0xb3, 0xe6, 0x8e, 0x72, 0xfb, 0xa5, 0x17, 0x25, 0x98, 0x63, 0x42, 0xcb, 0x30, 0x40, - 0x82, 0x9a, 0x10, 0xc4, 0xf7, 0x8f, 0x90, 0xbd, 0x52, 0x76, 0x31, 0xa8, 0x61, 0x8a, 0x85, 0x25, - 0x55, 0xe3, 0xf2, 0x56, 0xe6, 0x4d, 0x1a, 0x21, 0x6c, 0x89, 0x52, 0xf7, 0xfd, 0x60, 0x24, 0xdc, - 0x13, 0x89, 0xfc, 0x85, 0x8e, 0xd7, 0xfd, 0x90, 0x98, 0x50, 0xee, 0xd2, 0x3a, 0xee, 0xaf, 0x0c, - 0xc0, 0x50, 0xa5, 0xb3, 0x41, 0x75, 0x92, 0x6f, 0x39, 0x70, 0xe2, 0x66, 0x26, 0x27, 0x75, 0xba, - 0x49, 0xae, 0xd9, 0x33, 0x02, 0xeb, 0x91, 0x6b, 0xca, 0xf4, 0x95, 0x53, 0x88, 0xf3, 0xba, 0x63, - 0xa4, 0x85, 0x1d, 0x38, 0x94, 0xb4, 0xb0, 0xb7, 0x0e, 0xf9, 0xea, 0xc6, 0x78, 0xaf, 0x6b, 0x1b, - 0xee, 0xef, 0x17, 0x01, 0xf8, 0xd7, 0x58, 0x6d, 0x27, 0xfd, 0x98, 0xf5, 0x9e, 0x85, 0xb1, 0x3a, - 0x09, 0x48, 0x24, 0xe3, 0x12, 0x33, 0xef, 0x25, 0x2d, 0x69, 0x65, 0xd8, 0xa8, 0xc9, 0x74, 0xa8, - 0x20, 0x89, 0x76, 0xb8, 0x9c, 0x9d, 0xbd, 0x9e, 0xa1, 0x4a, 0xb0, 0x56, 0x0b, 0xcd, 0x18, 0x5e, - 0x17, 0xee, 0xc0, 0x9f, 0xd8, 0xc3, 0x49, 0xf2, 0x3e, 0x98, 0x30, 0x73, 0xa8, 0x08, 0x69, 0x4f, - 0x39, 0xdc, 0xcd, 0xd4, 0x2b, 0x38, 0x53, 0x9b, 0xee, 0x82, 0x5a, 0xb4, 0x83, 0x3b, 0x81, 0x10, - 0xfb, 0xd4, 0x2e, 0x58, 0x60, 0x50, 0x2c, 0x4a, 0x59, 0xf2, 0x09, 0x76, 0x00, 0x72, 0xb8, 0x48, - 0x60, 0x91, 0x26, 0x9f, 0xd0, 0xca, 0xb0, 0x51, 0x93, 0x52, 0x10, 0x66, 0x51, 0x30, 0xf7, 0x59, - 0xc6, 0x96, 0xd9, 0x86, 0x89, 0xd0, 0x34, 0xe7, 0x70, 0x19, 0xe8, 0x5d, 0x7d, 0x2e, 0x3d, 0xa3, - 0x2d, 0x0f, 0x94, 0xc8, 0x58, 0x7f, 0x32, 0xf8, 0xa9, 0xdc, 0xab, 0xdf, 0x62, 0x18, 0x33, 0xc3, - 0x5a, 0x7b, 0x5e, 0x34, 0x58, 0x83, 0x93, 0xed, 0xb0, 0xb6, 0x16, 0xf9, 0x61, 0xe4, 0x27, 0x3b, - 0xf3, 0x4d, 0x2f, 0x8e, 0xd9, 0xc2, 0x18, 0x37, 0xe5, 0xa1, 0xb5, 0x9c, 0x3a, 0x38, 0xb7, 0x25, - 0x55, 0x88, 0xda, 0x02, 0xc8, 0x82, 0xcb, 0x8a, 0x5c, 0xa2, 0x93, 0x15, 0xb1, 0x2a, 0x75, 0x4f, - 0xc0, 0xf1, 0x4a, 0xa7, 0xdd, 0x6e, 0xfa, 0xa4, 0xa6, 0xbc, 0x1a, 0xee, 0xfb, 0xe1, 0x98, 0x48, - 0x1a, 0xab, 0xa4, 0x8f, 0x7d, 0xa5, 0x38, 0x77, 0xff, 0xdc, 0x81, 0x63, 0x99, 0x50, 0x1e, 0xf4, - 0x5a, 0x56, 0x66, 0xb0, 0x93, 0xcc, 0x54, 0x93, 0x16, 0x44, 0x66, 0xd2, 0x3c, 0xf9, 0xa3, 0x21, - 0xe3, 0xf0, 0xad, 0xdd, 0x7f, 0x61, 0xd1, 0xea, 0xfc, 0x48, 0xd1, 0x83, 0xf9, 0xdd, 0xcf, 0x14, - 0x20, 0x3f, 0x7e, 0x0a, 0x7d, 0xb4, 0x7b, 0x02, 0x9e, 0xb7, 0x38, 0x01, 0x22, 0x80, 0xab, 0xf7, - 0x1c, 0x04, 0xe6, 0x1c, 0xac, 0x58, 0x9a, 0x03, 0x41, 0xb7, 0x7b, 0x26, 0xfe, 0xa7, 0x03, 0xa5, - 0xf5, 0xf5, 0x2b, 0xea, 0x9c, 0xc3, 0x70, 0x3a, 0xe6, 0xf7, 0xfb, 0x99, 0x9b, 0x79, 0x3e, 0x6c, - 0xb5, 0xb9, 0xd7, 0x59, 0x78, 0xc3, 0x59, 0xfe, 0xde, 0x4a, 0x6e, 0x0d, 0xdc, 0xa3, 0x25, 0xba, - 0x0c, 0x27, 0xf4, 0x92, 0x8a, 0xf6, 0x5c, 0x62, 0x51, 0xe4, 0xea, 0xe9, 0x2e, 0xc6, 0x79, 0x6d, - 0xb2, 0xa8, 0x84, 0x75, 0x95, 0x1d, 0x57, 0x39, 0xa8, 0x44, 0x31, 0xce, 0x6b, 0xe3, 0xae, 0x42, - 0x69, 0xdd, 0x8b, 0xd4, 0xc0, 0x3f, 0x00, 0x93, 0xd5, 0xb0, 0x25, 0xad, 0x5a, 0x57, 0xc8, 0x36, - 0x69, 0x8a, 0x21, 0xf3, 0x37, 0x4a, 0x32, 0x65, 0xb8, 0xab, 0xb6, 0xfb, 0xdf, 0xce, 0x81, 0xba, - 0xaf, 0xd8, 0xc7, 0x09, 0xd3, 0x56, 0x91, 0xa5, 0x45, 0xcb, 0x91, 0xa5, 0x8a, 0xd7, 0x66, 0xa2, - 0x4b, 0x93, 0x34, 0xba, 0x74, 0xc8, 0x76, 0x74, 0xa9, 0x92, 0x38, 0xbb, 0x22, 0x4c, 0xbf, 0xe2, - 0xc0, 0x58, 0x10, 0xd6, 0x88, 0x72, 0x07, 0x0e, 0x33, 0xb1, 0xf7, 0x25, 0x7b, 0x81, 0xfa, 0x3c, - 0x52, 0x52, 0xa0, 0xe7, 0x51, 0xcf, 0xea, 0x88, 0xd2, 0x8b, 0xb0, 0xd1, 0x0f, 0xb4, 0xa8, 0xd9, - 0x59, 0xb9, 0x3b, 0xe3, 0xa1, 0x3c, 0x7d, 0xe5, 0xae, 0x46, 0xd3, 0x5b, 0x9a, 0xdc, 0x34, 0x6a, - 0xcb, 0x7e, 0x28, 0x2f, 0xa1, 0x69, 0x5e, 0x19, 0x99, 0x82, 0x3a, 0x95, 0xa7, 0x5c, 0x18, 0xe2, - 0xe1, 0xd1, 0x22, 0x2b, 0x14, 0x73, 0x16, 0xf2, 0xd0, 0x69, 0x2c, 0x4a, 0x50, 0x22, 0x43, 0x0e, - 0x4a, 0xb6, 0x1e, 0x94, 0x30, 0x42, 0x1a, 0xf2, 0x63, 0x0e, 0xd0, 0x73, 0xba, 0x1e, 0x3c, 0xd6, - 0x8f, 0x1e, 0x3c, 0xde, 0x53, 0x07, 0xfe, 0xbc, 0x03, 0x63, 0x55, 0xed, 0x81, 0x87, 0xf2, 0x13, - 0xb6, 0x1e, 0xb2, 0xce, 0x7b, 0x87, 0x83, 0xfb, 0xa0, 0x8c, 0x07, 0x25, 0x0c, 0xea, 0x2c, 0x15, - 0x26, 0x53, 0xfa, 0xd9, 0xd1, 0x6f, 0x25, 0x4b, 0x85, 0x69, 0x44, 0x90, 0xa1, 0x9b, 0x14, 0x86, - 0x05, 0x2d, 0xf4, 0x3a, 0x8c, 0xc8, 0x08, 0x7b, 0x11, 0x89, 0x8e, 0x6d, 0x38, 0x05, 0x4c, 0xcf, - 0xa3, 0xcc, 0x9f, 0xc7, 0xa1, 0x58, 0x51, 0x44, 0x0d, 0x18, 0xa8, 0x79, 0x75, 0x11, 0x93, 0xbe, - 0x62, 0x27, 0x3f, 0xa9, 0xa4, 0xc9, 0xf4, 0xb3, 0x85, 0xd9, 0x25, 0x4c, 0x49, 0xa0, 0x5b, 0x69, - 0x86, 0xfc, 0x49, 0x6b, 0xa7, 0xaf, 0x29, 0x26, 0x71, 0xb3, 0x46, 0x57, 0xc2, 0xfd, 0x9a, 0x70, - 0xd6, 0xfe, 0x7f, 0x8c, 0xec, 0xa2, 0x9d, 0x04, 0xa7, 0x3c, 0xeb, 0x49, 0xea, 0xf0, 0xa5, 0x54, - 0x1a, 0x49, 0xd2, 0x2e, 0xff, 0xbc, 0x2d, 0x2a, 0x2c, 0x77, 0x07, 0x7f, 0x73, 0x7c, 0x7d, 0x7d, - 0x0d, 0x33, 0xec, 0xa8, 0x09, 0x43, 0x6d, 0x16, 0x47, 0x52, 0xfe, 0x05, 0x5b, 0x67, 0x0b, 0x8f, - 0x4b, 0xe1, 0x6b, 0x93, 0xff, 0x8f, 0x05, 0x0d, 0x74, 0x11, 0x86, 0xf9, 0x43, 0x2f, 0xfc, 0x4e, - 0x40, 0xe9, 0xc2, 0x54, 0xef, 0xe7, 0x62, 0xd2, 0x83, 0x82, 0xff, 0x8e, 0xb1, 0x6c, 0x8b, 0xbe, - 0xe0, 0xc0, 0x04, 0xe5, 0xa8, 0xe9, 0xcb, 0x34, 0x65, 0x64, 0x8b, 0x67, 0x5d, 0x8b, 0xa9, 0x44, - 0x22, 0x79, 0x8d, 0x52, 0x93, 0x2e, 0x1b, 0xe4, 0x70, 0x86, 0x3c, 0x7a, 0x03, 0x46, 0x62, 0xbf, - 0x46, 0xaa, 0x5e, 0x14, 0x97, 0x4f, 0x1c, 0x4e, 0x57, 0x52, 0xf7, 0x90, 0x20, 0x84, 0x15, 0x49, - 0xf4, 0xeb, 0xec, 0x69, 0x50, 0xf1, 0x8c, 0x7f, 0x95, 0x8b, 0xf5, 0x27, 0x6d, 0xed, 0x7d, 0xe9, - 0x08, 0x93, 0x98, 0x85, 0xd7, 0xc4, 0x24, 0x87, 0xb3, 0xf4, 0xd1, 0xdf, 0x72, 0xe0, 0x14, 0x4f, - 0xe1, 0x9f, 0x7d, 0x95, 0xe2, 0xd4, 0x01, 0xed, 0x33, 0xec, 0x32, 0xc3, 0x6c, 0x1e, 0x4a, 0x9c, - 0x4f, 0x89, 0x25, 0xdc, 0x35, 0x1f, 0x12, 0x3a, 0x6d, 0xd5, 0x4d, 0xda, 0xff, 0xe3, 0x41, 0xe8, - 0x69, 0x28, 0xb5, 0xc5, 0x71, 0xe8, 0xc7, 0x2d, 0x76, 0x35, 0x65, 0x80, 0x5f, 0x1a, 0x5c, 0x4b, - 0xc1, 0x58, 0xaf, 0x63, 0x64, 0x5f, 0x7e, 0x72, 0xaf, 0xec, 0xcb, 0xe8, 0x1a, 0x94, 0x92, 0xb0, - 0x29, 0x12, 0x90, 0xc6, 0xe5, 0x32, 0x5b, 0x81, 0xe7, 0xf2, 0xf6, 0xd6, 0xba, 0xaa, 0x96, 0x6a, - 0xb2, 0x29, 0x2c, 0xc6, 0x3a, 0x1e, 0x16, 0x0e, 0x2c, 0x9e, 0x46, 0x88, 0x98, 0x0a, 0xfb, 0x60, - 0x26, 0x1c, 0x58, 0x2f, 0xc4, 0x66, 0x5d, 0xb4, 0x04, 0xc7, 0xdb, 0x5d, 0x3a, 0x30, 0xbf, 0x12, - 0xa7, 0x22, 0x30, 0xba, 0x15, 0xe0, 0xee, 0x36, 0x86, 0xf6, 0x7b, 0x76, 0x2f, 0xed, 0xb7, 0x47, - 0x2e, 0xe2, 0x87, 0x0e, 0x92, 0x8b, 0x18, 0xd5, 0xe0, 0x21, 0xaf, 0x93, 0x84, 0x2c, 0x3f, 0x8d, - 0xd9, 0x84, 0x47, 0x46, 0x3f, 0xc2, 0x83, 0xad, 0x6f, 0xef, 0x4e, 0x3f, 0x34, 0xbb, 0x47, 0x3d, - 0xbc, 0x27, 0x16, 0xf4, 0x2a, 0x8c, 0x10, 0x91, 0x4f, 0xb9, 0xfc, 0x73, 0xb6, 0x84, 0x04, 0x33, - 0x43, 0xb3, 0x0c, 0x3a, 0xe5, 0x30, 0xac, 0xe8, 0xa1, 0x75, 0x28, 0x35, 0xc2, 0x38, 0x99, 0x6d, - 0xfa, 0x5e, 0x4c, 0xe2, 0xf2, 0xc3, 0x6c, 0xd1, 0xe4, 0xca, 0x5e, 0x97, 0x64, 0xb5, 0x74, 0xcd, - 0x5c, 0x4a, 0x5b, 0x62, 0x1d, 0x0d, 0x22, 0xcc, 0x59, 0xca, 0xc2, 0xc2, 0xa5, 0x23, 0xe8, 0x1c, - 0x1b, 0xd8, 0xe3, 0x79, 0x98, 0xd7, 0xc2, 0x5a, 0xc5, 0xac, 0xad, 0xbc, 0xa5, 0x3a, 0x10, 0x67, - 0x71, 0xa2, 0x67, 0x61, 0xac, 0x1d, 0xd6, 0x2a, 0x6d, 0x52, 0x5d, 0xf3, 0x92, 0x6a, 0xa3, 0x3c, - 0x6d, 0x5a, 0xdd, 0xd6, 0xb4, 0x32, 0x6c, 0xd4, 0x44, 0x6d, 0x18, 0x6e, 0xf1, 0xc4, 0x05, 0xe5, - 0x47, 0x6d, 0xe9, 0x36, 0x22, 0x13, 0x02, 0x97, 0x17, 0xc4, 0x0f, 0x2c, 0xc9, 0xa0, 0x7f, 0xe8, - 0xc0, 0xb1, 0xcc, 0x65, 0xab, 0xf2, 0x3b, 0xac, 0x89, 0x2c, 0x26, 0xe2, 0xb9, 0xc7, 0xd9, 0xf4, - 0x99, 0xc0, 0x3b, 0xdd, 0x20, 0x9c, 0xed, 0x11, 0x9f, 0x17, 0x96, 0x7d, 0xa4, 0xfc, 0x98, 0xbd, - 0x79, 0x61, 0x08, 0xe5, 0xbc, 0xb0, 0x1f, 0x58, 0x92, 0x41, 0x4f, 0xc2, 0xb0, 0x48, 0x14, 0x58, - 0x7e, 0xdc, 0x74, 0x41, 0x8b, 0x7c, 0x82, 0x58, 0x96, 0x4f, 0xbd, 0x1f, 0x8e, 0x77, 0xa9, 0x6e, - 0xfb, 0x4a, 0x81, 0xf1, 0x9b, 0x0e, 0xe8, 0xb7, 0xb3, 0xad, 0x3f, 0x62, 0xf2, 0x2c, 0x8c, 0x55, - 0xf9, 0x9b, 0x92, 0xfc, 0x7e, 0xf7, 0xa0, 0x69, 0xff, 0x9c, 0xd7, 0xca, 0xb0, 0x51, 0xd3, 0xbd, - 0x04, 0xa8, 0x3b, 0xc3, 0xfc, 0x81, 0xf2, 0x2b, 0xfd, 0x63, 0x07, 0xc6, 0x0d, 0x99, 0xc1, 0xba, - 0x93, 0x71, 0x11, 0x50, 0xcb, 0x8f, 0xa2, 0x30, 0xd2, 0x1f, 0xef, 0x13, 0x39, 0x18, 0x58, 0xf0, - 0xc1, 0x4a, 0x57, 0x29, 0xce, 0x69, 0xe1, 0xfe, 0xd3, 0x41, 0x48, 0xa3, 0xae, 0x55, 0x0a, 0x5f, - 0xa7, 0x67, 0x0a, 0xdf, 0xa7, 0x60, 0xe4, 0xe5, 0x38, 0x0c, 0xd6, 0xd2, 0x44, 0xbf, 0xea, 0x5b, - 0x3c, 0x57, 0x59, 0xbd, 0xca, 0x6a, 0xaa, 0x1a, 0xac, 0xf6, 0x2b, 0x8b, 0x7e, 0x33, 0xe9, 0xce, - 0x04, 0xfb, 0xdc, 0xf3, 0x1c, 0x8e, 0x55, 0x0d, 0xf6, 0x8e, 0xdf, 0x36, 0x51, 0x86, 0xf1, 0xf4, - 0x1d, 0x3f, 0xfe, 0x78, 0x04, 0x2b, 0x43, 0xe7, 0x61, 0x54, 0x19, 0xd5, 0x85, 0xa5, 0x5e, 0xcd, - 0x94, 0xb2, 0xbc, 0xe3, 0xb4, 0x0e, 0x13, 0x08, 0x85, 0x21, 0x56, 0x98, 0x50, 0x2a, 0x36, 0xd4, - 0x93, 0x8c, 0x69, 0x97, 0xf3, 0x76, 0x09, 0xc6, 0x8a, 0x64, 0x9e, 0xa3, 0x75, 0xf4, 0x50, 0x1c, - 0xad, 0xda, 0x15, 0x80, 0x62, 0xbf, 0x57, 0x00, 0xcc, 0xb5, 0x3d, 0xd2, 0xd7, 0xda, 0xfe, 0xd4, - 0x00, 0x0c, 0x5f, 0x27, 0x11, 0x4b, 0x80, 0xfe, 0x24, 0x0c, 0x6f, 0xf3, 0x7f, 0xb3, 0xf7, 0x47, - 0x45, 0x0d, 0x2c, 0xcb, 0xe9, 0x77, 0xdb, 0xe8, 0xf8, 0xcd, 0xda, 0x42, 0xba, 0x8b, 0xd3, 0x1c, - 0x87, 0xb2, 0x00, 0xa7, 0x75, 0x68, 0x83, 0x3a, 0x95, 0xec, 0x5b, 0x2d, 0xbf, 0xeb, 0x89, 0xfa, - 0x25, 0x59, 0x80, 0xd3, 0x3a, 0xe8, 0x71, 0x18, 0xaa, 0xfb, 0xc9, 0xba, 0x57, 0xcf, 0xba, 0x09, - 0x97, 0x18, 0x14, 0x8b, 0x52, 0xe6, 0x26, 0xf2, 0x93, 0xf5, 0x88, 0x30, 0xcb, 0x6e, 0x57, 0xfa, - 0x8a, 0x25, 0xad, 0x0c, 0x1b, 0x35, 0x59, 0x97, 0x42, 0x31, 0x32, 0x11, 0x34, 0x9a, 0x76, 0x49, - 0x16, 0xe0, 0xb4, 0x0e, 0x5d, 0xff, 0xd5, 0xb0, 0xd5, 0xf6, 0x9b, 0x22, 0x9c, 0x59, 0x5b, 0xff, - 0xf3, 0x02, 0x8e, 0x55, 0x0d, 0x5a, 0x9b, 0xb2, 0x30, 0xca, 0x7e, 0xb2, 0x6f, 0xa6, 0xad, 0x09, - 0x38, 0x56, 0x35, 0xdc, 0xeb, 0x30, 0xce, 0x77, 0xf2, 0x7c, 0xd3, 0xf3, 0x5b, 0x4b, 0xf3, 0xe8, - 0x62, 0xd7, 0x15, 0x80, 0x27, 0x73, 0xae, 0x00, 0x9c, 0x32, 0x1a, 0x75, 0x5f, 0x05, 0x70, 0x7f, - 0x58, 0x80, 0x91, 0x23, 0x7c, 0x76, 0xf2, 0xc8, 0x5f, 0x50, 0x46, 0xb7, 0x32, 0x4f, 0x4e, 0xae, - 0xd9, 0xbc, 0xd1, 0xb3, 0xe7, 0x73, 0x93, 0xff, 0xb9, 0x00, 0xa7, 0x65, 0x55, 0xa9, 0xcb, 0x2d, - 0xcd, 0xb3, 0xa7, 0xbc, 0x0e, 0x7f, 0xa2, 0x23, 0x63, 0xa2, 0xd7, 0xec, 0x69, 0xa3, 0x4b, 0xf3, - 0x3d, 0xa7, 0xfa, 0xd5, 0xcc, 0x54, 0x63, 0xab, 0x54, 0xf7, 0x9e, 0xec, 0xbf, 0x70, 0x60, 0x2a, - 0x7f, 0xb2, 0x8f, 0xe0, 0x95, 0xcf, 0x37, 0xcc, 0x57, 0x3e, 0x7f, 0xc9, 0xde, 0x12, 0x33, 0x87, - 0xd2, 0xe3, 0xbd, 0xcf, 0xff, 0xe1, 0xc0, 0x49, 0xd9, 0x80, 0x9d, 0x9e, 0x73, 0x7e, 0xc0, 0x22, - 0x59, 0x0e, 0x7f, 0x99, 0xbd, 0x6e, 0x2c, 0xb3, 0x17, 0xed, 0x0d, 0x5c, 0x1f, 0x47, 0xcf, 0xd7, - 0xd1, 0xff, 0xcc, 0x81, 0x72, 0x5e, 0x83, 0x23, 0xf8, 0xe4, 0xaf, 0x99, 0x9f, 0xfc, 0xfa, 0xe1, - 0x8c, 0xbc, 0xf7, 0x07, 0x2f, 0xf7, 0x9a, 0x28, 0xd4, 0x94, 0x72, 0x95, 0x63, 0xcb, 0x47, 0xcb, - 0x49, 0xe4, 0x0b, 0x68, 0x4d, 0x18, 0x8a, 0x59, 0xd4, 0x86, 0x58, 0x02, 0x97, 0x6c, 0x48, 0x5b, - 0x14, 0x9f, 0xb0, 0xb1, 0xb3, 0xff, 0xb1, 0xa0, 0xe1, 0xfe, 0x56, 0x01, 0xce, 0xa8, 0xd7, 0x7b, - 0xc9, 0x36, 0x69, 0xa6, 0xfb, 0x83, 0x3d, 0x17, 0xe1, 0xa9, 0x9f, 0xf6, 0x9e, 0x8b, 0x48, 0x49, - 0xa4, 0x7b, 0x21, 0x85, 0x61, 0x8d, 0x26, 0xaa, 0xc0, 0x29, 0xf6, 0xbc, 0xc3, 0xa2, 0x1f, 0x78, - 0x4d, 0xff, 0x55, 0x12, 0x61, 0xd2, 0x0a, 0xb7, 0xbd, 0xa6, 0x90, 0xd4, 0xd5, 0x15, 0xe2, 0xc5, - 0xbc, 0x4a, 0x38, 0xbf, 0x6d, 0x97, 0xc6, 0x3d, 0xd0, 0xaf, 0xc6, 0xed, 0xfe, 0x89, 0x03, 0x63, - 0x47, 0xf8, 0xd6, 0x71, 0x68, 0x6e, 0x89, 0xe7, 0xec, 0x6d, 0x89, 0x1e, 0xdb, 0x60, 0xb7, 0x08, - 0x5d, 0xcf, 0xbf, 0xa2, 0x4f, 0x3b, 0x2a, 0xae, 0x85, 0x07, 0x0f, 0x7e, 0xc8, 0x5e, 0x3f, 0xf6, - 0x93, 0x77, 0x12, 0x7d, 0x3d, 0x93, 0x8c, 0xb3, 0x60, 0x2b, 0xa3, 0x54, 0x57, 0x6f, 0x0e, 0x90, - 0x94, 0xf3, 0x2b, 0x0e, 0x00, 0xef, 0xa7, 0xc8, 0xe5, 0x4d, 0xfb, 0xb6, 0x71, 0x68, 0x33, 0x45, - 0x89, 0xf0, 0xae, 0xa9, 0x2d, 0x94, 0x16, 0x60, 0xad, 0x27, 0xf7, 0x90, 0x6d, 0xf3, 0x9e, 0x13, - 0x7d, 0x7e, 0xc1, 0x81, 0x63, 0x99, 0xee, 0xe6, 0xb4, 0xdf, 0x34, 0x5f, 0x2b, 0xb4, 0x20, 0x59, - 0x99, 0x19, 0x9e, 0x75, 0xe3, 0xc9, 0x7f, 0x75, 0xc1, 0x78, 0x37, 0x1b, 0xbd, 0x06, 0xa3, 0xd2, - 0xf2, 0x21, 0x97, 0xb7, 0xcd, 0x57, 0x5b, 0x95, 0x7a, 0x23, 0x21, 0x31, 0x4e, 0xe9, 0x65, 0xc2, - 0xe6, 0x0a, 0x7d, 0x85, 0xcd, 0xdd, 0xdf, 0x37, 0x5f, 0xf3, 0xed, 0xd2, 0x83, 0x87, 0x62, 0x97, - 0x7e, 0xc8, 0xba, 0x5d, 0xfa, 0xe1, 0x23, 0xb6, 0x4b, 0x6b, 0x4e, 0xc2, 0xe2, 0x3d, 0x38, 0x09, - 0x5f, 0x83, 0x93, 0xdb, 0xa9, 0xd2, 0xa9, 0x56, 0x92, 0xc8, 0x63, 0xf4, 0x64, 0xae, 0x35, 0x9a, - 0x2a, 0xd0, 0x71, 0x42, 0x82, 0x44, 0x53, 0x57, 0xd3, 0x88, 0xbd, 0xeb, 0x39, 0xe8, 0x70, 0x2e, - 0x91, 0xac, 0xb7, 0x67, 0xb8, 0x0f, 0x6f, 0xcf, 0x5b, 0x0e, 0x9c, 0xf2, 0xba, 0xee, 0x9c, 0x61, - 0xb2, 0x29, 0x42, 0x4e, 0x6e, 0xd8, 0x13, 0x21, 0x0c, 0xf4, 0xc2, 0xad, 0x96, 0x57, 0x84, 0xf3, - 0x3b, 0x84, 0x1e, 0x4b, 0x5d, 0xef, 0x3c, 0xce, 0x33, 0xdf, 0x4f, 0xfe, 0xf5, 0x6c, 0x3c, 0x0f, - 0xb0, 0xa9, 0xff, 0x88, 0x5d, 0x6d, 0xdb, 0x42, 0x4c, 0x4f, 0xe9, 0x1e, 0x62, 0x7a, 0x32, 0xae, - 0xb7, 0x31, 0x4b, 0xae, 0xb7, 0x00, 0x26, 0xfd, 0x96, 0x57, 0x27, 0x6b, 0x9d, 0x66, 0x93, 0x5f, - 0x22, 0x91, 0xef, 0xea, 0xe6, 0x5a, 0xf0, 0xae, 0x84, 0x55, 0xaf, 0x99, 0x7d, 0x51, 0x5d, 0x5d, - 0x96, 0xb9, 0x9c, 0xc1, 0x84, 0xbb, 0x70, 0xd3, 0x05, 0xcb, 0x12, 0xea, 0x91, 0x84, 0xce, 0x36, - 0x0b, 0x1c, 0x19, 0xe1, 0x0b, 0xf6, 0x52, 0x0a, 0xc6, 0x7a, 0x1d, 0xb4, 0x0c, 0xa3, 0xb5, 0x20, - 0x16, 0xd7, 0x67, 0x8f, 0x31, 0x66, 0xf6, 0x4e, 0xca, 0x02, 0x17, 0xae, 0x56, 0xd4, 0xc5, 0xd9, - 0x87, 0x72, 0x32, 0x44, 0xaa, 0x72, 0x9c, 0xb6, 0x47, 0x2b, 0x0c, 0x99, 0x78, 0x74, 0x8c, 0xc7, - 0x73, 0x3c, 0xd2, 0xc3, 0x61, 0xb4, 0x70, 0x55, 0x3e, 0x9b, 0x36, 0x2e, 0xc8, 0x89, 0xd7, 0xc3, - 0x52, 0x0c, 0xda, 0xfb, 0xc6, 0xc7, 0xf7, 0x7c, 0xdf, 0x98, 0xa5, 0x86, 0x4d, 0x9a, 0xca, 0x3d, - 0x7c, 0xce, 0x5a, 0x6a, 0xd8, 0x34, 0x52, 0x52, 0xa4, 0x86, 0x4d, 0x01, 0x58, 0x27, 0x89, 0x56, - 0x7b, 0xb9, 0xc9, 0x4f, 0x30, 0xa6, 0xb1, 0x7f, 0xa7, 0xb7, 0xee, 0x2f, 0x3d, 0xb9, 0xa7, 0xbf, - 0xb4, 0xcb, 0xbf, 0x7b, 0x6a, 0x1f, 0xfe, 0xdd, 0x06, 0x4b, 0xda, 0xb9, 0x34, 0x2f, 0x5c, 0xea, - 0x16, 0xf4, 0x3b, 0x96, 0x26, 0x84, 0x47, 0x9e, 0xb2, 0x7f, 0x31, 0x27, 0xd0, 0x33, 0xa0, 0xfa, - 0xcc, 0x81, 0x03, 0xaa, 0x29, 0x7b, 0x4e, 0xe1, 0x2c, 0xfb, 0x6b, 0x51, 0xb0, 0xe7, 0x14, 0x8c, - 0xf5, 0x3a, 0x59, 0x6f, 0xe9, 0x83, 0x87, 0xe6, 0x2d, 0x9d, 0x3a, 0x02, 0x6f, 0xe9, 0xd9, 0xbe, - 0xbd, 0xa5, 0xb7, 0xe0, 0x44, 0x3b, 0xac, 0x2d, 0xf8, 0x71, 0xd4, 0x61, 0xb7, 0xea, 0xe6, 0x3a, - 0xb5, 0x3a, 0x49, 0x98, 0xbb, 0xb5, 0x74, 0xe1, 0x9d, 0x7a, 0x27, 0xdb, 0x6c, 0x23, 0xcb, 0x3d, - 0x9a, 0x69, 0xc0, 0x4c, 0x27, 0x2c, 0xea, 0x36, 0xa7, 0x10, 0xe7, 0x91, 0xd0, 0xfd, 0xb4, 0x8f, - 0x1c, 0x8d, 0x9f, 0xf6, 0x03, 0x30, 0x12, 0x37, 0x3a, 0x49, 0x2d, 0xbc, 0x19, 0x30, 0x67, 0xfc, - 0xe8, 0xdc, 0x3b, 0x94, 0x29, 0x5b, 0xc0, 0xef, 0xec, 0x4e, 0x4f, 0xca, 0xff, 0x35, 0x2b, 0xb6, - 0x80, 0xa0, 0x6f, 0xf4, 0xb8, 0xbf, 0xe3, 0x1e, 0xe6, 0xfd, 0x9d, 0x33, 0xfb, 0xba, 0xbb, 0x93, - 0xe7, 0x8c, 0x7e, 0xf4, 0x67, 0xce, 0x19, 0xfd, 0x35, 0x07, 0xc6, 0xb7, 0x75, 0x97, 0x81, 0x70, - 0x98, 0x5b, 0x08, 0xdc, 0x31, 0x3c, 0x11, 0x73, 0x2e, 0xe5, 0x73, 0x06, 0xe8, 0x4e, 0x16, 0x80, - 0xcd, 0x9e, 0xe4, 0x04, 0x15, 0x3d, 0x76, 0xbf, 0x82, 0x8a, 0xde, 0x60, 0x7c, 0x4c, 0x2a, 0xb9, - 0xcc, 0x8b, 0x6e, 0x37, 0xa6, 0x58, 0xf2, 0x44, 0x15, 0x52, 0xac, 0xd3, 0x43, 0x9f, 0x77, 0x60, - 0x52, 0xea, 0x65, 0xc2, 0xe5, 0x17, 0x8b, 0xa8, 0x48, 0x9b, 0xea, 0x20, 0x0b, 0xab, 0x5f, 0xcf, - 0xd0, 0xc1, 0x5d, 0x94, 0x29, 0x57, 0x57, 0x41, 0x68, 0xf5, 0x98, 0x05, 0xff, 0x0a, 0x19, 0x66, - 0x36, 0x05, 0x63, 0xbd, 0x0e, 0xfa, 0xa6, 0x03, 0xc5, 0x46, 0x18, 0x6e, 0xc5, 0xe5, 0x27, 0x19, - 0x43, 0x7f, 0xc1, 0xb2, 0x6c, 0x7a, 0x89, 0xe2, 0xe6, 0x42, 0xe9, 0xd3, 0xd2, 0x76, 0xc4, 0x60, - 0x77, 0x76, 0xa7, 0x27, 0x8c, 0xb7, 0x8d, 0xe2, 0x37, 0xdf, 0xd6, 0x20, 0xc2, 0xb6, 0xc9, 0xba, - 0x86, 0xbe, 0xe4, 0xc0, 0xe4, 0xcd, 0x8c, 0x41, 0x43, 0x84, 0x85, 0x62, 0xfb, 0xa6, 0x12, 0x3e, - 0xdd, 0x59, 0x28, 0xee, 0xea, 0x01, 0xfa, 0x9c, 0x69, 0xe8, 0xe4, 0xf1, 0xa3, 0x16, 0x27, 0x30, - 0x63, 0x58, 0xe5, 0xd7, 0xdc, 0xf2, 0x2d, 0x9e, 0xf7, 0x1c, 0x1f, 0x32, 0x45, 0x07, 0x93, 0x7e, - 0xac, 0x9c, 0xa6, 0xc4, 0xb4, 0xb7, 0x58, 0xd8, 0xec, 0xc6, 0xe7, 0xd7, 0xcd, 0x2d, 0x5f, 0x3a, - 0x0d, 0x13, 0xa6, 0x6f, 0x0f, 0xbd, 0xcb, 0x7c, 0xb7, 0xe2, 0x5c, 0xf6, 0x09, 0x80, 0x71, 0x59, - 0xdf, 0x78, 0x06, 0xc0, 0xc8, 0xd3, 0x5f, 0x38, 0xd4, 0x3c, 0xfd, 0x03, 0x47, 0x93, 0xa7, 0x7f, - 0xf2, 0x30, 0xf2, 0xf4, 0x1f, 0xdf, 0x57, 0x9e, 0x7e, 0xed, 0x9d, 0x84, 0xc1, 0xbb, 0xbc, 0x93, - 0x30, 0x0b, 0xc7, 0xe4, 0xdd, 0x1f, 0x22, 0x52, 0xa1, 0x73, 0xb7, 0xff, 0x19, 0xd1, 0xe4, 0xd8, - 0xbc, 0x59, 0x8c, 0xb3, 0xf5, 0xe9, 0x26, 0x2b, 0x06, 0xac, 0xe5, 0x90, 0xad, 0x47, 0x94, 0xcc, - 0xa5, 0xc5, 0xd4, 0x67, 0xc1, 0xa2, 0x64, 0xb4, 0x73, 0x91, 0xc1, 0xee, 0xc8, 0x7f, 0x30, 0xef, - 0x01, 0x7a, 0x09, 0xca, 0xe1, 0xe6, 0x66, 0x33, 0xf4, 0x6a, 0xe9, 0x63, 0x02, 0x32, 0x2e, 0x81, - 0xdf, 0xdd, 0x54, 0xb9, 0x67, 0x57, 0x7b, 0xd4, 0xc3, 0x3d, 0x31, 0xa0, 0xb7, 0xa8, 0x60, 0x92, - 0x84, 0x11, 0xa9, 0xa5, 0xb6, 0x9a, 0x51, 0x36, 0x66, 0x62, 0x7d, 0xcc, 0x15, 0x93, 0x0e, 0x1f, - 0xbd, 0xfa, 0x28, 0x99, 0x52, 0x9c, 0xed, 0x16, 0x8a, 0xe0, 0x74, 0x3b, 0xcf, 0x54, 0x14, 0x8b, - 0x1b, 0x4b, 0x7b, 0x19, 0xac, 0xd4, 0xc3, 0xd2, 0xb9, 0xc6, 0xa6, 0x18, 0xf7, 0xc0, 0xac, 0x27, - 0xfc, 0x1f, 0x39, 0x9a, 0x84, 0xff, 0x1f, 0x03, 0x50, 0x97, 0xd4, 0xa5, 0xf1, 0x61, 0xd9, 0xca, - 0x55, 0x1a, 0x8e, 0x53, 0x7b, 0x63, 0x55, 0x91, 0xc1, 0x1a, 0x49, 0xf4, 0xbf, 0x73, 0x5f, 0xc4, - 0xe0, 0x16, 0x96, 0xba, 0xf5, 0x35, 0xf1, 0x33, 0xf7, 0x2a, 0xc6, 0x3f, 0x72, 0x60, 0x8a, 0xaf, - 0xbc, 0xac, 0x70, 0x4f, 0x45, 0x0b, 0x71, 0xb7, 0xc7, 0x76, 0xe8, 0x0a, 0x4f, 0x21, 0x64, 0x50, - 0x65, 0x8e, 0xee, 0x3d, 0x7a, 0x82, 0xbe, 0x92, 0xa3, 0x52, 0x1c, 0xb3, 0x65, 0xb3, 0xcc, 0x7f, - 0xd7, 0xe0, 0xc4, 0xed, 0x7e, 0xb4, 0x88, 0x7f, 0xd2, 0xd3, 0xa4, 0x8a, 0x58, 0xf7, 0x7e, 0xf9, - 0x90, 0x4c, 0xaa, 0xfa, 0xe3, 0x0b, 0xfb, 0x32, 0xac, 0x7e, 0xc1, 0x81, 0x49, 0x2f, 0x13, 0x6a, - 0xc2, 0xec, 0x40, 0x56, 0x6c, 0x52, 0xb3, 0x51, 0x1a, 0xbf, 0xc2, 0x84, 0xbc, 0x6c, 0x54, 0x0b, - 0xee, 0x22, 0x8e, 0x7e, 0xe8, 0xc0, 0xd9, 0xc4, 0x8b, 0xb7, 0x78, 0x6a, 0xe3, 0x38, 0xbd, 0xab, - 0x2b, 0x3a, 0x77, 0x92, 0xed, 0xc6, 0x57, 0xac, 0xef, 0xc6, 0xf5, 0xde, 0x34, 0xf9, 0xbe, 0x7c, - 0x54, 0xec, 0xcb, 0xb3, 0x7b, 0xd4, 0xc4, 0x7b, 0x75, 0x7d, 0xea, 0xd3, 0x0e, 0x7f, 0x02, 0xab, - 0xa7, 0xc8, 0xb7, 0x61, 0x8a, 0x7c, 0x57, 0x6c, 0x3e, 0xc2, 0xa3, 0xcb, 0x9e, 0xbf, 0xe6, 0xc0, - 0xc9, 0xbc, 0x13, 0x29, 0xa7, 0x4b, 0x1f, 0x31, 0xbb, 0x64, 0x51, 0xcb, 0xd2, 0x3b, 0x64, 0xe5, - 0x0d, 0x90, 0xa9, 0xab, 0xf0, 0xc8, 0xdd, 0xbe, 0xe2, 0xdd, 0xf0, 0x8d, 0xe8, 0x62, 0xf1, 0x9f, - 0x8d, 0x6a, 0x5e, 0xc8, 0x84, 0xb4, 0xad, 0xc7, 0x70, 0x07, 0x30, 0xe4, 0x07, 0x4d, 0x3f, 0x20, - 0xe2, 0xbe, 0xa6, 0x4d, 0x1d, 0x56, 0xbc, 0xe1, 0x43, 0xb1, 0x63, 0x41, 0xe5, 0x3e, 0x3b, 0x25, - 0xb3, 0xaf, 0xa2, 0x0d, 0x1e, 0xfd, 0xab, 0x68, 0x37, 0x61, 0xf4, 0xa6, 0x9f, 0x34, 0x58, 0x30, - 0x85, 0xf0, 0xf5, 0x59, 0xb8, 0xe7, 0x48, 0xd1, 0xa5, 0x63, 0xbf, 0x21, 0x09, 0xe0, 0x94, 0x16, - 0x3a, 0xcf, 0x09, 0xb3, 0xc8, 0xed, 0x6c, 0x48, 0xed, 0x0d, 0x59, 0x80, 0xd3, 0x3a, 0x74, 0xb2, - 0xc6, 0xe8, 0x2f, 0x99, 0x10, 0x49, 0xa4, 0x09, 0xb6, 0x91, 0xfe, 0x51, 0x60, 0xe4, 0xb7, 0x89, - 0x6f, 0x68, 0x34, 0xb0, 0x41, 0x51, 0x65, 0x6a, 0x1e, 0xe9, 0x99, 0xa9, 0xf9, 0x75, 0x26, 0xb0, - 0x25, 0x7e, 0xd0, 0x21, 0xab, 0x81, 0x88, 0xf7, 0xbe, 0x62, 0xe7, 0xee, 0x33, 0xc7, 0xc9, 0x55, - 0xf0, 0xf4, 0x37, 0xd6, 0xe8, 0x69, 0x2e, 0x97, 0xd2, 0x9e, 0x2e, 0x97, 0xd4, 0xe4, 0x32, 0x66, - 0xdd, 0xe4, 0x92, 0x90, 0xb6, 0x15, 0x93, 0xcb, 0xcf, 0x94, 0x39, 0xe0, 0x2f, 0x1c, 0x40, 0x4a, - 0xee, 0x52, 0x0c, 0xf5, 0x08, 0x82, 0x2a, 0x3f, 0xee, 0x00, 0x04, 0xea, 0xed, 0x4c, 0xbb, 0xa7, - 0x20, 0xc7, 0x99, 0x76, 0x20, 0x85, 0x61, 0x8d, 0xa6, 0xfb, 0xa7, 0x4e, 0x1a, 0xbb, 0x9c, 0x8e, - 0xfd, 0x08, 0x82, 0xc8, 0x76, 0xcc, 0x20, 0xb2, 0x75, 0x8b, 0xa6, 0x7b, 0x35, 0x8c, 0x1e, 0xe1, - 0x64, 0x3f, 0x29, 0xc0, 0x31, 0xbd, 0x72, 0x85, 0x1c, 0xc5, 0xc7, 0xbe, 0x69, 0x44, 0xd0, 0x5e, - 0xb3, 0x3b, 0xde, 0x8a, 0xf0, 0x00, 0xe5, 0x45, 0x6b, 0x7f, 0x2c, 0x13, 0xad, 0x7d, 0xc3, 0x3e, - 0xe9, 0xbd, 0x43, 0xb6, 0xff, 0x8b, 0x03, 0x27, 0x32, 0x2d, 0x8e, 0x60, 0x81, 0x6d, 0x9b, 0x0b, - 0xec, 0x79, 0xeb, 0xa3, 0xee, 0xb1, 0xba, 0xbe, 0x55, 0xe8, 0x1a, 0x2d, 0x53, 0xe2, 0x3e, 0xe5, - 0x40, 0x91, 0x4a, 0xcb, 0x32, 0x9e, 0xeb, 0x23, 0x87, 0xb2, 0x02, 0x98, 0x5c, 0x2f, 0xb8, 0xb3, - 0xea, 0x1f, 0x83, 0x61, 0x4e, 0x7d, 0xea, 0x93, 0x0e, 0x40, 0x5a, 0xe9, 0x7e, 0x89, 0xc0, 0xee, - 0x77, 0x0a, 0x70, 0x2a, 0x77, 0x19, 0xa1, 0xcf, 0x28, 0x8b, 0x9c, 0x63, 0x3b, 0x5a, 0xd1, 0x20, - 0xa4, 0x1b, 0xe6, 0xc6, 0x0d, 0xc3, 0x9c, 0xb0, 0xc7, 0xdd, 0x2f, 0x05, 0x46, 0xb0, 0x69, 0x6d, - 0xb2, 0x7e, 0xec, 0xa4, 0x01, 0xb0, 0x2a, 0xaf, 0xd1, 0x5f, 0xc2, 0x4b, 0x3c, 0xee, 0x4f, 0xb4, - 0x1b, 0x0e, 0x72, 0xa0, 0x47, 0xc0, 0x2b, 0x6e, 0x9a, 0xbc, 0x02, 0xdb, 0xf7, 0x23, 0xf7, 0x60, - 0x16, 0xaf, 0x40, 0x9e, 0x63, 0xb9, 0xbf, 0xa4, 0x88, 0xc6, 0x75, 0xd8, 0x42, 0xdf, 0xd7, 0x61, - 0xc7, 0xa1, 0xf4, 0xa2, 0xaf, 0xb2, 0x69, 0xce, 0xcd, 0x7c, 0xf7, 0x47, 0xe7, 0x1e, 0xf8, 0xde, - 0x8f, 0xce, 0x3d, 0xf0, 0xc3, 0x1f, 0x9d, 0x7b, 0xe0, 0xe3, 0xb7, 0xcf, 0x39, 0xdf, 0xbd, 0x7d, - 0xce, 0xf9, 0xde, 0xed, 0x73, 0xce, 0x0f, 0x6f, 0x9f, 0x73, 0xfe, 0xfd, 0xed, 0x73, 0xce, 0xdf, - 0xf9, 0x0f, 0xe7, 0x1e, 0x78, 0x71, 0x44, 0x0e, 0xec, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x5c, - 0x27, 0xbb, 0xaf, 0x9f, 0xd7, 0x00, 0x00, + 0xd2, 0xad, 0xa9, 0x89, 0x79, 0xf4, 0x60, 0xee, 0x44, 0x4d, 0xc1, 0x88, 0xd5, 0xc1, 0x7c, 0x15, + 0xaf, 0x60, 0x0a, 0x47, 0x5f, 0xd2, 0xb8, 0x23, 0x6d, 0xd6, 0x11, 0x6e, 0x0d, 0x4b, 0x26, 0x7a, + 0x03, 0x71, 0x37, 0xff, 0x13, 0x05, 0x38, 0xdb, 0x05, 0xf7, 0x8b, 0x05, 0x78, 0x78, 0x5f, 0xa1, + 0x35, 0xb7, 0xe3, 0xce, 0x7d, 0xef, 0x38, 0x3d, 0xd6, 0x22, 0xd2, 0x0e, 0xaf, 0xe2, 0x15, 0xf1, + 0xbd, 0xd4, 0xb1, 0x86, 0x39, 0x18, 0xcb, 0x72, 0x2a, 0x3a, 0x6c, 0x93, 0xdd, 0xc5, 0x30, 0x6a, + 0x79, 0x89, 0xe0, 0x0e, 0x4a, 0x74, 0x58, 0x96, 0x05, 0x38, 0xad, 0xe3, 0xfe, 0xc0, 0x81, 0x6c, + 0x07, 0x90, 0x07, 0x13, 0x9d, 0x98, 0x44, 0xf4, 0x48, 0xad, 0x90, 0x6a, 0x44, 0xe4, 0xf2, 0x7c, + 0x6c, 0x86, 0x7b, 0xfb, 0xe9, 0x08, 0x67, 0xaa, 0x61, 0x44, 0x66, 0x76, 0x9e, 0x9e, 0xe1, 0x35, + 0x96, 0xc9, 0x6e, 0x85, 0x34, 0x09, 0xc5, 0x31, 0x87, 0x6e, 0xed, 0x4d, 0x4f, 0x5c, 0x35, 0x10, + 0xe0, 0x0c, 0x42, 0x4a, 0xa2, 0xed, 0xc5, 0xf1, 0x8d, 0x30, 0xaa, 0x09, 0x12, 0x85, 0x03, 0x93, + 0x58, 0x37, 0x10, 0xe0, 0x0c, 0x42, 0xf7, 0xfb, 0x54, 0x7d, 0xd4, 0xa5, 0x56, 0xf4, 0x0d, 0x2a, + 0xfb, 0x50, 0xc8, 0x5c, 0x33, 0xdc, 0x9c, 0x0f, 0x83, 0xc4, 0xf3, 0x03, 0x22, 0x83, 0x05, 0x36, + 0x2c, 0xc9, 0xc8, 0x06, 0xee, 0xd4, 0x86, 0xdf, 0x5d, 0x86, 0x73, 0xfa, 0x42, 0x65, 0x9c, 0xcd, + 0x66, 0xb8, 0x99, 0xf5, 0x02, 0xd2, 0x4a, 0x98, 0x95, 0xb8, 0x3f, 0x75, 0xe0, 0x4c, 0x0f, 0x61, + 0x1c, 0x7d, 0xc5, 0x81, 0xf1, 0xcd, 0x9f, 0x89, 0xb1, 0x99, 0xdd, 0x40, 0xef, 0x83, 0x09, 0x0a, + 0xa0, 0x27, 0x91, 0x58, 0x9b, 0x05, 0xd3, 0x43, 0x35, 0x67, 0x94, 0xe2, 0x4c, 0x6d, 0xf7, 0x37, + 0x0a, 0x90, 0x43, 0x05, 0x3d, 0x05, 0x23, 0x24, 0xa8, 0xb5, 0x43, 0x3f, 0x48, 0x04, 0x33, 0x52, + 0x5c, 0xef, 0xa2, 0x80, 0x63, 0x55, 0x43, 0xe8, 0x1f, 0x62, 0x62, 0x0a, 0x5d, 0xfa, 0x87, 0xe8, + 0x79, 0x5a, 0x07, 0xd5, 0x61, 0xd2, 0xe3, 0xfe, 0x15, 0xb6, 0xf6, 0xd8, 0x32, 0x1d, 0x38, 0xc8, + 0x32, 0x3d, 0xc9, 0xdc, 0x9f, 0x19, 0x14, 0xb8, 0x0b, 0x29, 0x7a, 0x37, 0x94, 0x3a, 0x31, 0xa9, + 0x2c, 0x2c, 0xcf, 0x47, 0xa4, 0xc6, 0xb5, 0x62, 0xcd, 0xef, 0x77, 0x35, 0x2d, 0xc2, 0x7a, 0x3d, + 0xf7, 0x9f, 0x39, 0x30, 0x3c, 0xe7, 0x55, 0xb7, 0xc3, 0xad, 0x2d, 0x3a, 0x15, 0xb5, 0x4e, 0x94, + 0x1a, 0xb6, 0xb4, 0xa9, 0x58, 0x10, 0x70, 0xac, 0x6a, 0xa0, 0x0d, 0x18, 0xe2, 0x1b, 0x5e, 0x6c, + 0xbb, 0x5f, 0xd4, 0xc6, 0xa3, 0xe2, 0x78, 0xd8, 0x72, 0xe8, 0x24, 0x7e, 0x73, 0x86, 0xc7, 0xf1, + 0xcc, 0x5c, 0x0e, 0x92, 0xb5, 0xa8, 0x92, 0x44, 0x7e, 0x50, 0x9f, 0x03, 0x7a, 0x5c, 0x2c, 0x32, + 0x1c, 0x58, 0xe0, 0xa2, 0xc3, 0x68, 0x79, 0x37, 0x25, 0x39, 0xc1, 0x7e, 0xd4, 0x30, 0x56, 0xd3, + 0x22, 0xac, 0xd7, 0x73, 0xff, 0xc8, 0x81, 0xd1, 0x39, 0x2f, 0xf6, 0xab, 0x7f, 0x81, 0x98, 0xcf, + 0x87, 0xa0, 0x38, 0xef, 0x55, 0x1b, 0x04, 0x5d, 0xcd, 0x2a, 0xbd, 0xa5, 0x0b, 0x4f, 0xe4, 0x91, + 0x51, 0x0a, 0xb0, 0x4e, 0x69, 0xbc, 0x97, 0x6a, 0xec, 0xbe, 0xed, 0xc0, 0xc4, 0x7c, 0xd3, 0x27, + 0x41, 0x32, 0x4f, 0xa2, 0x84, 0x4d, 0x5c, 0x1d, 0x26, 0xab, 0x0a, 0x72, 0x37, 0x53, 0xc7, 0x56, + 0xeb, 0x7c, 0x06, 0x05, 0xee, 0x42, 0x8a, 0x6a, 0x70, 0x8c, 0xc3, 0xd2, 0x5d, 0x71, 0xa0, 0xf9, + 0x63, 0xd6, 0xd1, 0x79, 0x13, 0x03, 0xce, 0xa2, 0x74, 0x7f, 0xe2, 0xc0, 0x99, 0xf9, 0x66, 0x27, + 0x4e, 0x48, 0x74, 0x5d, 0x70, 0x23, 0x29, 0xde, 0xa2, 0x8f, 0xc0, 0x48, 0x4b, 0x7a, 0x6c, 0x9d, + 0x3b, 0x2c, 0x60, 0xc6, 0xcf, 0x68, 0x6d, 0xda, 0x99, 0xb5, 0xcd, 0x97, 0x49, 0x35, 0x59, 0x25, + 0x89, 0x97, 0x86, 0x17, 0xa4, 0x30, 0xac, 0xb0, 0xa2, 0x36, 0x0c, 0xc6, 0x6d, 0x52, 0xb5, 0x17, + 0xdd, 0x25, 0xc7, 0x50, 0x69, 0x93, 0x6a, 0xca, 0xd7, 0x99, 0xaf, 0x91, 0x51, 0x72, 0xff, 0x97, + 0x03, 0x67, 0x7b, 0x8c, 0x77, 0xc5, 0x8f, 0x13, 0xf4, 0x52, 0xd7, 0x98, 0x67, 0xfa, 0x1b, 0x33, + 0x6d, 0xcd, 0x46, 0xac, 0x18, 0x82, 0x84, 0x68, 0xe3, 0xfd, 0x28, 0x14, 0xfd, 0x84, 0xb4, 0xa4, + 0x19, 0xda, 0x82, 0xc1, 0xa8, 0xc7, 0x58, 0xe6, 0xc6, 0x65, 0x8c, 0xdf, 0x65, 0x4a, 0x0f, 0x73, + 0xb2, 0xee, 0x36, 0x0c, 0xcd, 0x87, 0xcd, 0x4e, 0x2b, 0xe8, 0x2f, 0x52, 0x26, 0xd9, 0x6d, 0x93, + 0xec, 0x19, 0xc9, 0xc4, 0x7f, 0x56, 0x22, 0x0d, 0x47, 0x03, 0xf9, 0x86, 0x23, 0xf7, 0x9f, 0x3b, + 0x40, 0x77, 0x55, 0xcd, 0x17, 0x9e, 0x44, 0x8e, 0x8e, 0x13, 0x7c, 0x58, 0x47, 0x77, 0x7b, 0x6f, + 0x7a, 0x5c, 0x55, 0xd4, 0xf0, 0x7f, 0x08, 0x86, 0x62, 0xa6, 0x92, 0x8b, 0x3e, 0x2c, 0x4a, 0xf9, + 0x99, 0x2b, 0xea, 0xb7, 0xf7, 0xa6, 0xfb, 0x0a, 0xdb, 0x9c, 0x51, 0xb8, 0x85, 0xd3, 0x53, 0x60, + 0xa5, 0x02, 0x5f, 0x8b, 0xc4, 0xb1, 0x57, 0x97, 0x1a, 0x9e, 0x12, 0xf8, 0x56, 0x39, 0x18, 0xcb, + 0x72, 0xf7, 0xcb, 0x0e, 0x8c, 0xab, 0xc3, 0x8b, 0x8a, 0xef, 0xe8, 0x8a, 0x7e, 0xcc, 0xf1, 0x95, + 0xf2, 0x70, 0x0f, 0x8e, 0x23, 0x0e, 0xf2, 0xfd, 0x4f, 0xc1, 0x77, 0xc1, 0x58, 0x8d, 0xb4, 0x49, + 0x50, 0x23, 0x41, 0x95, 0xaa, 0xdf, 0x74, 0x85, 0x8c, 0xce, 0x4d, 0x52, 0x7d, 0x73, 0x41, 0x83, + 0x63, 0xa3, 0x96, 0xfb, 0x4d, 0x07, 0x1e, 0x54, 0xe8, 0x2a, 0x24, 0xc1, 0x24, 0x89, 0x76, 0x55, + 0x98, 0xe6, 0xc1, 0x4e, 0xab, 0xeb, 0x54, 0xfe, 0x4d, 0x22, 0x4e, 0xfc, 0xee, 0x8e, 0xab, 0x12, + 0x97, 0x96, 0x19, 0x12, 0x2c, 0xb1, 0xb9, 0xbf, 0x36, 0x00, 0x27, 0xf5, 0x4e, 0x2a, 0x06, 0xf3, + 0x09, 0x07, 0x40, 0xcd, 0x00, 0x3d, 0x90, 0x07, 0xec, 0xf8, 0xae, 0x8c, 0x2f, 0x95, 0xb2, 0x20, + 0x05, 0x8e, 0xb1, 0x46, 0x16, 0xbd, 0x00, 0x63, 0x3b, 0x74, 0x53, 0x90, 0x55, 0x2a, 0x2e, 0xc4, + 0xe5, 0x01, 0xd6, 0x8d, 0xe9, 0xbc, 0x8f, 0x79, 0x2d, 0xad, 0x97, 0x9a, 0x03, 0x34, 0x60, 0x8c, + 0x0d, 0x54, 0x54, 0xd3, 0x19, 0x8f, 0xf4, 0x4f, 0x22, 0x6c, 0xe2, 0x1f, 0xb4, 0x38, 0xc6, 0xec, + 0x57, 0x9f, 0x3b, 0x7e, 0x6b, 0x6f, 0x7a, 0xdc, 0x00, 0x61, 0xb3, 0x13, 0xee, 0x0b, 0xc0, 0xe6, + 0xc2, 0x0f, 0x3a, 0x64, 0x2d, 0x40, 0x8f, 0x4a, 0x1b, 0x1d, 0xf7, 0xab, 0x28, 0xce, 0xa1, 0xdb, + 0xe9, 0xa8, 0x2e, 0xbb, 0xe5, 0xf9, 0x4d, 0x16, 0xbe, 0x48, 0x6b, 0x29, 0x5d, 0x76, 0x91, 0x41, + 0xb1, 0x28, 0x75, 0x67, 0x60, 0x78, 0x9e, 0x8e, 0x9d, 0x44, 0x14, 0xaf, 0x1e, 0x75, 0x3c, 0x6e, + 0x44, 0x1d, 0xcb, 0xe8, 0xe2, 0x0d, 0x38, 0x35, 0x1f, 0x11, 0x2f, 0x21, 0x95, 0x67, 0xe6, 0x3a, + 0xd5, 0x6d, 0x92, 0xf0, 0xd0, 0xae, 0x18, 0xbd, 0x17, 0xc6, 0x43, 0x76, 0x64, 0xac, 0x84, 0xd5, + 0x6d, 0x3f, 0xa8, 0x0b, 0x93, 0xeb, 0x29, 0x81, 0x65, 0x7c, 0x4d, 0x2f, 0xc4, 0x66, 0x5d, 0xf7, + 0xdf, 0x17, 0x60, 0x6c, 0x3e, 0x0a, 0x03, 0xc9, 0x16, 0x8f, 0xe0, 0x28, 0x4b, 0x8c, 0xa3, 0xcc, + 0x82, 0xbb, 0x53, 0xef, 0x7f, 0xaf, 0xe3, 0x0c, 0xbd, 0xae, 0x58, 0xe4, 0x80, 0x2d, 0x15, 0xc4, + 0xa0, 0xcb, 0x70, 0xa7, 0x1f, 0xdb, 0x64, 0xa0, 0xee, 0x7f, 0x70, 0x60, 0x52, 0xaf, 0x7e, 0x04, + 0x27, 0x68, 0x6c, 0x9e, 0xa0, 0x57, 0xec, 0x8e, 0xb7, 0xc7, 0xb1, 0xf9, 0xf6, 0xb0, 0x39, 0x4e, + 0xe6, 0xeb, 0xfe, 0xaa, 0x03, 0x63, 0x37, 0x34, 0x80, 0x18, 0xac, 0x6d, 0x21, 0xe6, 0x1d, 0x92, + 0xcd, 0xe8, 0xd0, 0xdb, 0x99, 0xdf, 0xd8, 0xe8, 0x09, 0xe5, 0xfb, 0x71, 0xb5, 0x41, 0x6a, 0x9d, + 0xa6, 0x3c, 0xbe, 0xd5, 0x94, 0x56, 0x04, 0x1c, 0xab, 0x1a, 0xe8, 0x25, 0x38, 0x5e, 0x0d, 0x83, + 0x6a, 0x27, 0x8a, 0x48, 0x50, 0xdd, 0x5d, 0x67, 0x77, 0x24, 0xc4, 0x81, 0x38, 0x23, 0x9a, 0x1d, + 0x9f, 0xcf, 0x56, 0xb8, 0x9d, 0x07, 0xc4, 0xdd, 0x88, 0xb8, 0xb3, 0x20, 0xa6, 0x47, 0x96, 0x50, + 0xb8, 0x34, 0x67, 0x01, 0x03, 0x63, 0x59, 0x8e, 0xae, 0xc2, 0x99, 0x38, 0xf1, 0xa2, 0xc4, 0x0f, + 0xea, 0x0b, 0xc4, 0xab, 0x35, 0xfd, 0x80, 0xaa, 0x12, 0x61, 0x50, 0xe3, 0xae, 0xc4, 0x81, 0xb9, + 0xb3, 0xb7, 0xf6, 0xa6, 0xcf, 0x54, 0xf2, 0xab, 0xe0, 0x5e, 0x6d, 0xd1, 0x87, 0x60, 0x4a, 0xb8, + 0x23, 0xb6, 0x3a, 0xcd, 0xe7, 0xc2, 0xcd, 0xf8, 0x92, 0x1f, 0x53, 0x3d, 0x7e, 0xc5, 0x6f, 0xf9, + 0x09, 0x73, 0x18, 0x16, 0xe7, 0xce, 0xdd, 0xda, 0x9b, 0x9e, 0xaa, 0xf4, 0xac, 0x85, 0xf7, 0xc1, + 0x80, 0x30, 0x9c, 0xe6, 0xcc, 0xaf, 0x0b, 0xf7, 0x30, 0xc3, 0x3d, 0x75, 0x6b, 0x6f, 0xfa, 0xf4, + 0x62, 0x6e, 0x0d, 0xdc, 0xa3, 0x25, 0xfd, 0x82, 0x89, 0xdf, 0x22, 0xaf, 0x86, 0x01, 0x61, 0x81, + 0x2a, 0xda, 0x17, 0xdc, 0x10, 0x70, 0xac, 0x6a, 0xa0, 0x97, 0xd3, 0x95, 0x48, 0xb7, 0x8b, 0x08, + 0x38, 0x39, 0x38, 0x87, 0x63, 0xaa, 0xc9, 0x75, 0x0d, 0x13, 0x8b, 0xa4, 0x34, 0x70, 0xa3, 0x4f, + 0x3a, 0x30, 0x16, 0x27, 0xa1, 0xba, 0xd7, 0x20, 0x22, 0x4e, 0x2c, 0x2c, 0xfb, 0x8a, 0x86, 0x95, + 0x0b, 0x3e, 0x3a, 0x04, 0x1b, 0x54, 0xd1, 0x2f, 0xc0, 0xa8, 0x5c, 0xc0, 0x71, 0xb9, 0xc4, 0x64, + 0x25, 0xa6, 0xc6, 0xc9, 0xf5, 0x1d, 0xe3, 0xb4, 0x9c, 0x8a, 0xb2, 0x37, 0x1a, 0x24, 0x60, 0x31, + 0xb7, 0x9a, 0x28, 0x7b, 0xbd, 0x41, 0x02, 0xcc, 0x4a, 0xdc, 0x1f, 0x0f, 0x00, 0xea, 0x66, 0x7c, + 0x68, 0x19, 0x86, 0xbc, 0x6a, 0xe2, 0xef, 0xc8, 0x78, 0xc3, 0x47, 0xf3, 0x84, 0x02, 0x3e, 0x81, + 0x98, 0x6c, 0x11, 0xba, 0xee, 0x49, 0xca, 0x2d, 0x67, 0x59, 0x53, 0x2c, 0x50, 0xa0, 0x10, 0x8e, + 0x37, 0xbd, 0x38, 0x91, 0x3d, 0xac, 0xd1, 0x0f, 0x29, 0x8e, 0x8b, 0x9f, 0xef, 0xef, 0x53, 0xd1, + 0x16, 0x73, 0xa7, 0xe8, 0x7e, 0x5c, 0xc9, 0x22, 0xc2, 0xdd, 0xb8, 0xd1, 0xc7, 0x98, 0x74, 0xc5, + 0x45, 0x5f, 0x29, 0xd6, 0x2c, 0x5b, 0x91, 0x3c, 0x38, 0x4e, 0x43, 0xb2, 0x12, 0x64, 0xb0, 0x46, + 0x12, 0x9d, 0x87, 0x51, 0xb6, 0x6f, 0x48, 0x8d, 0xf0, 0xdd, 0x3f, 0x90, 0x0a, 0xc1, 0x15, 0x59, + 0x80, 0xd3, 0x3a, 0x9a, 0x94, 0xc1, 0x37, 0x7c, 0x0f, 0x29, 0x03, 0x3d, 0x0b, 0xc5, 0x76, 0xc3, + 0x8b, 0x65, 0x0c, 0xbb, 0x2b, 0xb9, 0xf6, 0x3a, 0x05, 0x32, 0xd6, 0xa4, 0x7d, 0x4b, 0x06, 0xc4, + 0xbc, 0x81, 0xfb, 0x2f, 0x00, 0x86, 0x17, 0x66, 0x97, 0x36, 0xbc, 0x78, 0xbb, 0x0f, 0x1d, 0x88, + 0x6e, 0x43, 0x21, 0xac, 0x66, 0x19, 0xa9, 0x14, 0x62, 0xb1, 0xaa, 0x81, 0x02, 0x18, 0xf2, 0x03, + 0xca, 0x79, 0xca, 0x13, 0xb6, 0xfc, 0x0c, 0x4a, 0x9f, 0x63, 0x86, 0xa0, 0xcb, 0x0c, 0x3b, 0x16, + 0x54, 0xd0, 0xeb, 0x30, 0xea, 0xc9, 0x2b, 0x44, 0xe2, 0xfc, 0x5f, 0xb6, 0x61, 0x40, 0x17, 0x28, + 0xf5, 0x10, 0x26, 0x01, 0xc2, 0x29, 0x41, 0xf4, 0x71, 0x07, 0x4a, 0x72, 0xe8, 0x98, 0x6c, 0x09, + 0xdf, 0xf6, 0xaa, 0xbd, 0x31, 0x63, 0xb2, 0xc5, 0xe3, 0x5b, 0x34, 0x00, 0xd6, 0x49, 0x76, 0xe9, + 0x4c, 0xc5, 0x7e, 0x74, 0x26, 0x74, 0x03, 0x46, 0x6f, 0xf8, 0x49, 0x83, 0x9d, 0xf0, 0xc2, 0xa7, + 0xb6, 0x78, 0xef, 0xbd, 0xa6, 0xe8, 0xd2, 0x19, 0xbb, 0x2e, 0x09, 0xe0, 0x94, 0x16, 0xdd, 0x0e, + 0xf4, 0x07, 0xbb, 0x82, 0xc5, 0xce, 0x86, 0x51, 0xb3, 0x01, 0x2b, 0xc0, 0x69, 0x1d, 0x3a, 0xc5, + 0x63, 0xf4, 0x57, 0x85, 0xbc, 0xd2, 0xa1, 0xac, 0x45, 0xc4, 0x2c, 0x5a, 0x58, 0x57, 0x12, 0x23, + 0x9f, 0xac, 0xeb, 0x1a, 0x0d, 0x6c, 0x50, 0x54, 0xac, 0x73, 0xb4, 0x17, 0xeb, 0x44, 0xaf, 0x73, + 0x1d, 0x8e, 0x2b, 0x13, 0xe2, 0x34, 0x58, 0xb1, 0xa3, 0xdf, 0x70, 0x9c, 0xfc, 0x5a, 0x43, 0xfa, + 0x1b, 0x6b, 0xf4, 0x28, 0xc7, 0x08, 0x83, 0x8b, 0x37, 0xfd, 0x44, 0x5c, 0xc6, 0x50, 0x1c, 0x63, + 0x8d, 0x41, 0xb1, 0x28, 0xe5, 0xb1, 0x1b, 0x74, 0x11, 0xc4, 0xe2, 0x14, 0xd0, 0x62, 0x37, 0x18, + 0x18, 0xcb, 0x72, 0xf4, 0x77, 0x1d, 0x28, 0x36, 0xc2, 0x70, 0x3b, 0x2e, 0x8f, 0xb3, 0xc5, 0x61, + 0x41, 0xa6, 0x16, 0x1c, 0x67, 0xe6, 0x12, 0x45, 0x6b, 0x5e, 0x2f, 0x2b, 0x32, 0xd8, 0xed, 0xbd, + 0xe9, 0x89, 0x15, 0x7f, 0x8b, 0x54, 0x77, 0xab, 0x4d, 0xc2, 0x20, 0x6f, 0xbe, 0xad, 0x41, 0x2e, + 0xee, 0x90, 0x20, 0xc1, 0xbc, 0x57, 0x53, 0x9f, 0x73, 0x00, 0x52, 0x44, 0x39, 0x4e, 0x52, 0x62, + 0x86, 0x15, 0x58, 0x50, 0xa8, 0x8d, 0xae, 0xe9, 0x5e, 0xd7, 0x7f, 0xe5, 0x40, 0x89, 0x0e, 0x4e, + 0xb2, 0xc0, 0xc7, 0x61, 0x28, 0xf1, 0xa2, 0x3a, 0x91, 0x8e, 0x02, 0xf5, 0x39, 0x36, 0x18, 0x14, + 0x8b, 0x52, 0x14, 0x40, 0x31, 0xf1, 0xe2, 0x6d, 0x29, 0xc6, 0x5f, 0xb6, 0x36, 0xc5, 0xa9, 0x04, + 0x4f, 0x7f, 0xc5, 0x98, 0x93, 0x41, 0x4f, 0xc0, 0x08, 0x3d, 0x3a, 0x16, 0xbd, 0x58, 0xc6, 0xee, + 0x8c, 0x51, 0x26, 0xbe, 0x28, 0x60, 0x58, 0x95, 0xba, 0xbf, 0x51, 0x80, 0xc1, 0x05, 0xae, 0xd0, + 0x0d, 0xc5, 0x61, 0x27, 0xaa, 0x12, 0x21, 0xd8, 0x5b, 0x58, 0xd3, 0x14, 0x6f, 0x85, 0xe1, 0xd4, + 0x54, 0x2a, 0xf6, 0x1b, 0x0b, 0x5a, 0xe8, 0x4b, 0x0e, 0x4c, 0x24, 0x91, 0x17, 0xc4, 0x5b, 0xcc, + 0x25, 0xe3, 0x87, 0x81, 0x98, 0x22, 0x0b, 0xab, 0x70, 0xc3, 0xc0, 0x5b, 0x49, 0x48, 0x3b, 0xf5, + 0x0c, 0x99, 0x65, 0x38, 0xd3, 0x07, 0xf7, 0x37, 0x1d, 0x80, 0xb4, 0xf7, 0xe8, 0xb3, 0x0e, 0x8c, + 0x7b, 0x7a, 0xcc, 0xa8, 0x98, 0xa3, 0x35, 0x7b, 0xfe, 0x5b, 0x86, 0x96, 0xdb, 0x32, 0x0c, 0x10, + 0x36, 0x09, 0xbb, 0xef, 0x86, 0x22, 0xdb, 0x1d, 0x4c, 0xe9, 0x11, 0xb6, 0xef, 0xac, 0xb1, 0x4b, + 0xda, 0xc4, 0xb1, 0xaa, 0xe1, 0xbe, 0x04, 0x13, 0x17, 0x6f, 0x92, 0x6a, 0x27, 0x09, 0x23, 0x6e, + 0xf9, 0xef, 0x71, 0x47, 0xc8, 0xb9, 0xab, 0x3b, 0x42, 0xdf, 0x71, 0xa0, 0xa4, 0x05, 0x10, 0xd2, + 0x93, 0xba, 0x3e, 0x5f, 0xe1, 0x06, 0x0e, 0x31, 0x55, 0xcb, 0x56, 0x42, 0x14, 0x39, 0xca, 0xf4, + 0x18, 0x51, 0x20, 0x9c, 0x12, 0xbc, 0x43, 0x80, 0x9f, 0xfb, 0x07, 0x0e, 0x9c, 0xca, 0x8d, 0x76, + 0xbc, 0xcf, 0xdd, 0x36, 0x9c, 0xec, 0x85, 0x3e, 0x9c, 0xec, 0xbf, 0xe3, 0x40, 0x8a, 0x89, 0xb2, + 0xa2, 0xcd, 0xb4, 0xe7, 0x1a, 0x2b, 0x12, 0x94, 0x44, 0x29, 0x7a, 0x1d, 0xce, 0x98, 0x5f, 0xf0, + 0x2e, 0xfd, 0x2d, 0x5c, 0x39, 0xcd, 0xc7, 0x84, 0x7b, 0x91, 0x70, 0xbf, 0xe6, 0x40, 0x71, 0xc9, + 0xeb, 0xd4, 0x49, 0x5f, 0xe6, 0x32, 0xca, 0xc7, 0x22, 0xe2, 0x35, 0x13, 0xa9, 0x3a, 0x08, 0x3e, + 0x86, 0x05, 0x0c, 0xab, 0x52, 0x34, 0x0b, 0xa3, 0x61, 0x9b, 0x18, 0x3e, 0xc2, 0x47, 0xe5, 0xec, + 0xad, 0xc9, 0x02, 0x7a, 0xec, 0x30, 0xea, 0x0a, 0x82, 0xd3, 0x56, 0xee, 0x0f, 0x8a, 0x50, 0xd2, + 0xee, 0xc5, 0x50, 0x59, 0x20, 0x22, 0xed, 0x30, 0x2b, 0x2f, 0xd3, 0x05, 0x83, 0x59, 0x09, 0xdd, + 0x83, 0x11, 0xd9, 0xf1, 0x63, 0xce, 0xb6, 0x8c, 0x3d, 0x88, 0x05, 0x1c, 0xab, 0x1a, 0x68, 0x1a, + 0x8a, 0x35, 0xd2, 0x4e, 0x1a, 0xac, 0x7b, 0x83, 0x3c, 0x38, 0x70, 0x81, 0x02, 0x30, 0x87, 0xd3, + 0x0a, 0x5b, 0x24, 0xa9, 0x36, 0x98, 0x65, 0x58, 0x44, 0x0f, 0x2e, 0x52, 0x00, 0xe6, 0xf0, 0x1c, + 0x2f, 0x66, 0xf1, 0xf0, 0xbd, 0x98, 0x43, 0x96, 0xbd, 0x98, 0xa8, 0x0d, 0x27, 0xe2, 0xb8, 0xb1, + 0x1e, 0xf9, 0x3b, 0x5e, 0x42, 0xd2, 0xd5, 0x37, 0x7c, 0x10, 0x3a, 0x67, 0xd8, 0x4d, 0xf5, 0xca, + 0xa5, 0x2c, 0x16, 0x9c, 0x87, 0x1a, 0x55, 0xe0, 0x94, 0x1f, 0xc4, 0xa4, 0xda, 0x89, 0xc8, 0xe5, + 0x7a, 0x10, 0x46, 0xe4, 0x52, 0x18, 0x53, 0x74, 0xe2, 0x9e, 0xad, 0x8a, 0xa7, 0xbd, 0x9c, 0x57, + 0x09, 0xe7, 0xb7, 0x45, 0x4b, 0x70, 0xbc, 0xe6, 0xc7, 0xde, 0x66, 0x93, 0x54, 0x3a, 0x9b, 0xad, + 0x90, 0xab, 0xe6, 0xa3, 0x0c, 0xe1, 0x83, 0xd2, 0x8e, 0xb4, 0x90, 0xad, 0x80, 0xbb, 0xdb, 0xa0, + 0x67, 0x61, 0x2c, 0xf6, 0x83, 0x7a, 0x93, 0xcc, 0x45, 0x5e, 0x50, 0x6d, 0x88, 0x0b, 0xba, 0xca, + 0xde, 0x5e, 0xd1, 0xca, 0xb0, 0x51, 0x93, 0xed, 0x79, 0xde, 0x26, 0x23, 0x0d, 0x8a, 0xda, 0xa2, + 0xd4, 0xfd, 0xa1, 0x03, 0x63, 0x7a, 0x2c, 0x3b, 0x95, 0xb4, 0xa1, 0xb1, 0xb0, 0x58, 0xe1, 0x67, + 0x81, 0xbd, 0x13, 0xff, 0x92, 0xc2, 0x99, 0x2a, 0xcb, 0x29, 0x0c, 0x6b, 0x34, 0xfb, 0xb8, 0x99, + 0xfe, 0x28, 0x14, 0xb7, 0x42, 0x2a, 0x90, 0x0c, 0x98, 0x86, 0xfa, 0x45, 0x0a, 0xc4, 0xbc, 0xcc, + 0xfd, 0x6f, 0x0e, 0x9c, 0xce, 0x0f, 0xd3, 0xff, 0x59, 0x18, 0xe4, 0x05, 0x00, 0x3a, 0x14, 0x83, + 0xa9, 0x6b, 0xb9, 0x29, 0x64, 0x09, 0xd6, 0x6a, 0xf5, 0x37, 0xec, 0x7f, 0x59, 0x00, 0x8d, 0x26, + 0xfa, 0xbc, 0x03, 0xe3, 0x94, 0xec, 0x72, 0xb4, 0x69, 0x8c, 0x76, 0xcd, 0xce, 0x68, 0x15, 0xda, + 0xd4, 0x1f, 0x61, 0x80, 0xb1, 0x49, 0x1c, 0xfd, 0x02, 0x8c, 0x7a, 0xb5, 0x5a, 0x44, 0xe2, 0x58, + 0x79, 0xf6, 0x98, 0xb5, 0x6a, 0x56, 0x02, 0x71, 0x5a, 0x4e, 0x99, 0x68, 0xa3, 0xb6, 0x15, 0x53, + 0xbe, 0x24, 0x18, 0xb7, 0x62, 0xa2, 0x94, 0x08, 0x85, 0x63, 0x55, 0x03, 0x5d, 0x83, 0xd3, 0x35, + 0x2f, 0xf1, 0xb8, 0xfc, 0x46, 0xa2, 0xf5, 0x28, 0x4c, 0x48, 0x95, 0x31, 0x7d, 0x1e, 0x81, 0x7a, + 0x4e, 0xb4, 0x3d, 0xbd, 0x90, 0x5b, 0x0b, 0xf7, 0x68, 0xed, 0xfe, 0xea, 0x20, 0x98, 0x63, 0x42, + 0x35, 0x38, 0xb6, 0x1d, 0x6d, 0xce, 0xb3, 0x80, 0x8b, 0xbb, 0x09, 0x7c, 0x60, 0x01, 0x09, 0xcb, + 0x26, 0x06, 0x9c, 0x45, 0x29, 0xa8, 0x2c, 0x93, 0xdd, 0xc4, 0xdb, 0xbc, 0xeb, 0xb0, 0x87, 0x65, + 0x13, 0x03, 0xce, 0xa2, 0x44, 0xef, 0x86, 0xd2, 0x76, 0xb4, 0x29, 0x59, 0x7f, 0x36, 0x86, 0x66, + 0x39, 0x2d, 0xc2, 0x7a, 0x3d, 0xfa, 0x69, 0xb6, 0xa3, 0x4d, 0x7a, 0xda, 0xca, 0x0c, 0x10, 0xea, + 0xd3, 0x2c, 0x0b, 0x38, 0x56, 0x35, 0x50, 0x1b, 0xd0, 0xb6, 0x9c, 0x3d, 0x15, 0x5e, 0x22, 0x4e, + 0xa8, 0xfe, 0xa3, 0x53, 0x58, 0x5c, 0xff, 0x72, 0x17, 0x1e, 0x9c, 0x83, 0x1b, 0xbd, 0x00, 0x67, + 0xb6, 0xa3, 0x4d, 0x21, 0x84, 0xac, 0x47, 0x7e, 0x50, 0xf5, 0xdb, 0x46, 0xb6, 0x87, 0x69, 0xd1, + 0xdd, 0x33, 0xcb, 0xf9, 0xd5, 0x70, 0xaf, 0xf6, 0xee, 0xef, 0x0e, 0x02, 0xbb, 0xa7, 0x4a, 0x79, + 0x6c, 0x8b, 0x24, 0x8d, 0xb0, 0x96, 0x95, 0xab, 0x56, 0x19, 0x14, 0x8b, 0x52, 0x19, 0xbd, 0x5a, + 0xe8, 0x11, 0xbd, 0x7a, 0x03, 0x86, 0x1b, 0xc4, 0xab, 0x91, 0x48, 0x5a, 0x26, 0x57, 0xec, 0xdc, + 0xac, 0xbd, 0xc4, 0x90, 0xa6, 0xea, 0x3d, 0xff, 0x1d, 0x63, 0x49, 0x0d, 0xbd, 0x07, 0x26, 0xa8, + 0x80, 0x14, 0x76, 0x12, 0xe9, 0x5c, 0xe0, 0x96, 0x49, 0x76, 0x52, 0x6f, 0x18, 0x25, 0x38, 0x53, + 0x13, 0x2d, 0xc0, 0xa4, 0x70, 0x04, 0x28, 0x8b, 0xa7, 0x98, 0x58, 0x95, 0x86, 0xa3, 0x92, 0x29, + 0xc7, 0x5d, 0x2d, 0x58, 0xf4, 0x61, 0x58, 0xe3, 0xbe, 0x60, 0x3d, 0xfa, 0x30, 0xac, 0xed, 0x62, + 0x56, 0x82, 0x5e, 0x85, 0x11, 0xfa, 0x77, 0x31, 0x0a, 0x5b, 0xc2, 0xe6, 0xb3, 0x6e, 0x67, 0x76, + 0x28, 0x0d, 0xa1, 0x81, 0x32, 0xc1, 0x71, 0x4e, 0x50, 0xc1, 0x8a, 0x1e, 0xd5, 0x83, 0xe4, 0xf9, + 0x5e, 0xd9, 0xf6, 0xdb, 0xd7, 0x48, 0xe4, 0x6f, 0xed, 0x32, 0x61, 0x64, 0x24, 0xd5, 0x83, 0x2e, + 0x77, 0xd5, 0xc0, 0x39, 0xad, 0xdc, 0xcf, 0x17, 0x60, 0x4c, 0xbf, 0xee, 0x7c, 0xa7, 0x90, 0xe6, + 0x38, 0x5d, 0x14, 0x5c, 0xeb, 0xbd, 0x64, 0x61, 0xd8, 0x77, 0x5a, 0x10, 0x0d, 0x18, 0xf4, 0x3a, + 0x42, 0x0a, 0xb5, 0x62, 0x5c, 0x63, 0x23, 0xee, 0x24, 0x0d, 0x7e, 0x2f, 0x8e, 0x05, 0x1b, 0x33, + 0x0a, 0xee, 0xa7, 0x06, 0x60, 0x44, 0x16, 0xa2, 0x4f, 0x3a, 0x00, 0x69, 0xd0, 0x97, 0x60, 0xa5, + 0xeb, 0x36, 0x22, 0x82, 0xf4, 0x78, 0x35, 0xcd, 0x46, 0xaf, 0xe0, 0x58, 0xa3, 0x8b, 0x12, 0x18, + 0x0a, 0x69, 0xe7, 0x2e, 0xd8, 0xbb, 0xb2, 0xbf, 0x46, 0x09, 0x5f, 0x60, 0xd4, 0x53, 0x73, 0x1c, + 0x83, 0x61, 0x41, 0x8b, 0x6a, 0x96, 0x9b, 0x32, 0x16, 0xd1, 0x9e, 0xe9, 0x5a, 0x85, 0x37, 0xa6, + 0x8a, 0xa2, 0x02, 0xe1, 0x94, 0xa0, 0xfb, 0x34, 0x4c, 0x98, 0x9b, 0x81, 0x6a, 0x1a, 0x9b, 0xbb, + 0x09, 0xe1, 0x76, 0x8c, 0x31, 0xae, 0x69, 0xcc, 0x51, 0x00, 0xe6, 0x70, 0xf7, 0xfb, 0x0e, 0x40, + 0xca, 0x5e, 0xfa, 0x70, 0x1d, 0x3c, 0xaa, 0x1b, 0xe1, 0x7a, 0xa9, 0x73, 0x1f, 0x83, 0x51, 0xf6, + 0x0f, 0xdb, 0xe8, 0x03, 0xb6, 0x22, 0x07, 0xd2, 0x7e, 0x8a, 0xad, 0xce, 0x64, 0x8d, 0x6b, 0x92, + 0x10, 0x4e, 0x69, 0xba, 0x21, 0x4c, 0x66, 0x6b, 0xa3, 0x0f, 0xc2, 0x58, 0x2c, 0x8f, 0xd5, 0xf4, + 0xf2, 0x5e, 0x9f, 0xc7, 0x2f, 0xf7, 0xdb, 0x69, 0xcd, 0xb1, 0x81, 0xcc, 0x5d, 0x83, 0x21, 0xab, + 0x53, 0xe8, 0x7e, 0xdb, 0x81, 0x51, 0xe6, 0x3a, 0xad, 0x47, 0x5e, 0x2b, 0x6d, 0x32, 0xb0, 0xcf, + 0xac, 0xc7, 0x30, 0xcc, 0x75, 0x7f, 0x19, 0x72, 0x64, 0x81, 0xcb, 0xf0, 0x4c, 0x7b, 0x29, 0x97, + 0xe1, 0x46, 0x86, 0x18, 0x4b, 0x4a, 0xee, 0xa7, 0x0b, 0x30, 0x74, 0x39, 0x68, 0x77, 0xfe, 0xd2, + 0x67, 0x7b, 0x5b, 0x85, 0xc1, 0xcb, 0x09, 0x69, 0x99, 0x49, 0x09, 0xc7, 0xe6, 0x1e, 0xd3, 0x13, + 0x12, 0x96, 0xcd, 0x84, 0x84, 0xd8, 0xbb, 0x21, 0x23, 0xf2, 0x84, 0xed, 0x39, 0xbd, 0xc0, 0xf8, + 0x14, 0x8c, 0xae, 0x78, 0x9b, 0xa4, 0xb9, 0x4c, 0x76, 0xd9, 0x75, 0x43, 0x1e, 0x1d, 0xe2, 0xa4, + 0x06, 0x03, 0x23, 0x92, 0x63, 0x01, 0x26, 0x58, 0x6d, 0xb5, 0x19, 0xa8, 0x46, 0x42, 0xd2, 0x8c, + 0x4e, 0x8e, 0xa9, 0x91, 0x68, 0xd9, 0x9c, 0xb4, 0x5a, 0xee, 0x0c, 0x94, 0x52, 0x2c, 0x7d, 0x50, + 0xfd, 0x69, 0x01, 0xc6, 0x0d, 0x13, 0xba, 0xe1, 0x58, 0x74, 0xee, 0xe8, 0x58, 0x34, 0x1c, 0x7d, + 0x85, 0xfb, 0xed, 0xe8, 0x1b, 0x38, 0x7a, 0x47, 0x9f, 0xf9, 0x91, 0x06, 0xfb, 0xfa, 0x48, 0x4d, + 0x18, 0x5c, 0xf1, 0x83, 0xed, 0xfe, 0xf8, 0x4c, 0x5c, 0x0d, 0xdb, 0x5d, 0x7c, 0xa6, 0x42, 0x81, + 0x98, 0x97, 0x49, 0xc9, 0x65, 0x20, 0x5f, 0x72, 0x71, 0x3f, 0xe9, 0xc0, 0xd8, 0xaa, 0x17, 0xf8, + 0x5b, 0x24, 0x4e, 0xd8, 0xba, 0x4a, 0x0e, 0xf5, 0xda, 0xd9, 0x58, 0x8f, 0x04, 0x0a, 0x6f, 0x3a, + 0x70, 0x7c, 0x95, 0xb4, 0x42, 0xff, 0x55, 0x2f, 0x0d, 0x78, 0xa5, 0x7d, 0x6f, 0xf8, 0x89, 0x88, + 0xef, 0x53, 0x7d, 0xbf, 0xe4, 0x27, 0x98, 0xc2, 0xef, 0x60, 0x1f, 0x66, 0x17, 0x3a, 0xa8, 0x82, + 0xa6, 0x5d, 0x85, 0x4c, 0x43, 0x59, 0x65, 0x01, 0x4e, 0xeb, 0xb8, 0xbf, 0xe7, 0xc0, 0x30, 0xef, + 0x84, 0x8a, 0x11, 0x76, 0x7a, 0xe0, 0x6e, 0x40, 0x91, 0xb5, 0x13, 0xab, 0x7a, 0xc9, 0x82, 0xf8, + 0x43, 0xd1, 0xf1, 0x3d, 0xc8, 0xfe, 0xc5, 0x9c, 0x00, 0x53, 0x5b, 0xbc, 0x9b, 0xb3, 0x2a, 0xd6, + 0x37, 0x55, 0x5b, 0x18, 0x14, 0x8b, 0x52, 0xf7, 0xeb, 0x03, 0x30, 0xa2, 0xf2, 0x86, 0xb1, 0xac, + 0x0e, 0x41, 0x10, 0x26, 0x1e, 0x8f, 0xa1, 0xe0, 0xbc, 0xfa, 0x83, 0xf6, 0xf2, 0x96, 0xcd, 0xcc, + 0xa6, 0xd8, 0xb9, 0x5f, 0x50, 0x29, 0xa1, 0x5a, 0x09, 0xd6, 0x3b, 0x81, 0x3e, 0x0a, 0x43, 0x4d, + 0xca, 0x7d, 0x24, 0xeb, 0xbe, 0x66, 0xb1, 0x3b, 0x8c, 0xad, 0x89, 0x9e, 0xa8, 0x19, 0xe2, 0x40, + 0x2c, 0xa8, 0x4e, 0xbd, 0x0f, 0x26, 0xb3, 0xbd, 0xbe, 0xd3, 0x4d, 0xcd, 0x51, 0xfd, 0x9e, 0xe7, + 0x5f, 0x15, 0xdc, 0xf3, 0xe0, 0x4d, 0xdd, 0xe7, 0xa1, 0xb4, 0x4a, 0x92, 0xc8, 0xaf, 0x32, 0x04, + 0x77, 0x5a, 0x5c, 0x7d, 0xc9, 0x0f, 0x9f, 0x61, 0x8b, 0x95, 0xe2, 0x8c, 0xd1, 0xeb, 0x00, 0xed, + 0x28, 0xa4, 0xfa, 0x2b, 0xe9, 0xc8, 0x8f, 0x6d, 0x41, 0x1e, 0x5e, 0x57, 0x38, 0xb9, 0x2b, 0x3b, + 0xfd, 0x8d, 0x35, 0x7a, 0xee, 0x8b, 0x50, 0x5c, 0xed, 0x24, 0xe4, 0x66, 0x1f, 0x1c, 0xeb, 0xa0, + 0xa9, 0x0b, 0xdc, 0x0f, 0xc2, 0x18, 0xc3, 0x7d, 0x29, 0x6c, 0xd2, 0x63, 0x95, 0x4e, 0x4d, 0x8b, + 0xfe, 0xce, 0x3a, 0x1b, 0x58, 0x25, 0xcc, 0xcb, 0xe8, 0x96, 0x69, 0x84, 0xcd, 0x9a, 0xba, 0xc6, + 0xa5, 0x16, 0xc4, 0x25, 0x06, 0xc5, 0xa2, 0xd4, 0xfd, 0x44, 0x01, 0x4a, 0xac, 0xa1, 0x60, 0x37, + 0xbb, 0x30, 0xdc, 0xe0, 0x74, 0xc4, 0x1c, 0x5a, 0x08, 0x0e, 0xd3, 0x7b, 0xaf, 0xe9, 0x72, 0x1c, + 0x80, 0x25, 0x3d, 0x4a, 0xfa, 0x86, 0xe7, 0x27, 0x94, 0x74, 0xe1, 0x70, 0x49, 0x5f, 0xe7, 0x64, + 0xb0, 0xa4, 0xe7, 0xfe, 0x32, 0xb0, 0xeb, 0xd1, 0x8b, 0x4d, 0xaf, 0xce, 0x67, 0x2e, 0xdc, 0x26, + 0x35, 0xc1, 0x73, 0xb5, 0x99, 0xa3, 0x50, 0x2c, 0x4a, 0xf9, 0x95, 0xd3, 0x24, 0xf2, 0x55, 0x58, + 0xb5, 0x76, 0xe5, 0x94, 0x81, 0x65, 0x10, 0x7d, 0xcd, 0xfd, 0x72, 0x01, 0x80, 0x65, 0x99, 0xe3, + 0xb7, 0x9a, 0x7f, 0x51, 0x46, 0x40, 0x99, 0x0e, 0x4a, 0x15, 0x01, 0xc5, 0xee, 0x6d, 0xeb, 0x91, + 0x4f, 0xfa, 0x6d, 0x87, 0xc2, 0xfe, 0xb7, 0x1d, 0x50, 0x1b, 0x86, 0xc3, 0x4e, 0x42, 0x65, 0x55, + 0x71, 0xd8, 0x5b, 0xf0, 0xcf, 0xaf, 0x71, 0x84, 0xfc, 0x8a, 0x80, 0xf8, 0x81, 0x25, 0x19, 0xf4, + 0x2c, 0x8c, 0xb4, 0xa3, 0xb0, 0x4e, 0xcf, 0x6e, 0x71, 0xbc, 0x3f, 0x24, 0xe5, 0xa1, 0x75, 0x01, + 0xbf, 0xad, 0xfd, 0x8f, 0x55, 0x6d, 0xf7, 0x8f, 0x27, 0xf9, 0xbc, 0x88, 0xb5, 0x37, 0x05, 0x05, + 0x5f, 0x5a, 0xa6, 0x40, 0xa0, 0x28, 0x5c, 0x5e, 0xc0, 0x05, 0xbf, 0xa6, 0xf6, 0x55, 0xa1, 0xe7, + 0xbe, 0x7a, 0x37, 0x94, 0x6a, 0x7e, 0xdc, 0x6e, 0x7a, 0xbb, 0x57, 0x72, 0xcc, 0x82, 0x0b, 0x69, + 0x11, 0xd6, 0xeb, 0xa1, 0xa7, 0xc4, 0xdd, 0x96, 0x41, 0xc3, 0x14, 0x24, 0xef, 0xb6, 0xa4, 0xb7, + 0xe6, 0xf9, 0xb5, 0x96, 0x6c, 0x76, 0x81, 0x62, 0xdf, 0xd9, 0x05, 0xb2, 0x92, 0xd8, 0xd0, 0xd1, + 0x4b, 0x62, 0xef, 0x85, 0x71, 0xf9, 0x93, 0x89, 0x47, 0xe5, 0x93, 0xac, 0xf7, 0xca, 0x0c, 0xbe, + 0xa1, 0x17, 0x62, 0xb3, 0x6e, 0xba, 0x68, 0x87, 0xfb, 0x5d, 0xb4, 0x17, 0x00, 0x36, 0xc3, 0x4e, + 0x50, 0xf3, 0xa2, 0xdd, 0xcb, 0x0b, 0x22, 0x12, 0x56, 0x09, 0x7e, 0x73, 0xaa, 0x04, 0x6b, 0xb5, + 0xf4, 0x85, 0x3e, 0x7a, 0x87, 0x85, 0xfe, 0x41, 0x18, 0x65, 0x51, 0xc3, 0xa4, 0x36, 0x9b, 0x88, + 0xd0, 0xa5, 0x83, 0x84, 0x62, 0xa6, 0xc1, 0x8c, 0x12, 0x09, 0x4e, 0xf1, 0xa1, 0x0f, 0x01, 0x6c, + 0xf9, 0x81, 0x1f, 0x37, 0x18, 0xf6, 0xd2, 0x81, 0xb1, 0xab, 0x71, 0x2e, 0x2a, 0x2c, 0x58, 0xc3, + 0x88, 0x5e, 0x82, 0xe3, 0x24, 0x4e, 0xfc, 0x96, 0x97, 0x90, 0x9a, 0xba, 0x0d, 0x5a, 0x66, 0xb6, + 0x4c, 0x15, 0xb7, 0x7d, 0x31, 0x5b, 0xe1, 0x76, 0x1e, 0x10, 0x77, 0x23, 0x32, 0x76, 0xe4, 0xd4, + 0x41, 0x76, 0x24, 0xfa, 0x9f, 0x0e, 0x1c, 0x8f, 0x08, 0x8f, 0x67, 0x89, 0x55, 0xc7, 0x4e, 0x31, + 0x76, 0x5c, 0xb5, 0x91, 0xc0, 0x5d, 0x65, 0x6a, 0xc1, 0x59, 0x2a, 0x5c, 0x70, 0x21, 0x72, 0xf4, + 0x5d, 0xe5, 0xb7, 0xf3, 0x80, 0x6f, 0xbe, 0x3d, 0x3d, 0xdd, 0xfd, 0x90, 0x80, 0x42, 0x4e, 0x77, + 0xde, 0xdf, 0x7c, 0x7b, 0x7a, 0x52, 0xfe, 0x4e, 0x27, 0xad, 0x6b, 0x90, 0xf4, 0x58, 0x6d, 0x87, + 0xb5, 0xcb, 0xeb, 0x22, 0xc6, 0x4c, 0x1d, 0xab, 0xeb, 0x14, 0x88, 0x79, 0x19, 0x7a, 0x02, 0x46, + 0x6a, 0x1e, 0x69, 0x85, 0x81, 0x4a, 0xc5, 0xcb, 0xa4, 0xf9, 0x05, 0x01, 0xc3, 0xaa, 0x94, 0xea, + 0x10, 0x81, 0x38, 0x52, 0xca, 0x67, 0x6d, 0xe9, 0x10, 0xf2, 0x90, 0xe2, 0x54, 0xe5, 0x2f, 0xac, + 0x28, 0xa1, 0x26, 0x0c, 0xf9, 0xcc, 0x50, 0x21, 0xc2, 0x58, 0x2d, 0x58, 0x47, 0xb8, 0xe1, 0x43, + 0x06, 0xb1, 0x32, 0xd6, 0x2f, 0x68, 0xe8, 0x67, 0xcd, 0xb1, 0xa3, 0x39, 0x6b, 0x9e, 0x80, 0x91, + 0x6a, 0xc3, 0x6f, 0xd6, 0x22, 0x12, 0x94, 0x27, 0x99, 0xc6, 0xce, 0x66, 0x62, 0x5e, 0xc0, 0xb0, + 0x2a, 0x45, 0x7f, 0x05, 0xc6, 0xc3, 0x4e, 0xc2, 0x58, 0x0b, 0x9d, 0xa7, 0xb8, 0x7c, 0x9c, 0x55, + 0x67, 0x41, 0x49, 0x6b, 0x7a, 0x01, 0x36, 0xeb, 0x51, 0x16, 0xdf, 0x08, 0x63, 0x96, 0x54, 0x88, + 0xb1, 0xf8, 0xd3, 0x26, 0x8b, 0xbf, 0xa4, 0x95, 0x61, 0xa3, 0x26, 0xfa, 0xaa, 0x03, 0xc7, 0x5b, + 0x59, 0x05, 0xae, 0x7c, 0x86, 0xcd, 0x4c, 0xc5, 0x86, 0xa0, 0x9f, 0x41, 0xcd, 0xc3, 0xc9, 0xbb, + 0xc0, 0xb8, 0xbb, 0x13, 0x2c, 0xbd, 0x57, 0xbc, 0x1b, 0x54, 0x1b, 0x51, 0x18, 0x98, 0xdd, 0x7b, + 0xd0, 0xd6, 0xa5, 0x36, 0xb6, 0xb7, 0xf3, 0x48, 0xcc, 0x3d, 0x78, 0x6b, 0x6f, 0xfa, 0x54, 0x6e, + 0x11, 0xce, 0xef, 0xd4, 0xd4, 0x02, 0x9c, 0xce, 0xe7, 0x0f, 0x77, 0xd2, 0x38, 0x06, 0x74, 0x8d, + 0x63, 0x11, 0x1e, 0xec, 0xd9, 0x29, 0x7a, 0xd2, 0x48, 0x69, 0xd3, 0x31, 0x4f, 0x9a, 0x2e, 0xe9, + 0x70, 0x02, 0xc6, 0xf4, 0x97, 0x27, 0xdc, 0xff, 0x33, 0x00, 0x90, 0xda, 0xc9, 0x91, 0x07, 0x13, + 0xdc, 0x26, 0x7f, 0x79, 0xe1, 0xae, 0xaf, 0xe3, 0xcf, 0x1b, 0x08, 0x70, 0x06, 0x21, 0x6a, 0x01, + 0xe2, 0x10, 0xfe, 0xfb, 0x6e, 0x7c, 0xab, 0xcc, 0x15, 0x39, 0xdf, 0x85, 0x04, 0xe7, 0x20, 0xa6, + 0x23, 0x4a, 0xc2, 0x6d, 0x12, 0x5c, 0xc5, 0x2b, 0x77, 0x93, 0xd3, 0x81, 0x7b, 0xe3, 0x0c, 0x04, + 0x38, 0x83, 0x10, 0xb9, 0x30, 0xc4, 0x6c, 0x33, 0x32, 0xf0, 0x9b, 0xb1, 0x17, 0x26, 0x69, 0xc4, + 0x58, 0x94, 0xa0, 0x2f, 0x3b, 0x30, 0x21, 0x53, 0x53, 0x30, 0x6b, 0xa8, 0x0c, 0xf9, 0xbe, 0x6a, + 0xcb, 0xcf, 0x71, 0x51, 0xc7, 0x9e, 0x06, 0x54, 0x1a, 0xe0, 0x18, 0x67, 0x3a, 0xe1, 0xbe, 0x00, + 0x27, 0x72, 0x9a, 0x5b, 0xd1, 0x68, 0xbf, 0xe3, 0x40, 0x49, 0xcb, 0x98, 0x88, 0x5e, 0x87, 0xd1, + 0xb0, 0x62, 0x3d, 0x8a, 0x6f, 0xad, 0xd2, 0x15, 0xc5, 0xa7, 0x40, 0x38, 0x25, 0xd8, 0x4f, 0xf0, + 0x61, 0x6e, 0x7a, 0xc7, 0xfb, 0xdc, 0xed, 0x03, 0x07, 0x1f, 0xfe, 0x6a, 0x11, 0x52, 0x4c, 0x07, + 0x4c, 0x99, 0x92, 0x86, 0x2a, 0x16, 0xf6, 0x0d, 0x55, 0xac, 0xc1, 0x31, 0x8f, 0xf9, 0x92, 0xef, + 0x32, 0x51, 0x0a, 0x4f, 0x98, 0x6b, 0x62, 0xc0, 0x59, 0x94, 0x94, 0x4a, 0x9c, 0x36, 0x65, 0x54, + 0x06, 0x0f, 0x4c, 0xa5, 0x62, 0x62, 0xc0, 0x59, 0x94, 0xe8, 0x25, 0x28, 0x57, 0xd9, 0xc5, 0x5f, + 0x3e, 0xc6, 0xcb, 0x5b, 0x57, 0xc2, 0x64, 0x3d, 0x22, 0x31, 0x09, 0x12, 0x91, 0x12, 0xed, 0x11, + 0x31, 0x0b, 0xe5, 0xf9, 0x1e, 0xf5, 0x70, 0x4f, 0x0c, 0x54, 0x4d, 0x61, 0xce, 0x68, 0x3f, 0xd9, + 0x65, 0x4c, 0x44, 0x78, 0xe9, 0x95, 0x9a, 0x52, 0xd1, 0x0b, 0xb1, 0x59, 0x17, 0xfd, 0x8a, 0x03, + 0xe3, 0x4d, 0x69, 0xae, 0xc7, 0x9d, 0xa6, 0xcc, 0xef, 0x89, 0xad, 0x2c, 0xbf, 0x15, 0x1d, 0x33, + 0x97, 0x25, 0x0c, 0x10, 0x36, 0x69, 0x67, 0xb3, 0xd6, 0x8c, 0xf4, 0x99, 0xb5, 0xe6, 0xfb, 0x0e, + 0x4c, 0x66, 0xa9, 0xa1, 0x6d, 0x78, 0xb8, 0xe5, 0x45, 0xdb, 0x97, 0x83, 0xad, 0x88, 0x5d, 0xf0, + 0x48, 0xf8, 0x62, 0x98, 0xdd, 0x4a, 0x48, 0xb4, 0xe0, 0xed, 0x72, 0xf7, 0x67, 0x51, 0x3d, 0x10, + 0xf5, 0xf0, 0xea, 0x7e, 0x95, 0xf1, 0xfe, 0xb8, 0x50, 0x05, 0x4e, 0xd1, 0x0a, 0x2c, 0xa9, 0x9d, + 0x1f, 0x06, 0x29, 0x91, 0x02, 0x23, 0xa2, 0x82, 0x0c, 0x57, 0xf3, 0x2a, 0xe1, 0xfc, 0xb6, 0xee, + 0x45, 0x18, 0xe2, 0xf7, 0xed, 0xee, 0xc9, 0x7f, 0xe4, 0xfe, 0x9b, 0x02, 0x48, 0xc1, 0xf0, 0x2f, + 0xb7, 0x3b, 0x8e, 0x1e, 0xa2, 0x11, 0x33, 0x29, 0x09, 0x6b, 0x07, 0x3b, 0x44, 0x45, 0xfa, 0x48, + 0x51, 0x42, 0x25, 0x66, 0x72, 0xd3, 0x4f, 0xe6, 0xc3, 0x9a, 0xb4, 0x71, 0x30, 0x89, 0xf9, 0xa2, + 0x80, 0x61, 0x55, 0xea, 0x7e, 0xd2, 0x81, 0x71, 0x3a, 0xca, 0x66, 0x93, 0x34, 0x2b, 0x09, 0x69, + 0xc7, 0x28, 0x86, 0x62, 0x4c, 0xff, 0xb1, 0x67, 0x0a, 0x4c, 0xef, 0x68, 0x92, 0xb6, 0xe6, 0xac, + 0xa1, 0x44, 0x30, 0xa7, 0xe5, 0xbe, 0x35, 0x00, 0xa3, 0x6a, 0xb2, 0xfb, 0xb0, 0xa7, 0x5e, 0x48, + 0x33, 0xbb, 0x72, 0x0e, 0x5c, 0xd6, 0xb2, 0xba, 0xde, 0xa6, 0x53, 0x17, 0xec, 0xf2, 0x14, 0x17, + 0x69, 0x8a, 0xd7, 0xa7, 0x4c, 0x57, 0xf3, 0x69, 0x7d, 0xfd, 0x69, 0xf5, 0x85, 0xcf, 0xf9, 0xa6, + 0xee, 0xe9, 0x1f, 0xb4, 0x75, 0x9a, 0x29, 0x37, 0x66, 0x6f, 0x17, 0x7f, 0xe6, 0xd1, 0x9f, 0x62, + 0x5f, 0x8f, 0xfe, 0x3c, 0x09, 0x83, 0x24, 0xe8, 0xb4, 0x98, 0xa8, 0x34, 0xca, 0x54, 0x84, 0xc1, + 0x8b, 0x41, 0xa7, 0x65, 0x8e, 0x8c, 0x55, 0x41, 0xef, 0x83, 0x52, 0x8d, 0xc4, 0xd5, 0xc8, 0x67, + 0x79, 0x1b, 0x84, 0x65, 0xe7, 0x21, 0x66, 0x2e, 0x4b, 0xc1, 0x66, 0x43, 0xbd, 0x81, 0xfb, 0x2a, + 0x0c, 0xad, 0x37, 0x3b, 0x75, 0x3f, 0x40, 0x6d, 0x18, 0xe2, 0x59, 0x1c, 0xc4, 0x69, 0x6f, 0x41, + 0xef, 0xe4, 0xac, 0x42, 0x8b, 0x42, 0xe1, 0x57, 0x75, 0x05, 0x1d, 0xf7, 0x13, 0x05, 0xa0, 0xaa, + 0xf9, 0xd2, 0x3c, 0xfa, 0xeb, 0x5d, 0x6f, 0xdc, 0xfc, 0x5c, 0xce, 0x1b, 0x37, 0xe3, 0xac, 0x72, + 0xce, 0xf3, 0x36, 0x4d, 0x18, 0x67, 0xce, 0x11, 0x79, 0x06, 0x0a, 0xb1, 0xfa, 0x99, 0x3e, 0x13, + 0x1f, 0xe8, 0x4d, 0xc5, 0x89, 0xa0, 0x83, 0xb0, 0x89, 0x1c, 0xad, 0xc2, 0x09, 0x9e, 0x20, 0x74, + 0x81, 0x34, 0xbd, 0xdd, 0x4c, 0x22, 0xb0, 0xb3, 0xf2, 0xd9, 0xb2, 0x85, 0xee, 0x2a, 0x38, 0xaf, + 0x9d, 0xfb, 0xfb, 0x83, 0xa0, 0xb9, 0x24, 0xfa, 0xd8, 0x2d, 0xaf, 0x64, 0x1c, 0x50, 0xab, 0x56, + 0x1c, 0x50, 0xd2, 0xab, 0xc3, 0x39, 0x90, 0xe9, 0x73, 0xa2, 0x9d, 0x6a, 0x90, 0x66, 0x5b, 0x8c, + 0x51, 0x75, 0xea, 0x12, 0x69, 0xb6, 0x31, 0x2b, 0x51, 0x17, 0x15, 0x07, 0x7b, 0x5e, 0x54, 0x6c, + 0x40, 0xb1, 0xee, 0x75, 0xea, 0x44, 0x44, 0x60, 0x5a, 0xf0, 0x35, 0xb2, 0xab, 0x13, 0xdc, 0xd7, + 0xc8, 0xfe, 0xc5, 0x9c, 0x00, 0xdd, 0xec, 0x0d, 0x19, 0x92, 0x22, 0x8c, 0xb4, 0x16, 0x36, 0xbb, + 0x8a, 0x72, 0xe1, 0x9b, 0x5d, 0xfd, 0xc4, 0x29, 0x31, 0xd4, 0x86, 0xe1, 0x2a, 0x4f, 0xbf, 0x22, + 0x64, 0x96, 0xcb, 0x36, 0x6e, 0x62, 0x32, 0x84, 0xdc, 0x9a, 0x22, 0x7e, 0x60, 0x49, 0xc6, 0x3d, + 0x0f, 0x25, 0xed, 0xa9, 0x0d, 0xfa, 0x19, 0x54, 0xe6, 0x0f, 0xed, 0x33, 0x2c, 0x78, 0x89, 0x87, + 0x59, 0x89, 0xfb, 0xcd, 0x41, 0x50, 0xb6, 0x34, 0xfd, 0xde, 0xa0, 0x57, 0xd5, 0xf2, 0x14, 0x19, + 0x77, 0xe8, 0xc3, 0x00, 0x8b, 0x52, 0x2a, 0xd7, 0xb5, 0x48, 0x54, 0x57, 0x7a, 0xb4, 0x60, 0xd7, + 0x4a, 0xae, 0x5b, 0xd5, 0x0b, 0xb1, 0x59, 0x97, 0x0a, 0xe5, 0x2d, 0xe1, 0xa2, 0xcf, 0x06, 0x56, + 0x4b, 0xd7, 0x3d, 0x56, 0x35, 0x58, 0xa2, 0x83, 0x96, 0xe6, 0xd1, 0x17, 0x81, 0x98, 0x36, 0x1c, + 0x4a, 0x1a, 0x56, 0x1e, 0x30, 0xa5, 0x43, 0xb0, 0x41, 0x15, 0x2d, 0xc1, 0xf1, 0x98, 0x24, 0x6b, + 0x37, 0x02, 0x12, 0xa9, 0x14, 0x03, 0x22, 0x93, 0x86, 0xba, 0x55, 0x51, 0xc9, 0x56, 0xc0, 0xdd, + 0x6d, 0x72, 0x63, 0x57, 0x8b, 0x07, 0x8e, 0x5d, 0x5d, 0x80, 0xc9, 0x2d, 0xcf, 0x6f, 0x76, 0x22, + 0xd2, 0x33, 0x02, 0x76, 0x31, 0x53, 0x8e, 0xbb, 0x5a, 0xb0, 0x8b, 0x3d, 0x4d, 0xaf, 0x1e, 0x97, + 0x87, 0xb5, 0x8b, 0x3d, 0x14, 0x80, 0x39, 0xdc, 0xfd, 0x2d, 0x07, 0x78, 0x0a, 0xa3, 0xd9, 0xad, + 0x2d, 0x3f, 0xf0, 0x93, 0x5d, 0xf4, 0x35, 0x07, 0x26, 0x83, 0xb0, 0x46, 0x66, 0x83, 0xc4, 0x97, + 0x40, 0x7b, 0x79, 0xe5, 0x19, 0xad, 0x2b, 0x19, 0xf4, 0x3c, 0x1f, 0x46, 0x16, 0x8a, 0xbb, 0xba, + 0xe1, 0x9e, 0x81, 0x53, 0xb9, 0x08, 0xdc, 0xef, 0x0f, 0x80, 0x99, 0x89, 0x09, 0x3d, 0x0f, 0xc5, + 0x26, 0xcb, 0x0d, 0xe2, 0xdc, 0x65, 0x8a, 0x2d, 0x36, 0x57, 0x3c, 0x79, 0x08, 0xc7, 0x84, 0x16, + 0xa0, 0xc4, 0xd2, 0x3b, 0x89, 0xcc, 0x2d, 0x05, 0x23, 0x25, 0x42, 0x09, 0xa7, 0x45, 0xb7, 0xcd, + 0x9f, 0x58, 0x6f, 0x86, 0x5e, 0x83, 0xe1, 0x4d, 0x9e, 0xe4, 0xd2, 0x9e, 0xcf, 0x4f, 0x64, 0xcd, + 0x64, 0xb2, 0x91, 0x4c, 0xa1, 0x79, 0x3b, 0xfd, 0x17, 0x4b, 0x8a, 0x68, 0x17, 0x46, 0x3c, 0xf9, + 0x4d, 0x07, 0x6d, 0x5d, 0xd4, 0x30, 0xd6, 0x8f, 0x88, 0x98, 0x91, 0xdf, 0x50, 0x91, 0xcb, 0x84, + 0x16, 0x15, 0xfb, 0x0a, 0x2d, 0xfa, 0xb6, 0x03, 0x90, 0xbe, 0x08, 0x82, 0x6e, 0xc2, 0x48, 0xfc, + 0x8c, 0x61, 0xa8, 0xb0, 0x71, 0x43, 0x5f, 0x60, 0xd4, 0x6e, 0xb1, 0x0a, 0x08, 0x56, 0xd4, 0xee, + 0x64, 0x5c, 0xf9, 0xa9, 0x03, 0x27, 0xf3, 0x5e, 0x2e, 0xb9, 0x8f, 0x3d, 0x3e, 0xa8, 0x5d, 0x45, + 0x34, 0x58, 0x8f, 0xc8, 0x96, 0x7f, 0x33, 0x27, 0xd5, 0x32, 0x2f, 0xc0, 0x69, 0x1d, 0xf7, 0x4f, + 0x87, 0x41, 0x11, 0x3e, 0x24, 0x3b, 0xcc, 0xe3, 0x54, 0x67, 0xaa, 0xa7, 0x32, 0x97, 0xaa, 0x87, + 0x19, 0x14, 0x8b, 0x52, 0xaa, 0x37, 0xc9, 0xa0, 0x78, 0xc1, 0xb2, 0xd9, 0x2a, 0x94, 0xc1, 0xf3, + 0x58, 0x95, 0xe6, 0x59, 0x76, 0x8a, 0x47, 0x62, 0xd9, 0x19, 0xb2, 0x6f, 0xd9, 0x69, 0x01, 0x8a, + 0xf9, 0x46, 0x61, 0xe6, 0x14, 0x41, 0x68, 0xec, 0xc0, 0x86, 0xe6, 0x4a, 0x17, 0x12, 0x9c, 0x83, + 0x98, 0xc5, 0x50, 0x84, 0x4d, 0x32, 0x8b, 0xaf, 0x08, 0xe5, 0x23, 0x8d, 0xa1, 0xe0, 0x60, 0x2c, + 0xcb, 0xef, 0xd2, 0x94, 0x82, 0x7e, 0xc7, 0xd9, 0xc7, 0x56, 0x35, 0x6a, 0xeb, 0x08, 0xca, 0x4d, + 0x83, 0xc7, 0x34, 0xa9, 0xbb, 0x31, 0x80, 0x7d, 0xdd, 0x81, 0xe3, 0x24, 0xa8, 0x46, 0xbb, 0x0c, + 0x8f, 0xc0, 0x26, 0x5c, 0xdc, 0x57, 0x6d, 0xec, 0xf5, 0x8b, 0x59, 0xe4, 0xdc, 0x93, 0xd4, 0x05, + 0xc6, 0xdd, 0xdd, 0x40, 0x6b, 0x30, 0x52, 0xf5, 0xc4, 0xba, 0x28, 0x1d, 0x64, 0x5d, 0x70, 0x47, + 0xdd, 0xac, 0x58, 0x0d, 0x0a, 0x89, 0xfb, 0xe3, 0x02, 0x9c, 0xc8, 0xe9, 0x12, 0xbb, 0xaf, 0xd5, + 0xa2, 0x1b, 0xe0, 0x72, 0x2d, 0xbb, 0xfd, 0x97, 0x05, 0x1c, 0xab, 0x1a, 0x68, 0x1d, 0x4e, 0x6e, + 0xb7, 0xe2, 0x14, 0xcb, 0x7c, 0x18, 0x24, 0xe4, 0xa6, 0x64, 0x06, 0xd2, 0xfd, 0x7d, 0x72, 0x39, + 0xa7, 0x0e, 0xce, 0x6d, 0x49, 0xa5, 0x25, 0x12, 0x78, 0x9b, 0x4d, 0x92, 0x16, 0x89, 0x5b, 0x8c, + 0x4a, 0x5a, 0xba, 0x98, 0x29, 0xc7, 0x5d, 0x2d, 0xd0, 0x67, 0x1d, 0x38, 0x1b, 0x93, 0x68, 0x87, + 0x44, 0x15, 0xbf, 0x46, 0xe6, 0x3b, 0x71, 0x12, 0xb6, 0x48, 0x74, 0x97, 0xd6, 0xd9, 0xe9, 0x5b, + 0x7b, 0xd3, 0x67, 0x2b, 0xbd, 0xb1, 0xe1, 0xfd, 0x48, 0xb9, 0x9f, 0x75, 0x60, 0xa2, 0xc2, 0x74, + 0x77, 0x25, 0xba, 0xdb, 0x4e, 0x84, 0xfa, 0xb8, 0xca, 0xbb, 0x91, 0x61, 0xc2, 0x66, 0xa6, 0x0c, + 0xf7, 0x65, 0x98, 0xac, 0x90, 0x96, 0xd7, 0x6e, 0xb0, 0x2b, 0xc8, 0x3c, 0xfc, 0xeb, 0x3c, 0x8c, + 0xc6, 0x12, 0x96, 0x7d, 0xfb, 0x48, 0x55, 0xc6, 0x69, 0x1d, 0xf4, 0x18, 0x0f, 0x55, 0x93, 0x17, + 0x8e, 0x46, 0xb9, 0x92, 0xc3, 0xe3, 0xdb, 0x62, 0x2c, 0xcb, 0xdc, 0xb7, 0x1c, 0x18, 0x4b, 0xdb, + 0x93, 0x2d, 0x54, 0x87, 0x63, 0x55, 0xed, 0xb2, 0x5e, 0x7a, 0x4d, 0xa2, 0xff, 0x7b, 0x7d, 0x3c, + 0x3f, 0xb3, 0x89, 0x04, 0x67, 0xb1, 0x1e, 0x3c, 0xd2, 0xef, 0x0b, 0x05, 0x38, 0xa6, 0xba, 0x2a, + 0xfc, 0x94, 0x6f, 0x64, 0x03, 0xf2, 0xb0, 0x8d, 0x0c, 0x42, 0xe6, 0xdc, 0xef, 0x13, 0x94, 0xf7, + 0x46, 0x36, 0x28, 0xef, 0x50, 0xc9, 0x77, 0xb9, 0x5e, 0xbf, 0x5d, 0x80, 0x11, 0x95, 0xcf, 0xe8, + 0x79, 0x28, 0x32, 0xcd, 0xf5, 0xde, 0xe4, 0x6f, 0xa6, 0x05, 0x63, 0x8e, 0x89, 0xa2, 0x64, 0x41, + 0x3f, 0x77, 0x9d, 0x35, 0x77, 0x94, 0xdb, 0x2f, 0xbd, 0x28, 0xc1, 0x1c, 0x13, 0x5a, 0x86, 0x01, + 0x12, 0xd4, 0x84, 0x20, 0x7e, 0x70, 0x84, 0xec, 0x95, 0xb2, 0x8b, 0x41, 0x0d, 0x53, 0x2c, 0x2c, + 0xa9, 0x1a, 0x97, 0xb7, 0x32, 0x6f, 0xd2, 0x08, 0x61, 0x4b, 0x94, 0xba, 0xef, 0x07, 0x23, 0xe1, + 0x9e, 0x48, 0xe4, 0x2f, 0x74, 0xbc, 0xee, 0x87, 0xc4, 0x84, 0x72, 0x97, 0xd6, 0x71, 0x7f, 0x65, + 0x00, 0x86, 0x2a, 0x9d, 0x4d, 0xaa, 0x93, 0x7c, 0xcb, 0x81, 0x13, 0x37, 0x32, 0x39, 0xa9, 0xd3, + 0x4d, 0x72, 0xd5, 0x9e, 0x11, 0x58, 0x8f, 0x5c, 0x53, 0xa6, 0xaf, 0x9c, 0x42, 0x9c, 0xd7, 0x1d, + 0x23, 0x2d, 0xec, 0xc0, 0xa1, 0xa4, 0x85, 0xbd, 0x79, 0xc8, 0x57, 0x37, 0xc6, 0x7b, 0x5d, 0xdb, + 0x70, 0x7f, 0xbf, 0x08, 0xc0, 0xbf, 0xc6, 0x5a, 0x3b, 0xe9, 0xc7, 0xac, 0xf7, 0x2c, 0x8c, 0xd5, + 0x49, 0x40, 0x22, 0x19, 0x97, 0x98, 0x79, 0x2f, 0x69, 0x49, 0x2b, 0xc3, 0x46, 0x4d, 0xa6, 0x43, + 0x05, 0x49, 0xb4, 0xcb, 0xe5, 0xec, 0xec, 0xf5, 0x0c, 0x55, 0x82, 0xb5, 0x5a, 0x68, 0xc6, 0xf0, + 0xba, 0x70, 0x07, 0xfe, 0xc4, 0x3e, 0x4e, 0x92, 0xf7, 0xc1, 0x84, 0x99, 0x43, 0x45, 0x48, 0x7b, + 0xca, 0xe1, 0x6e, 0xa6, 0x5e, 0xc1, 0x99, 0xda, 0x74, 0x17, 0xd4, 0xa2, 0x5d, 0xdc, 0x09, 0x84, + 0xd8, 0xa7, 0x76, 0xc1, 0x02, 0x83, 0x62, 0x51, 0xca, 0x92, 0x4f, 0xb0, 0x03, 0x90, 0xc3, 0x45, + 0x02, 0x8b, 0x34, 0xf9, 0x84, 0x56, 0x86, 0x8d, 0x9a, 0x94, 0x82, 0x30, 0x8b, 0x82, 0xb9, 0xcf, + 0x32, 0xb6, 0xcc, 0x36, 0x4c, 0x84, 0xa6, 0x39, 0x87, 0xcb, 0x40, 0xef, 0xea, 0x73, 0xe9, 0x19, + 0x6d, 0x79, 0xa0, 0x44, 0xc6, 0xfa, 0x93, 0xc1, 0x4f, 0xe5, 0x5e, 0xfd, 0x16, 0xc3, 0x98, 0x19, + 0xd6, 0xda, 0xf3, 0xa2, 0xc1, 0x3a, 0x9c, 0x6c, 0x87, 0xb5, 0xf5, 0xc8, 0x0f, 0x23, 0x3f, 0xd9, + 0x9d, 0x6f, 0x7a, 0x71, 0xcc, 0x16, 0xc6, 0xb8, 0x29, 0x0f, 0xad, 0xe7, 0xd4, 0xc1, 0xb9, 0x2d, + 0xa9, 0x42, 0xd4, 0x16, 0x40, 0x16, 0x5c, 0x56, 0xe4, 0x12, 0x9d, 0xac, 0x88, 0x55, 0xa9, 0x7b, + 0x02, 0x8e, 0x57, 0x3a, 0xed, 0x76, 0xd3, 0x27, 0x35, 0xe5, 0xd5, 0x70, 0xdf, 0x0f, 0xc7, 0x44, + 0xd2, 0x58, 0x25, 0x7d, 0x1c, 0x28, 0xc5, 0xb9, 0xfb, 0x1f, 0x07, 0xe0, 0x58, 0x26, 0x94, 0x07, + 0xbd, 0x96, 0x95, 0x19, 0xec, 0x24, 0x33, 0xd5, 0xa4, 0x05, 0x91, 0x99, 0x34, 0x4f, 0xfe, 0x68, + 0xc8, 0x38, 0x7c, 0x6b, 0xf7, 0x5f, 0x58, 0xb4, 0x3a, 0x3f, 0x52, 0x8c, 0x60, 0xfe, 0x8f, 0x02, + 0x28, 0xb2, 0xf2, 0xca, 0xbd, 0xed, 0x71, 0xb2, 0xfd, 0xab, 0x20, 0x31, 0xd6, 0x28, 0xa2, 0x00, + 0x86, 0x59, 0x47, 0x88, 0xbc, 0x74, 0x69, 0x6d, 0xac, 0x4c, 0x64, 0x5b, 0xe5, 0xb8, 0xb1, 0x24, + 0xe2, 0x7e, 0xa6, 0x00, 0xf9, 0xf1, 0x62, 0xe8, 0xa3, 0xdd, 0x1f, 0xfc, 0x79, 0x8b, 0x13, 0x21, + 0x02, 0xd6, 0x7a, 0x7f, 0xf3, 0xc0, 0xfc, 0xe6, 0xab, 0x96, 0xe6, 0x41, 0xd0, 0xed, 0xfa, 0xf2, + 0xee, 0xff, 0x70, 0xa0, 0xb4, 0xb1, 0xb1, 0xa2, 0xce, 0x75, 0x0c, 0xa7, 0x63, 0x9e, 0xcf, 0x80, + 0xb9, 0xd5, 0xe7, 0xc3, 0x56, 0x9b, 0x7b, 0xd9, 0x85, 0xf7, 0x9f, 0xe5, 0x2b, 0xae, 0xe4, 0xd6, + 0xc0, 0x3d, 0x5a, 0xa2, 0xcb, 0x70, 0x42, 0x2f, 0xa9, 0x68, 0xcf, 0x43, 0x16, 0x45, 0x6e, 0xa2, + 0xee, 0x62, 0x9c, 0xd7, 0x26, 0x8b, 0x4a, 0x58, 0x93, 0xd9, 0xf1, 0x9c, 0x83, 0x4a, 0x14, 0xe3, + 0xbc, 0x36, 0xee, 0x1a, 0x94, 0x36, 0xbc, 0x48, 0x0d, 0xfc, 0x03, 0x30, 0x59, 0x0d, 0x5b, 0xd2, + 0x8a, 0xb7, 0x42, 0x76, 0x48, 0x53, 0x0c, 0x99, 0xbf, 0xc9, 0x92, 0x29, 0xc3, 0x5d, 0xb5, 0xdd, + 0xff, 0x7a, 0x0e, 0xd4, 0xfd, 0xcc, 0x3e, 0x4e, 0xd4, 0xb6, 0x8a, 0xa4, 0x2d, 0x5a, 0x8e, 0xa4, + 0x55, 0x67, 0x4b, 0x26, 0x9a, 0x36, 0x49, 0xa3, 0x69, 0x87, 0x6c, 0x47, 0xd3, 0x2a, 0x09, 0xbb, + 0x2b, 0xa2, 0xf6, 0x2b, 0x0e, 0x8c, 0x05, 0x61, 0x8d, 0x28, 0xf7, 0xe7, 0x30, 0xdb, 0xe1, 0x2f, + 0xd9, 0xbb, 0x98, 0xc0, 0x23, 0x43, 0x05, 0x7a, 0x1e, 0xe5, 0xad, 0x8e, 0x64, 0xbd, 0x08, 0x1b, + 0xfd, 0x40, 0x8b, 0x9a, 0x5d, 0x99, 0xbb, 0x6f, 0x1e, 0xca, 0xd3, 0xcf, 0xee, 0x68, 0x24, 0xbe, + 0xa9, 0xc9, 0x89, 0xa3, 0xb6, 0xec, 0xa5, 0xf2, 0xd2, 0x9d, 0xe6, 0x85, 0x92, 0x29, 0xb7, 0x53, + 0xf9, 0xd1, 0x85, 0x21, 0x1e, 0x0e, 0x2e, 0xb2, 0x60, 0x31, 0xe7, 0x28, 0x0f, 0x15, 0xc7, 0xa2, + 0x04, 0x25, 0x32, 0xc4, 0xa2, 0x64, 0xeb, 0x01, 0x0d, 0x23, 0x84, 0x23, 0x3f, 0xc6, 0x02, 0x3d, + 0xa7, 0xeb, 0xfd, 0x63, 0xfd, 0xe8, 0xfd, 0xe3, 0x3d, 0x75, 0xfe, 0xcf, 0x3b, 0x30, 0x56, 0xd5, + 0x1e, 0xb4, 0x28, 0x3f, 0x61, 0xeb, 0xe1, 0xee, 0xbc, 0x77, 0x47, 0xb8, 0xcf, 0xcd, 0x78, 0x40, + 0xc3, 0xa0, 0xce, 0x52, 0x7f, 0x32, 0x23, 0x07, 0x13, 0x75, 0xac, 0x64, 0xe5, 0x30, 0x8d, 0x26, + 0x32, 0x54, 0x95, 0xc2, 0xb0, 0xa0, 0x85, 0x5e, 0x87, 0x11, 0x79, 0xa3, 0x40, 0x44, 0xde, 0x63, + 0x1b, 0x4e, 0x10, 0xd3, 0xd3, 0x2a, 0xf3, 0x05, 0x72, 0x28, 0x56, 0x14, 0x51, 0x03, 0x06, 0x6a, + 0x5e, 0x5d, 0xc4, 0xe0, 0xaf, 0xda, 0xc9, 0xc7, 0x2a, 0x69, 0x32, 0x7d, 0x74, 0x61, 0x76, 0x09, + 0x53, 0x12, 0xe8, 0x66, 0xfa, 0x22, 0xc0, 0xa4, 0xb5, 0xd3, 0xd7, 0x14, 0x0b, 0xb9, 0x4c, 0xd0, + 0xf5, 0xc0, 0x40, 0x4d, 0x38, 0xa7, 0xff, 0x3f, 0x46, 0x76, 0xd1, 0x4e, 0x42, 0x57, 0x9e, 0xe5, + 0x25, 0x75, 0x70, 0x53, 0x2a, 0x8d, 0x24, 0x69, 0x97, 0x7f, 0xde, 0x16, 0x15, 0x96, 0xab, 0x84, + 0xbf, 0xb1, 0xbe, 0xb1, 0xb1, 0x8e, 0x19, 0x76, 0xd4, 0x84, 0xa1, 0x36, 0x8b, 0x9b, 0x29, 0xff, + 0x82, 0xad, 0xb3, 0x85, 0xc7, 0xe1, 0xf0, 0xb5, 0xc9, 0xff, 0xc7, 0x82, 0x06, 0xba, 0x08, 0xc3, + 0xfc, 0x61, 0x1b, 0x7e, 0x07, 0xa2, 0x74, 0x61, 0xaa, 0xf7, 0xf3, 0x38, 0xe9, 0x41, 0xc1, 0x7f, + 0xc7, 0x58, 0xb6, 0x45, 0x5f, 0x70, 0x60, 0x82, 0x72, 0xd4, 0xf4, 0x25, 0x9e, 0x32, 0xb2, 0xc5, + 0xb3, 0xae, 0xc6, 0x54, 0x22, 0x91, 0xbc, 0x46, 0xa9, 0x85, 0x97, 0x0d, 0x72, 0x38, 0x43, 0x1e, + 0xbd, 0x01, 0x23, 0xb1, 0x5f, 0x23, 0x55, 0x2f, 0x8a, 0xcb, 0x27, 0x0e, 0xa7, 0x2b, 0xa9, 0x3b, + 0x4c, 0x10, 0xc2, 0x8a, 0x24, 0xfa, 0x75, 0xf6, 0x14, 0x6a, 0xb5, 0xe1, 0xef, 0x90, 0x95, 0xb0, + 0xca, 0xd5, 0x98, 0x93, 0xb6, 0xf6, 0xbe, 0x74, 0xfc, 0x49, 0xcc, 0xc2, 0x4b, 0x64, 0x92, 0xc3, + 0x59, 0xfa, 0xe8, 0x6f, 0x38, 0x70, 0x8a, 0x3f, 0x59, 0x90, 0x7d, 0x85, 0xe3, 0xd4, 0x5d, 0xda, + 0xa3, 0xd8, 0xe5, 0x8d, 0xd9, 0x3c, 0x94, 0x38, 0x9f, 0x12, 0x4b, 0x30, 0x6c, 0x3e, 0x9c, 0x74, + 0xda, 0xaa, 0x5b, 0xb8, 0xff, 0xc7, 0x92, 0xd0, 0xd3, 0x50, 0x6a, 0x8b, 0xe3, 0xd0, 0x8f, 0x5b, + 0xec, 0x2a, 0xce, 0x00, 0xbf, 0x24, 0xb9, 0x9e, 0x82, 0xb1, 0x5e, 0xc7, 0xc8, 0x36, 0xfd, 0xe4, + 0x7e, 0xd9, 0xa6, 0xd1, 0x55, 0x28, 0x25, 0x61, 0x53, 0x24, 0x5c, 0x8d, 0xcb, 0x65, 0xb6, 0x02, + 0xcf, 0xe5, 0xed, 0xad, 0x0d, 0x55, 0x2d, 0xd5, 0xdc, 0x53, 0x58, 0x8c, 0x75, 0x3c, 0x2c, 0xfc, + 0x59, 0x3c, 0x05, 0x11, 0x31, 0x95, 0xfd, 0xc1, 0x4c, 0xf8, 0xb3, 0x5e, 0x88, 0xcd, 0xba, 0x68, + 0x09, 0x8e, 0xb7, 0xbb, 0x74, 0x7e, 0x7e, 0x05, 0x50, 0x45, 0x9c, 0x74, 0x2b, 0xfc, 0xdd, 0x6d, + 0x0c, 0x6d, 0xff, 0xec, 0x7e, 0xda, 0x7e, 0x8f, 0xdc, 0xcb, 0x0f, 0xdd, 0x4d, 0xee, 0x65, 0x54, + 0x83, 0x87, 0xbc, 0x4e, 0x12, 0xb2, 0x7c, 0x3c, 0x66, 0x13, 0x1e, 0x09, 0xfe, 0x08, 0x0f, 0x2e, + 0xbf, 0xb5, 0x37, 0xfd, 0xd0, 0xec, 0x3e, 0xf5, 0xf0, 0xbe, 0x58, 0xd0, 0xab, 0x30, 0x42, 0x44, + 0xfe, 0xe8, 0xf2, 0xcf, 0xd9, 0x12, 0x12, 0xcc, 0x8c, 0xd4, 0x32, 0xc8, 0x96, 0xc3, 0xb0, 0xa2, + 0x87, 0x36, 0xa0, 0xd4, 0x08, 0xe3, 0x64, 0xb6, 0xe9, 0x7b, 0x31, 0x89, 0xcb, 0x0f, 0xb3, 0x45, + 0x93, 0x2b, 0x7b, 0x5d, 0x92, 0xd5, 0xd2, 0x35, 0x73, 0x29, 0x6d, 0x89, 0x75, 0x34, 0x88, 0x30, + 0xe7, 0x30, 0x0b, 0x83, 0x97, 0x8e, 0xaf, 0x73, 0x6c, 0x60, 0x8f, 0xe7, 0x61, 0x5e, 0x0f, 0x6b, + 0x15, 0xb3, 0xb6, 0xf2, 0x0e, 0xeb, 0x40, 0x9c, 0xc5, 0x89, 0x9e, 0x85, 0xb1, 0x76, 0x58, 0xab, + 0xb4, 0x49, 0x75, 0xdd, 0x4b, 0xaa, 0x8d, 0xf2, 0xb4, 0x69, 0x65, 0x5c, 0xd7, 0xca, 0xb0, 0x51, + 0x13, 0xb5, 0x61, 0xb8, 0xc5, 0x13, 0x35, 0x94, 0x1f, 0xb5, 0xa5, 0xdb, 0x88, 0xcc, 0x0f, 0xc2, + 0x86, 0xc0, 0x7f, 0x60, 0x49, 0x06, 0xfd, 0x7d, 0x07, 0x8e, 0x65, 0x2e, 0x97, 0x95, 0xdf, 0x61, + 0x4d, 0x64, 0x31, 0x11, 0xcf, 0x3d, 0xce, 0xa6, 0xcf, 0x04, 0xde, 0xee, 0x06, 0xe1, 0x6c, 0x8f, + 0xf8, 0xbc, 0xb0, 0x6c, 0x2b, 0xe5, 0xc7, 0xec, 0xcd, 0x0b, 0x43, 0x28, 0xe7, 0x85, 0xfd, 0xc0, + 0x92, 0x0c, 0x7a, 0x12, 0x86, 0x45, 0x62, 0xc4, 0xf2, 0xe3, 0xa6, 0xcb, 0x5d, 0xe4, 0x4f, 0xc4, + 0xb2, 0x7c, 0xea, 0xfd, 0x70, 0xbc, 0x4b, 0x75, 0x3b, 0x50, 0xca, 0x8f, 0xdf, 0x74, 0x40, 0xbf, + 0x8d, 0x6e, 0xfd, 0xd1, 0x96, 0x67, 0x61, 0xac, 0xca, 0xdf, 0xd0, 0xe4, 0xf7, 0xd9, 0x07, 0x4d, + 0x7b, 0xef, 0xbc, 0x56, 0x86, 0x8d, 0x9a, 0xee, 0x25, 0x40, 0xdd, 0x19, 0xf5, 0xef, 0x2a, 0x9f, + 0xd4, 0x3f, 0x74, 0x60, 0xdc, 0x90, 0x19, 0xac, 0x3b, 0x55, 0x17, 0x01, 0xb5, 0xfc, 0x28, 0x0a, + 0x23, 0xfd, 0xb1, 0x42, 0x91, 0x73, 0x82, 0x05, 0x5b, 0xac, 0x76, 0x95, 0xe2, 0x9c, 0x16, 0xee, + 0x3f, 0x1e, 0x84, 0x34, 0xca, 0x5c, 0xa5, 0x2c, 0x76, 0x7a, 0xa6, 0x2c, 0x7e, 0x0a, 0x46, 0x5e, + 0x8e, 0xc3, 0x60, 0x3d, 0x4d, 0x6c, 0xac, 0xbe, 0xc5, 0x73, 0x95, 0xb5, 0x2b, 0xac, 0xa6, 0xaa, + 0xc1, 0x6a, 0xbf, 0xb2, 0xe8, 0x37, 0x93, 0xee, 0xcc, 0xb7, 0xcf, 0x3d, 0xcf, 0xe1, 0x58, 0xd5, + 0x60, 0xef, 0x16, 0xee, 0x10, 0xe5, 0x08, 0x48, 0xdf, 0x2d, 0xe4, 0x8f, 0x65, 0xb0, 0x32, 0x74, + 0x1e, 0x46, 0x95, 0x13, 0x41, 0x78, 0x26, 0xd4, 0x4c, 0x29, 0x4f, 0x03, 0x4e, 0xeb, 0x30, 0x81, + 0x50, 0x18, 0x9e, 0x85, 0x09, 0xa5, 0x62, 0x43, 0x3d, 0xc9, 0x98, 0xb2, 0x39, 0x6f, 0x97, 0x60, + 0xac, 0x48, 0xe6, 0x39, 0x96, 0x47, 0x0f, 0xc5, 0xb1, 0xac, 0x5d, 0x79, 0x28, 0xf6, 0x7b, 0xe5, + 0xc1, 0x5c, 0xdb, 0x23, 0x7d, 0xad, 0xed, 0x4f, 0x0d, 0xc0, 0xf0, 0x35, 0x12, 0xb1, 0x84, 0xef, + 0x4f, 0xc2, 0xf0, 0x0e, 0xff, 0x37, 0x7b, 0x5f, 0x56, 0xd4, 0xc0, 0xb2, 0x9c, 0x7e, 0xb7, 0xcd, + 0x8e, 0xdf, 0xac, 0x2d, 0xa4, 0xbb, 0x38, 0xcd, 0xe9, 0x28, 0x0b, 0x70, 0x5a, 0x87, 0x36, 0xa8, + 0x53, 0xc9, 0xbe, 0xd5, 0xf2, 0xbb, 0x9e, 0xe4, 0x5f, 0x92, 0x05, 0x38, 0xad, 0x83, 0x1e, 0x87, + 0xa1, 0xba, 0x9f, 0x6c, 0x78, 0xf5, 0xac, 0x5b, 0x74, 0x89, 0x41, 0xb1, 0x28, 0x65, 0x6e, 0x31, + 0x3f, 0xd9, 0x88, 0x08, 0xb3, 0xec, 0x76, 0xa5, 0xeb, 0x58, 0xd2, 0xca, 0xb0, 0x51, 0x93, 0x75, + 0x29, 0x14, 0x23, 0x13, 0x41, 0xb2, 0x69, 0x97, 0x64, 0x01, 0x4e, 0xeb, 0xd0, 0xf5, 0x5f, 0x0d, + 0x5b, 0x6d, 0xbf, 0x29, 0xc2, 0xb7, 0xb5, 0xf5, 0x3f, 0x2f, 0xe0, 0x58, 0xd5, 0xa0, 0xb5, 0x29, + 0x0b, 0xa3, 0xec, 0x27, 0xfb, 0x46, 0xdc, 0xba, 0x80, 0x63, 0x55, 0xc3, 0xbd, 0x06, 0xe3, 0x7c, + 0x27, 0xcf, 0x37, 0x3d, 0xbf, 0xb5, 0x34, 0x8f, 0x2e, 0x76, 0x5d, 0x79, 0x78, 0x32, 0xe7, 0xca, + 0xc3, 0x29, 0xa3, 0x51, 0xf7, 0xd5, 0x07, 0xf7, 0x87, 0x05, 0x18, 0x39, 0xc2, 0x67, 0x36, 0x8f, + 0xfc, 0xc5, 0x68, 0x74, 0x33, 0xf3, 0xc4, 0xe6, 0xba, 0xcd, 0x1b, 0x4c, 0xfb, 0x3e, 0xaf, 0xf9, + 0x9f, 0x0a, 0x70, 0x5a, 0x56, 0x95, 0xba, 0xdc, 0xd2, 0x3c, 0x7b, 0xba, 0xec, 0xf0, 0x27, 0x3a, + 0x32, 0x26, 0x7a, 0xdd, 0x9e, 0x36, 0xba, 0x34, 0xdf, 0x73, 0xaa, 0x5f, 0xcd, 0x4c, 0x35, 0xb6, + 0x4a, 0x75, 0xff, 0xc9, 0xfe, 0x73, 0x07, 0xa6, 0xf2, 0x27, 0xfb, 0x08, 0x5e, 0x35, 0x7d, 0xc3, + 0x7c, 0xd5, 0xf4, 0x97, 0xec, 0x2d, 0x31, 0x73, 0x28, 0x3d, 0xde, 0x37, 0xfd, 0xef, 0x0e, 0x9c, + 0x94, 0x0d, 0xd8, 0xe9, 0x39, 0xe7, 0x07, 0x2c, 0x72, 0xe7, 0xf0, 0x97, 0xd9, 0xeb, 0xc6, 0x32, + 0x7b, 0xd1, 0xde, 0xc0, 0xf5, 0x71, 0xf4, 0x7c, 0x0d, 0xfe, 0xcf, 0x1c, 0x28, 0xe7, 0x35, 0x38, + 0x82, 0x4f, 0xfe, 0x9a, 0xf9, 0xc9, 0xaf, 0x1d, 0xce, 0xc8, 0x7b, 0x7f, 0xf0, 0x72, 0xaf, 0x89, + 0x42, 0x4d, 0x29, 0x57, 0x39, 0xb6, 0x7c, 0xd2, 0x9c, 0x44, 0xbe, 0x80, 0xd6, 0x84, 0xa1, 0x98, + 0x45, 0xa9, 0x88, 0x25, 0x70, 0xc9, 0x86, 0xb4, 0x45, 0xf1, 0x09, 0x1b, 0x3b, 0xfb, 0x1f, 0x0b, + 0x1a, 0xee, 0x6f, 0x15, 0xe0, 0x8c, 0x7a, 0xad, 0x98, 0xec, 0x90, 0x66, 0xba, 0x3f, 0xd8, 0xf3, + 0x18, 0x9e, 0xfa, 0x69, 0xef, 0x79, 0x8c, 0x94, 0x44, 0xba, 0x17, 0x52, 0x18, 0xd6, 0x68, 0xa2, + 0x0a, 0x9c, 0x62, 0xcf, 0x59, 0x2c, 0xfa, 0x81, 0xd7, 0xf4, 0x5f, 0x25, 0x11, 0x26, 0xad, 0x70, + 0xc7, 0x6b, 0x0a, 0x49, 0x5d, 0x5d, 0x99, 0x5e, 0xcc, 0xab, 0x84, 0xf3, 0xdb, 0x76, 0x69, 0xdc, + 0x03, 0xfd, 0x6a, 0xdc, 0xee, 0x9f, 0x38, 0x30, 0x76, 0x84, 0x6f, 0x3b, 0x87, 0xe6, 0x96, 0x78, + 0xce, 0xde, 0x96, 0xe8, 0xb1, 0x0d, 0xf6, 0x8a, 0xd0, 0xf5, 0xdc, 0x2d, 0xfa, 0xb4, 0xa3, 0xe2, + 0x78, 0x78, 0xb0, 0xe4, 0x87, 0xec, 0xf5, 0xe3, 0x20, 0x79, 0x36, 0xd1, 0xd7, 0x33, 0xc9, 0x47, + 0x0b, 0xb6, 0x32, 0x68, 0x75, 0xf5, 0xe6, 0x2e, 0x92, 0x90, 0x7e, 0xc5, 0x01, 0xe0, 0xfd, 0x14, + 0xb9, 0xcb, 0x69, 0xdf, 0x36, 0x0f, 0x6d, 0xa6, 0x28, 0x11, 0xde, 0x35, 0xb5, 0x85, 0xd2, 0x02, + 0xac, 0xf5, 0xe4, 0x1e, 0xb2, 0x8b, 0xde, 0x73, 0x62, 0xd3, 0x2f, 0x38, 0x70, 0x2c, 0xd3, 0xdd, + 0x9c, 0xf6, 0x5b, 0xe6, 0xeb, 0x8c, 0x16, 0x24, 0x2b, 0x33, 0xa3, 0xb5, 0x6e, 0x3c, 0xf9, 0x2f, + 0x2e, 0x18, 0xef, 0x84, 0xa3, 0xd7, 0x60, 0x54, 0x5a, 0x3e, 0xe4, 0xf2, 0xb6, 0xf9, 0x4a, 0xad, + 0x52, 0x6f, 0x24, 0x24, 0xc6, 0x29, 0xbd, 0x4c, 0x98, 0x60, 0xa1, 0xaf, 0x30, 0xc1, 0xfb, 0xfb, + 0xc6, 0x6d, 0xbe, 0x5d, 0x7a, 0xf0, 0x50, 0xec, 0xd2, 0x0f, 0x59, 0xb7, 0x4b, 0x3f, 0x7c, 0xc4, + 0x76, 0x69, 0xcd, 0x49, 0x58, 0xbc, 0x07, 0x27, 0xe1, 0x6b, 0x70, 0x72, 0x27, 0x55, 0x3a, 0xd5, + 0x4a, 0x12, 0x79, 0x9b, 0x9e, 0xcc, 0xb5, 0x46, 0x53, 0x05, 0x3a, 0x4e, 0x48, 0x90, 0x68, 0xea, + 0x6a, 0x1a, 0xa1, 0x78, 0x2d, 0x07, 0x1d, 0xce, 0x25, 0x92, 0xf5, 0xf6, 0x0c, 0xf7, 0xe1, 0xed, + 0x79, 0xcb, 0x81, 0x53, 0x5e, 0xd7, 0x1d, 0x3b, 0x4c, 0xb6, 0x44, 0xc8, 0xc9, 0x75, 0x7b, 0x22, + 0x84, 0x81, 0x5e, 0xb8, 0xd5, 0xf2, 0x8a, 0x70, 0x7e, 0x87, 0xd0, 0x63, 0xa9, 0xeb, 0x9d, 0xc7, + 0xb5, 0xe6, 0xfb, 0xc9, 0xbf, 0x9e, 0x8d, 0xe7, 0x01, 0x36, 0xf5, 0x1f, 0xb1, 0xab, 0x6d, 0x5b, + 0x88, 0xe9, 0x29, 0xdd, 0x43, 0x4c, 0x4f, 0xc6, 0xf5, 0x36, 0x66, 0xc9, 0xf5, 0x16, 0xc0, 0xa4, + 0xdf, 0xf2, 0xea, 0x64, 0xbd, 0xd3, 0x6c, 0xf2, 0x4b, 0x33, 0xf2, 0x1d, 0xe1, 0x5c, 0x0b, 0xde, + 0x4a, 0x58, 0xf5, 0x9a, 0xd9, 0x17, 0xe4, 0xd5, 0xe5, 0xa0, 0xcb, 0x19, 0x4c, 0xb8, 0x0b, 0x37, + 0x5d, 0xb0, 0x2c, 0x81, 0x20, 0x49, 0xe8, 0x6c, 0xb3, 0xc0, 0x91, 0x11, 0xbe, 0x60, 0x2f, 0xa5, + 0x60, 0xac, 0xd7, 0x41, 0xcb, 0x30, 0x5a, 0x0b, 0x62, 0x71, 0x5d, 0xf8, 0x18, 0x63, 0x66, 0xef, + 0xa4, 0x2c, 0x70, 0xe1, 0x4a, 0x45, 0x5d, 0x14, 0x7e, 0x28, 0x27, 0x23, 0xa6, 0x2a, 0xc7, 0x69, + 0x7b, 0xb4, 0xca, 0x90, 0x89, 0x47, 0xd6, 0x78, 0x3c, 0xc7, 0x23, 0x3d, 0x1c, 0x46, 0x0b, 0x57, + 0xe4, 0x33, 0x71, 0xe3, 0x82, 0x9c, 0x78, 0x2d, 0x2d, 0xc5, 0xa0, 0xbd, 0xe7, 0x7c, 0x7c, 0xdf, + 0xf7, 0x9c, 0x59, 0x2a, 0xdc, 0xa4, 0xa9, 0xdc, 0xc3, 0xe7, 0xac, 0xa5, 0xc2, 0x4d, 0x23, 0x25, + 0x45, 0x2a, 0xdc, 0x14, 0x80, 0x75, 0x92, 0x68, 0xad, 0x97, 0x9b, 0xfc, 0x04, 0x63, 0x1a, 0x07, + 0x77, 0x7a, 0xeb, 0xfe, 0xd2, 0x93, 0xfb, 0xfa, 0x4b, 0xbb, 0xfc, 0xbb, 0xa7, 0x0e, 0xe0, 0xdf, + 0x6d, 0xb0, 0x24, 0xa5, 0x4b, 0xf3, 0xc2, 0xa5, 0x6e, 0x41, 0xbf, 0x63, 0x69, 0x51, 0x78, 0xe4, + 0x29, 0xfb, 0x17, 0x73, 0x02, 0x3d, 0x03, 0xc8, 0xcf, 0xdc, 0x75, 0x00, 0x39, 0x65, 0xcf, 0x29, + 0x9c, 0x65, 0xbb, 0x2d, 0x0a, 0xf6, 0x9c, 0x82, 0xb1, 0x5e, 0x27, 0xeb, 0x2d, 0x7d, 0xf0, 0xd0, + 0xbc, 0xa5, 0x53, 0x47, 0xe0, 0x2d, 0x3d, 0xdb, 0xb7, 0xb7, 0xf4, 0x26, 0x9c, 0x68, 0x87, 0xb5, + 0x05, 0x3f, 0x8e, 0x3a, 0xec, 0x16, 0xe1, 0x5c, 0xa7, 0x56, 0x27, 0x09, 0x73, 0xb7, 0x96, 0x2e, + 0xbc, 0x53, 0xef, 0x64, 0x9b, 0x6d, 0x64, 0xb9, 0x47, 0x33, 0x0d, 0x98, 0xe9, 0x84, 0x45, 0xdd, + 0xe6, 0x14, 0xe2, 0x3c, 0x12, 0xba, 0x9f, 0xf6, 0x91, 0xa3, 0xf1, 0xd3, 0x7e, 0x00, 0x46, 0xe2, + 0x46, 0x27, 0xa9, 0x85, 0x37, 0x02, 0xe6, 0x8c, 0x1f, 0x9d, 0x7b, 0x87, 0x32, 0x65, 0x0b, 0xf8, + 0xed, 0xbd, 0xe9, 0x49, 0xf9, 0xbf, 0x66, 0xc5, 0x16, 0x10, 0xf4, 0x8d, 0x1e, 0xf7, 0x95, 0xdc, + 0xc3, 0xbc, 0xaf, 0x74, 0xe6, 0x40, 0x77, 0x95, 0xf2, 0x9c, 0xd1, 0x8f, 0xfe, 0xcc, 0x39, 0xa3, + 0xbf, 0xe6, 0xc0, 0xf8, 0x8e, 0xee, 0x32, 0x10, 0x0e, 0x73, 0x0b, 0x81, 0x3b, 0x86, 0x27, 0x62, + 0xce, 0xa5, 0x7c, 0xce, 0x00, 0xdd, 0xce, 0x02, 0xb0, 0xd9, 0x93, 0x9c, 0xa0, 0xa2, 0xc7, 0xee, + 0x57, 0x50, 0xd1, 0x1b, 0x8c, 0x8f, 0x49, 0x25, 0x97, 0x79, 0xd1, 0xed, 0xc6, 0x14, 0x4b, 0x9e, + 0xa8, 0x42, 0x8a, 0x75, 0x7a, 0xe8, 0xf3, 0x0e, 0x4c, 0x4a, 0xbd, 0x4c, 0xb8, 0xfc, 0x62, 0x11, + 0x15, 0x69, 0x53, 0x1d, 0x64, 0x61, 0xf5, 0x1b, 0x19, 0x3a, 0xb8, 0x8b, 0x32, 0xe5, 0xea, 0x2a, + 0x08, 0xad, 0x1e, 0xb3, 0xe0, 0x5f, 0x21, 0xc3, 0xcc, 0xa6, 0x60, 0xac, 0xd7, 0x41, 0xdf, 0x74, + 0xa0, 0xd8, 0x08, 0xc3, 0xed, 0xb8, 0xfc, 0x24, 0x63, 0xe8, 0x2f, 0x58, 0x96, 0x4d, 0x2f, 0x51, + 0xdc, 0x5c, 0x28, 0x7d, 0x5a, 0xda, 0x8e, 0x18, 0xec, 0xf6, 0xde, 0xf4, 0x84, 0xf1, 0x96, 0x53, + 0xfc, 0xe6, 0xdb, 0x1a, 0x44, 0xd8, 0x36, 0x59, 0xd7, 0xd0, 0x97, 0x1c, 0x98, 0xbc, 0x91, 0x31, + 0x68, 0x88, 0xb0, 0x50, 0x6c, 0xdf, 0x54, 0xc2, 0xa7, 0x3b, 0x0b, 0xc5, 0x5d, 0x3d, 0x40, 0x9f, + 0x33, 0x0d, 0x9d, 0x3c, 0x7e, 0xd4, 0xe2, 0x04, 0x66, 0x0c, 0xab, 0xfc, 0x5a, 0x50, 0xbe, 0xc5, + 0xf3, 0x9e, 0xe3, 0x43, 0xa6, 0xe8, 0x60, 0xd2, 0x8f, 0x95, 0xd3, 0x94, 0x98, 0xf6, 0x16, 0x0b, + 0x9b, 0xdd, 0xf8, 0xfc, 0xba, 0xb9, 0xe5, 0x4b, 0xa7, 0x61, 0xc2, 0xf4, 0xed, 0xa1, 0x77, 0x99, + 0xef, 0x74, 0x9c, 0xcb, 0x3e, 0x79, 0x30, 0x2e, 0xeb, 0x1b, 0xcf, 0x1e, 0x18, 0xef, 0x12, 0x14, + 0x0e, 0xf5, 0x5d, 0x82, 0x81, 0xa3, 0x79, 0x97, 0x60, 0xf2, 0x30, 0xde, 0x25, 0x38, 0x7e, 0xa0, + 0x77, 0x09, 0xb4, 0x77, 0x21, 0x06, 0xef, 0xf0, 0x2e, 0xc4, 0x2c, 0x1c, 0x93, 0x77, 0x7f, 0x88, + 0x48, 0xfd, 0xce, 0xdd, 0xfe, 0x67, 0x44, 0x93, 0x63, 0xf3, 0x66, 0x31, 0xce, 0xd6, 0xa7, 0x9b, + 0xac, 0x18, 0xb0, 0x96, 0x43, 0xb6, 0x1e, 0x8d, 0x32, 0x97, 0x16, 0x53, 0x9f, 0x05, 0x8b, 0x92, + 0xd1, 0xce, 0x45, 0x06, 0xbb, 0x2d, 0xff, 0xc1, 0xbc, 0x07, 0xe8, 0x25, 0x28, 0x87, 0x5b, 0x5b, + 0xcd, 0xd0, 0xab, 0xa5, 0x8f, 0x27, 0xc8, 0xb8, 0x04, 0x7e, 0x57, 0x55, 0xe5, 0xda, 0x5d, 0xeb, + 0x51, 0x0f, 0xf7, 0xc4, 0x80, 0xde, 0xa2, 0x82, 0x49, 0x12, 0x46, 0xa4, 0x96, 0xda, 0x6a, 0x46, + 0xd9, 0x98, 0x89, 0xf5, 0x31, 0x57, 0x4c, 0x3a, 0x7c, 0xf4, 0xea, 0xa3, 0x64, 0x4a, 0x71, 0xb6, + 0x5b, 0x28, 0x82, 0xd3, 0xed, 0x3c, 0x53, 0x51, 0x2c, 0x6e, 0x2c, 0xed, 0x67, 0xb0, 0x52, 0x0f, + 0x69, 0xe7, 0x1a, 0x9b, 0x62, 0xdc, 0x03, 0xb3, 0xfe, 0xc0, 0xc1, 0xc8, 0xd1, 0x3c, 0x70, 0xf0, + 0x31, 0x00, 0x75, 0x29, 0x5f, 0x1a, 0x1f, 0x96, 0xad, 0x5c, 0xa5, 0xe1, 0x38, 0xb5, 0x37, 0x65, + 0x15, 0x19, 0xac, 0x91, 0x44, 0xff, 0x3b, 0xf7, 0x05, 0x10, 0x6e, 0x61, 0xa9, 0x5b, 0x5f, 0x13, + 0x3f, 0x73, 0xaf, 0x80, 0xfc, 0x03, 0x07, 0xa6, 0xf8, 0xca, 0xcb, 0x0a, 0xf7, 0x54, 0xb4, 0x10, + 0x77, 0x7b, 0x6c, 0x87, 0xae, 0xf0, 0x94, 0x49, 0x06, 0x55, 0xe6, 0xe8, 0xde, 0xa7, 0x27, 0xe8, + 0x2b, 0x39, 0x2a, 0xc5, 0x31, 0x5b, 0x36, 0xcb, 0xfc, 0x77, 0x1c, 0x4e, 0xdc, 0xea, 0x47, 0x8b, + 0xf8, 0x47, 0x3d, 0x4d, 0xaa, 0x88, 0x75, 0xef, 0x97, 0x0f, 0xc9, 0xa4, 0xaa, 0x3f, 0x36, 0x71, + 0x20, 0xc3, 0xea, 0x17, 0x1c, 0x98, 0xf4, 0x32, 0xa1, 0x26, 0xcc, 0x0e, 0x64, 0xc5, 0x26, 0x35, + 0x1b, 0xa5, 0xf1, 0x2b, 0x4c, 0xc8, 0xcb, 0x46, 0xb5, 0xe0, 0x2e, 0xe2, 0xe8, 0x87, 0x0e, 0x9c, + 0x4d, 0xbc, 0x78, 0x9b, 0xa7, 0x72, 0x8e, 0xd3, 0xbb, 0xba, 0xa2, 0x73, 0x27, 0xd9, 0x6e, 0x7c, + 0xc5, 0xfa, 0x6e, 0xdc, 0xe8, 0x4d, 0x93, 0xef, 0xcb, 0x47, 0xc5, 0xbe, 0x3c, 0xbb, 0x4f, 0x4d, + 0xbc, 0x5f, 0xd7, 0xa7, 0x3e, 0xed, 0xf0, 0x27, 0xbf, 0x7a, 0x8a, 0x7c, 0x9b, 0xa6, 0xc8, 0xb7, + 0x62, 0xf3, 0xd1, 0x21, 0x5d, 0xf6, 0xfc, 0x35, 0x07, 0x4e, 0xe6, 0x9d, 0x48, 0x39, 0x5d, 0xfa, + 0x88, 0xd9, 0x25, 0x8b, 0x5a, 0x96, 0xde, 0x21, 0x2b, 0x6f, 0x9e, 0x4c, 0x5d, 0x81, 0x47, 0xee, + 0xf4, 0x15, 0xef, 0x84, 0x6f, 0x44, 0x17, 0x8b, 0xff, 0x6c, 0x54, 0xf3, 0x42, 0x26, 0xa4, 0x6d, + 0x3d, 0x86, 0x3b, 0x80, 0x21, 0x3f, 0x68, 0xfa, 0x01, 0x11, 0xf7, 0x35, 0x6d, 0xea, 0xb0, 0xe2, + 0xcd, 0x22, 0x8a, 0x1d, 0x0b, 0x2a, 0xf7, 0xd9, 0x29, 0x99, 0x7d, 0x05, 0x6e, 0xf0, 0xe8, 0x5f, + 0x81, 0xbb, 0x01, 0xa3, 0x37, 0xfc, 0xa4, 0xc1, 0x82, 0x29, 0x84, 0xaf, 0xcf, 0xc2, 0x3d, 0x47, + 0x8a, 0x2e, 0x1d, 0xfb, 0x75, 0x49, 0x00, 0xa7, 0xb4, 0xd0, 0x79, 0x4e, 0x98, 0x45, 0x6e, 0x67, + 0x43, 0x6a, 0xaf, 0xcb, 0x02, 0x9c, 0xd6, 0xa1, 0x93, 0x35, 0x46, 0x7f, 0xc9, 0x04, 0x50, 0x22, + 0x2d, 0xb2, 0x8d, 0x74, 0x97, 0x02, 0x23, 0xbf, 0x4d, 0x7c, 0x5d, 0xa3, 0x81, 0x0d, 0x8a, 0x2a, + 0x33, 0xf5, 0x48, 0xcf, 0xcc, 0xd4, 0xaf, 0x33, 0x81, 0x2d, 0xf1, 0x83, 0x0e, 0x59, 0x0b, 0x44, + 0xbc, 0xf7, 0x8a, 0x9d, 0xbb, 0xcf, 0x1c, 0x27, 0x57, 0xc1, 0xd3, 0xdf, 0x58, 0xa3, 0xa7, 0xb9, + 0x5c, 0x4a, 0xfb, 0xba, 0x5c, 0x52, 0x93, 0xcb, 0x98, 0x75, 0x93, 0x4b, 0x42, 0xda, 0x56, 0x4c, + 0x2e, 0x3f, 0x53, 0xe6, 0x80, 0x3f, 0x77, 0x00, 0x29, 0xb9, 0x4b, 0x31, 0xd4, 0x23, 0x08, 0xaa, + 0xfc, 0xb8, 0x03, 0x10, 0xa8, 0xb7, 0x42, 0xed, 0x9e, 0x82, 0x1c, 0x67, 0xda, 0x81, 0x14, 0x86, + 0x35, 0x9a, 0xee, 0x9f, 0x3a, 0x69, 0xec, 0x72, 0x3a, 0xf6, 0x23, 0x08, 0x22, 0xdb, 0x35, 0x83, + 0xc8, 0x36, 0x2c, 0x9a, 0xee, 0xd5, 0x30, 0x7a, 0x84, 0x93, 0xfd, 0xa4, 0x00, 0xc7, 0xf4, 0xca, + 0x15, 0x72, 0x14, 0x1f, 0xfb, 0x86, 0x11, 0x41, 0x7b, 0xd5, 0xee, 0x78, 0x2b, 0xc2, 0x03, 0x94, + 0x17, 0xad, 0xfd, 0xb1, 0x4c, 0xb4, 0xf6, 0x75, 0xfb, 0xa4, 0xf7, 0x0f, 0xd9, 0xfe, 0xcf, 0x0e, + 0x9c, 0xc8, 0xb4, 0x38, 0x82, 0x05, 0xb6, 0x63, 0x2e, 0xb0, 0xe7, 0xad, 0x8f, 0xba, 0xc7, 0xea, + 0xfa, 0x56, 0xa1, 0x6b, 0xb4, 0x4c, 0x89, 0xfb, 0x94, 0x03, 0x45, 0x2a, 0x2d, 0xcb, 0x78, 0xae, + 0x8f, 0x1c, 0xca, 0x0a, 0x60, 0x72, 0xbd, 0xe0, 0xce, 0xaa, 0x7f, 0x0c, 0x86, 0x39, 0xf5, 0xa9, + 0x4f, 0x3a, 0x00, 0x69, 0xa5, 0xfb, 0x25, 0x02, 0xbb, 0xdf, 0x29, 0xc0, 0xa9, 0xdc, 0x65, 0x84, + 0x3e, 0xa3, 0x2c, 0x72, 0x8e, 0xed, 0x68, 0x45, 0x83, 0x90, 0x6e, 0x98, 0x1b, 0x37, 0x0c, 0x73, + 0xc2, 0x1e, 0x77, 0xbf, 0x14, 0x18, 0xc1, 0xa6, 0xb5, 0xc9, 0xfa, 0xb1, 0x93, 0x06, 0xc0, 0xaa, + 0xbc, 0x46, 0x7f, 0x01, 0x2f, 0xf1, 0xb8, 0x3f, 0xd1, 0x6e, 0x38, 0xc8, 0x81, 0x1e, 0x01, 0xaf, + 0xb8, 0x61, 0xf2, 0x0a, 0x6c, 0xdf, 0x8f, 0xdc, 0x83, 0x59, 0xbc, 0x02, 0x79, 0x8e, 0xe5, 0xfe, + 0x92, 0x40, 0x1a, 0xd7, 0x61, 0x0b, 0x7d, 0x5f, 0x87, 0x1d, 0x87, 0xd2, 0x8b, 0xbe, 0xca, 0x1e, + 0x3a, 0x37, 0xf3, 0xdd, 0x1f, 0x9d, 0x7b, 0xe0, 0x7b, 0x3f, 0x3a, 0xf7, 0xc0, 0x0f, 0x7f, 0x74, + 0xee, 0x81, 0x8f, 0xdf, 0x3a, 0xe7, 0x7c, 0xf7, 0xd6, 0x39, 0xe7, 0x7b, 0xb7, 0xce, 0x39, 0x3f, + 0xbc, 0x75, 0xce, 0xf9, 0xb7, 0xb7, 0xce, 0x39, 0x7f, 0xeb, 0xdf, 0x9d, 0x7b, 0xe0, 0xc5, 0x11, + 0x39, 0xb0, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x78, 0xa3, 0xd3, 0x3a, 0x8f, 0xd8, 0x00, 0x00, } func (m *Amount) Marshal() (dAtA []byte, err error) { @@ -11341,6 +11343,34 @@ func (m *Synchronization) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Mutexes) > 0 { + for iNdEx := len(m.Mutexes) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Mutexes[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x22 + } + } + if len(m.Semaphores) > 0 { + for iNdEx := len(m.Semaphores) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.Semaphores[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + } if m.Mutex != nil { { size, err := m.Mutex.MarshalToSizedBuffer(dAtA[:i]) @@ -16428,6 +16458,18 @@ func (m *Synchronization) Size() (n int) { l = m.Mutex.Size() n += 1 + l + sovGenerated(uint64(l)) } + if len(m.Semaphores) > 0 { + for _, e := range m.Semaphores { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } + if len(m.Mutexes) > 0 { + for _, e := range m.Mutexes { + l = e.Size() + n += 1 + l + sovGenerated(uint64(l)) + } + } return n } @@ -19040,9 +19082,21 @@ func (this *Synchronization) String() string { if this == nil { return "nil" } + repeatedStringForSemaphores := "[]*SemaphoreRef{" + for _, f := range this.Semaphores { + repeatedStringForSemaphores += strings.Replace(f.String(), "SemaphoreRef", "SemaphoreRef", 1) + "," + } + repeatedStringForSemaphores += "}" + repeatedStringForMutexes := "[]*Mutex{" + for _, f := range this.Mutexes { + repeatedStringForMutexes += strings.Replace(f.String(), "Mutex", "Mutex", 1) + "," + } + repeatedStringForMutexes += "}" s := strings.Join([]string{`&Synchronization{`, `Semaphore:` + strings.Replace(this.Semaphore.String(), "SemaphoreRef", "SemaphoreRef", 1) + `,`, `Mutex:` + strings.Replace(this.Mutex.String(), "Mutex", "Mutex", 1) + `,`, + `Semaphores:` + repeatedStringForSemaphores + `,`, + `Mutexes:` + repeatedStringForMutexes + `,`, `}`, }, "") return s @@ -39120,6 +39174,74 @@ func (m *Synchronization) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Semaphores", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Semaphores = append(m.Semaphores, &SemaphoreRef{}) + if err := m.Semaphores[len(m.Semaphores)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Mutexes", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenerated + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenerated + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Mutexes = append(m.Mutexes, &Mutex{}) + if err := m.Mutexes[len(m.Mutexes)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) diff --git a/pkg/apis/workflow/v1alpha1/generated.proto b/pkg/apis/workflow/v1alpha1/generated.proto index facdfe3763d1..dbe6f87cf7e7 100644 --- a/pkg/apis/workflow/v1alpha1/generated.proto +++ b/pkg/apis/workflow/v1alpha1/generated.proto @@ -1561,11 +1561,17 @@ message SuspendTemplate { // Synchronization holds synchronization lock configuration message Synchronization { - // Semaphore holds the Semaphore configuration + // Semaphore holds the Semaphore configuration - deprecated, use semaphores instead optional SemaphoreRef semaphore = 1; - // Mutex holds the Mutex lock details + // Mutex holds the Mutex lock details - deprecated, use mutexes instead optional Mutex mutex = 2; + + // Semaphores holds the list of Semaphores configuration + repeated SemaphoreRef semaphores = 3; + + // Mutexes holds the list of Mutex lock details + repeated Mutex mutexes = 4; } // SynchronizationStatus stores the status of semaphore and mutex. diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index c5060c77ee6f..7c17df2624a2 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -6172,16 +6172,42 @@ func schema_pkg_apis_workflow_v1alpha1_Synchronization(ref common.ReferenceCallb Properties: map[string]spec.Schema{ "semaphore": { SchemaProps: spec.SchemaProps{ - Description: "Semaphore holds the Semaphore configuration", + Description: "Semaphore holds the Semaphore configuration - deprecated, use semaphores instead", Ref: ref("github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1.SemaphoreRef"), }, }, "mutex": { SchemaProps: spec.SchemaProps{ - Description: "Mutex holds the Mutex lock details", + Description: "Mutex holds the Mutex lock details - deprecated, use mutexes instead", Ref: ref("github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1.Mutex"), }, }, + "semaphores": { + SchemaProps: spec.SchemaProps{ + Description: "Semaphores holds the list of Semaphores configuration", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1.SemaphoreRef"), + }, + }, + }, + }, + }, + "mutexes": { + SchemaProps: spec.SchemaProps{ + Description: "Mutexes holds the list of Mutex lock details", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1.Mutex"), + }, + }, + }, + }, + }, }, }, }, diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 0ec8817c1d6f..3cd1840c0c4e 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -1642,10 +1642,14 @@ type TemplateRef struct { // Synchronization holds synchronization lock configuration type Synchronization struct { - // Semaphore holds the Semaphore configuration + // Semaphore holds the Semaphore configuration - deprecated, use semaphores instead Semaphore *SemaphoreRef `json:"semaphore,omitempty" protobuf:"bytes,1,opt,name=semaphore"` - // Mutex holds the Mutex lock details + // Mutex holds the Mutex lock details - deprecated, use mutexes instead Mutex *Mutex `json:"mutex,omitempty" protobuf:"bytes,2,opt,name=mutex"` + // Semaphores holds the list of Semaphores configuration + Semaphores []*SemaphoreRef `json:"semaphores,omitempty" protobuf:"bytes,3,opt,name=semaphores"` + // Mutexes holds the list of Mutex lock details + Mutexes []*Mutex `json:"mutexes,omitempty" protobuf:"bytes,4,opt,name=mutexes"` } func (s *Synchronization) getSemaphoreConfigMapRef() *apiv1.ConfigMapKeySelector { @@ -1655,23 +1659,6 @@ func (s *Synchronization) getSemaphoreConfigMapRef() *apiv1.ConfigMapKeySelector return nil } -type SynchronizationType string - -const ( - SynchronizationTypeSemaphore SynchronizationType = "Semaphore" - SynchronizationTypeMutex SynchronizationType = "Mutex" - SynchronizationTypeUnknown SynchronizationType = "Unknown" -) - -func (s *Synchronization) GetType() SynchronizationType { - if s.Semaphore != nil { - return SynchronizationTypeSemaphore - } else if s.Mutex != nil { - return SynchronizationTypeMutex - } - return SynchronizationTypeUnknown -} - // SemaphoreRef is a reference of Semaphore type SemaphoreRef struct { // ConfigMapKeyRef is configmap selector for Semaphore configuration @@ -3915,6 +3902,14 @@ type SynchronizationStatus struct { Mutex *MutexStatus `json:"mutex,omitempty" protobuf:"bytes,2,opt,name=mutex"` } +type SynchronizationType string + +const ( + SynchronizationTypeSemaphore SynchronizationType = "Semaphore" + SynchronizationTypeMutex SynchronizationType = "Mutex" + SynchronizationTypeUnknown SynchronizationType = "Unknown" +) + func (ss *SynchronizationStatus) GetStatus(syncType SynchronizationType) SynchronizationAction { switch syncType { case SynchronizationTypeSemaphore: diff --git a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go index 9862a4d1eee4..7592ca05ced8 100644 --- a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go @@ -3055,6 +3055,28 @@ func (in *Synchronization) DeepCopyInto(out *Synchronization) { *out = new(Mutex) **out = **in } + if in.Semaphores != nil { + in, out := &in.Semaphores, &out.Semaphores + *out = make([]*SemaphoreRef, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(SemaphoreRef) + (*in).DeepCopyInto(*out) + } + } + } + if in.Mutexes != nil { + in, out := &in.Mutexes, &out.Mutexes + *out = make([]*Mutex, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Mutex) + **out = **in + } + } + } return } diff --git a/pkg/plugins/executor/swagger.yml b/pkg/plugins/executor/swagger.yml index e00ffffe4341..588d7190e343 100644 --- a/pkg/plugins/executor/swagger.yml +++ b/pkg/plugins/executor/swagger.yml @@ -4221,8 +4221,18 @@ definitions: properties: mutex: $ref: '#/definitions/Mutex' + mutexes: + description: Mutexes holds the list of Mutex lock details + items: + $ref: '#/definitions/Mutex' + type: array semaphore: $ref: '#/definitions/SemaphoreRef' + semaphores: + description: Semaphores holds the list of Semaphores configuration + items: + $ref: '#/definitions/SemaphoreRef' + type: array type: object Sysctl: description: Sysctl defines a kernel parameter to be set diff --git a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md index ac9b866bb953..310e05a2f1d6 100644 --- a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md +++ b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md @@ -9,7 +9,9 @@ Synchronization holds synchronization lock configuration Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **mutex** | [**IoArgoprojWorkflowV1alpha1Mutex**](IoArgoprojWorkflowV1alpha1Mutex.md) | | [optional] +**mutexes** | [**List<IoArgoprojWorkflowV1alpha1Mutex>**](IoArgoprojWorkflowV1alpha1Mutex.md) | Mutexes holds the list of Mutex lock details | [optional] **semaphore** | [**IoArgoprojWorkflowV1alpha1SemaphoreRef**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | | [optional] +**semaphores** | [**List<IoArgoprojWorkflowV1alpha1SemaphoreRef>**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | Semaphores holds the list of Semaphores configuration | [optional] diff --git a/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py index 3c3a131cbb58..95fa013e6b89 100644 --- a/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py +++ b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py @@ -90,7 +90,9 @@ def openapi_types(): lazy_import() return { 'mutex': (IoArgoprojWorkflowV1alpha1Mutex,), # noqa: E501 + 'mutexes': ([IoArgoprojWorkflowV1alpha1Mutex],), # noqa: E501 'semaphore': (IoArgoprojWorkflowV1alpha1SemaphoreRef,), # noqa: E501 + 'semaphores': ([IoArgoprojWorkflowV1alpha1SemaphoreRef],), # noqa: E501 } @cached_property @@ -100,7 +102,9 @@ def discriminator(): attribute_map = { 'mutex': 'mutex', # noqa: E501 + 'mutexes': 'mutexes', # noqa: E501 'semaphore': 'semaphore', # noqa: E501 + 'semaphores': 'semaphores', # noqa: E501 } read_only_vars = { @@ -145,7 +149,9 @@ def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 through its discriminator because we passed in _visited_composed_classes = (Animal,) mutex (IoArgoprojWorkflowV1alpha1Mutex): [optional] # noqa: E501 + mutexes ([IoArgoprojWorkflowV1alpha1Mutex]): Mutexes holds the list of Mutex lock details. [optional] # noqa: E501 semaphore (IoArgoprojWorkflowV1alpha1SemaphoreRef): [optional] # noqa: E501 + semaphores ([IoArgoprojWorkflowV1alpha1SemaphoreRef]): Semaphores holds the list of Semaphores configuration. [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) @@ -228,7 +234,9 @@ def __init__(self, *args, **kwargs): # noqa: E501 through its discriminator because we passed in _visited_composed_classes = (Animal,) mutex (IoArgoprojWorkflowV1alpha1Mutex): [optional] # noqa: E501 + mutexes ([IoArgoprojWorkflowV1alpha1Mutex]): Mutexes holds the list of Mutex lock details. [optional] # noqa: E501 semaphore (IoArgoprojWorkflowV1alpha1SemaphoreRef): [optional] # noqa: E501 + semaphores ([IoArgoprojWorkflowV1alpha1SemaphoreRef]): Semaphores holds the list of Semaphores configuration. [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) diff --git a/sdks/python/client/docs/ClusterWorkflowTemplateServiceApi.md b/sdks/python/client/docs/ClusterWorkflowTemplateServiceApi.md index 916110314804..24d56f83bee4 100644 --- a/sdks/python/client/docs/ClusterWorkflowTemplateServiceApi.md +++ b/sdks/python/client/docs/ClusterWorkflowTemplateServiceApi.md @@ -1097,6 +1097,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -1105,6 +1111,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -5479,6 +5495,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -5487,6 +5509,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -10265,6 +10297,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -10273,6 +10311,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -12536,6 +12584,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -12544,6 +12598,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -16918,6 +16982,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -16926,6 +16996,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -21704,6 +21784,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -21712,6 +21798,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -23881,6 +23977,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -23889,6 +23991,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -28263,6 +28375,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -28271,6 +28389,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -33049,6 +33177,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -33057,6 +33191,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ diff --git a/sdks/python/client/docs/CronWorkflowServiceApi.md b/sdks/python/client/docs/CronWorkflowServiceApi.md index 64bdaa0ce443..c7c5ec6a921e 100644 --- a/sdks/python/client/docs/CronWorkflowServiceApi.md +++ b/sdks/python/client/docs/CronWorkflowServiceApi.md @@ -1157,6 +1157,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -1165,6 +1171,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -5539,6 +5555,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -5547,6 +5569,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -10325,6 +10357,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -10333,6 +10371,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -12678,6 +12726,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -12686,6 +12740,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -17060,6 +17124,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -17068,6 +17138,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -21846,6 +21926,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -21854,6 +21940,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -24286,6 +24382,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -24294,6 +24396,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -28668,6 +28780,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -28676,6 +28794,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -33454,6 +33582,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -33462,6 +33596,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ diff --git a/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md index fc8ba3f2e9c5..829ce269c1fc 100644 --- a/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md +++ b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md @@ -6,7 +6,9 @@ Synchronization holds synchronization lock configuration Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **mutex** | [**IoArgoprojWorkflowV1alpha1Mutex**](IoArgoprojWorkflowV1alpha1Mutex.md) | | [optional] +**mutexes** | [**[IoArgoprojWorkflowV1alpha1Mutex]**](IoArgoprojWorkflowV1alpha1Mutex.md) | Mutexes holds the list of Mutex lock details | [optional] **semaphore** | [**IoArgoprojWorkflowV1alpha1SemaphoreRef**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | | [optional] +**semaphores** | [**[IoArgoprojWorkflowV1alpha1SemaphoreRef]**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | Semaphores holds the list of Semaphores configuration | [optional] **any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/sdks/python/client/docs/WorkflowServiceApi.md b/sdks/python/client/docs/WorkflowServiceApi.md index 93cf7dafd65b..9a7be230c42c 100644 --- a/sdks/python/client/docs/WorkflowServiceApi.md +++ b/sdks/python/client/docs/WorkflowServiceApi.md @@ -1112,6 +1112,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -1120,6 +1126,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -5494,6 +5510,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -5502,6 +5524,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -10280,6 +10312,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -10288,6 +10326,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -17053,6 +17101,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -17061,6 +17115,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -18460,6 +18524,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -18468,6 +18538,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -22842,6 +22922,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -22850,6 +22936,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -27628,6 +27724,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -27636,6 +27738,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -29941,6 +30053,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -29949,6 +30067,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -34323,6 +34451,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -34331,6 +34465,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -39109,6 +39253,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -39117,6 +39267,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -45882,6 +46042,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -45890,6 +46056,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -47289,6 +47465,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -47297,6 +47479,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -51671,6 +51863,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -51679,6 +51877,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -56457,6 +56665,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -56465,6 +56679,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ diff --git a/sdks/python/client/docs/WorkflowTemplateServiceApi.md b/sdks/python/client/docs/WorkflowTemplateServiceApi.md index 0f6f82a58ae1..d555b8c0f3d4 100644 --- a/sdks/python/client/docs/WorkflowTemplateServiceApi.md +++ b/sdks/python/client/docs/WorkflowTemplateServiceApi.md @@ -1099,6 +1099,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -1107,6 +1113,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -5481,6 +5497,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -5489,6 +5511,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -10267,6 +10299,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -10275,6 +10313,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -12545,6 +12593,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -12553,6 +12607,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -16927,6 +16991,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -16935,6 +17005,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -21713,6 +21793,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -21721,6 +21807,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -23904,6 +24000,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -23912,6 +24014,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), template_defaults=IoArgoprojWorkflowV1alpha1Template( active_deadline_seconds="active_deadline_seconds_example", @@ -28286,6 +28398,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -28294,6 +28412,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ @@ -33072,6 +33200,12 @@ with argo_workflows.ApiClient(configuration) as api_client: name="name_example", namespace="namespace_example", ), + mutexes=[ + IoArgoprojWorkflowV1alpha1Mutex( + name="name_example", + namespace="namespace_example", + ), + ], semaphore=IoArgoprojWorkflowV1alpha1SemaphoreRef( config_map_key_ref=ConfigMapKeySelector( key="key_example", @@ -33080,6 +33214,16 @@ with argo_workflows.ApiClient(configuration) as api_client: ), namespace="namespace_example", ), + semaphores=[ + IoArgoprojWorkflowV1alpha1SemaphoreRef( + config_map_key_ref=ConfigMapKeySelector( + key="key_example", + name="name_example", + optional=True, + ), + namespace="namespace_example", + ), + ], ), timeout="timeout_example", tolerations=[ diff --git a/test/e2e/functional/synchronization-legacy-mutex-semaphore.yaml b/test/e2e/functional/synchronization-legacy-mutex-semaphore.yaml new file mode 100644 index 000000000000..e74226cf818a --- /dev/null +++ b/test/e2e/functional/synchronization-legacy-mutex-semaphore.yaml @@ -0,0 +1,31 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: synchronization-legacy- +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: task-1 + template: django-command + - name: task-2 + template: load-command + + - name: load-command + synchronization: + mutex: + name: task-1 + container: + image: argoproj/argosay:v2 + args: ["sleep", "2s"] + + - name: django-command + synchronization: + semaphore: + configMapKeyRef: + name: my-config + key: workflow + container: + image: argoproj/argosay:v2 + args: ["sleep", "2s"] diff --git a/test/e2e/functional/synchronization-multiple.yaml b/test/e2e/functional/synchronization-multiple.yaml new file mode 100644 index 000000000000..5293a2a5bb2d --- /dev/null +++ b/test/e2e/functional/synchronization-multiple.yaml @@ -0,0 +1,39 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: synchronization-multiple- +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: task-1 + template: django-command + - name: task-2 + template: load-command + + - name: load-command + synchronization: + mutexes: + - name: load-1 + - name: load-2 + semaphores: + - configMapKeyRef: + name: my-config + key: workflow + container: + image: argoproj/argosay:v2 + args: ["sleep", "2s"] + + - name: django-command + synchronization: + mutexes: + - name: django-1 + - name: django-2 + semaphores: + - configMapKeyRef: + name: my-config + key: workflow + container: + image: argoproj/argosay:v2 + args: ["sleep", "2s"] diff --git a/test/e2e/functional/synchronization-mutex-tmpl-level.yaml b/test/e2e/functional/synchronization-mutex-tmpl-level.yaml index dd6e011941e1..b59836cc0bb2 100644 --- a/test/e2e/functional/synchronization-mutex-tmpl-level.yaml +++ b/test/e2e/functional/synchronization-mutex-tmpl-level.yaml @@ -25,16 +25,16 @@ spec: - name: acquire-lock synchronization: - mutex: - name: welcome + mutexes: + - name: welcome container: image: argoproj/argosay:v2 args: ["sleep", "2s"] - name: acquire-lock-1 synchronization: - mutex: - name: test + mutexes: + - name: test container: image: argoproj/argosay:v2 args: ["sleep", "2s"] \ No newline at end of file diff --git a/test/e2e/functional/synchronization-mutex-wf-level-1.yaml b/test/e2e/functional/synchronization-mutex-wf-level-1.yaml index e55b50f99ab8..84618ec9686a 100644 --- a/test/e2e/functional/synchronization-mutex-wf-level-1.yaml +++ b/test/e2e/functional/synchronization-mutex-wf-level-1.yaml @@ -5,8 +5,8 @@ metadata: spec: entrypoint: main synchronization: - mutex: - name: test + mutexes: + - name: test templates: - name: main container: diff --git a/test/e2e/functional/synchronization-mutex-wf-level.yaml b/test/e2e/functional/synchronization-mutex-wf-level.yaml index 94a0deeaac90..b52dc7771d9c 100644 --- a/test/e2e/functional/synchronization-mutex-wf-level.yaml +++ b/test/e2e/functional/synchronization-mutex-wf-level.yaml @@ -5,8 +5,8 @@ metadata: spec: entrypoint: main synchronization: - mutex: - name: test + mutexes: + - name: test templates: - name: main container: diff --git a/test/e2e/functional/synchronization-tmpl-level-mutex-semaphore.yaml b/test/e2e/functional/synchronization-tmpl-level-mutex-semaphore.yaml index 824a6501bcb3..e4831352b82b 100644 --- a/test/e2e/functional/synchronization-tmpl-level-mutex-semaphore.yaml +++ b/test/e2e/functional/synchronization-tmpl-level-mutex-semaphore.yaml @@ -11,22 +11,24 @@ spec: template: django-command - name: task-2 template: load-command - + - name: load-command synchronization: - mutex: - name: task-1 + mutexes: + - name: task-1 container: image: argoproj/argosay:v2 args: ["sleep", "2s"] - + - name: django-command synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: workflow + mutexes: + - name: task-1 + - name: task-2 + semaphores: + - configMapKeyRef: + name: my-config + key: workflow container: image: argoproj/argosay:v2 args: ["sleep", "2s"] - diff --git a/test/e2e/hooks_test.go b/test/e2e/hooks_test.go index a6442ab8b75e..30912e9ae638 100644 --- a/test/e2e/hooks_test.go +++ b/test/e2e/hooks_test.go @@ -536,8 +536,8 @@ spec: template: sleep - name: sleep synchronization: - mutex: - name: job + mutexes: + - name: job script: image: alpine:latest command: [/bin/sh] diff --git a/test/e2e/semaphore_test.go b/test/e2e/semaphore_test.go index 7cdb6834d58d..d1e41cdf3938 100644 --- a/test/e2e/semaphore_test.go +++ b/test/e2e/semaphore_test.go @@ -81,6 +81,25 @@ func (s *SemaphoreSuite) TestSynchronizationTmplLevelMutexAndSemaphore() { WaitForWorkflow(fixtures.ToBeSucceeded, 90*time.Second) } +func (s *SemaphoreSuite) TestSynchronizationMultiple() { + s.Given(). + Workflow("@functional/synchronization-multiple.yaml"). + When(). + CreateConfigMap("my-config", map[string]string{"workflow": "2"}, map[string]string{}). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeSucceeded, 90*time.Second) +} + +// Legacy CRD entries: mutex and semaphore +func (s *SemaphoreSuite) TestSynchronizationLegacyMutexAndSemaphore() { + s.Given(). + Workflow("@functional/synchronization-legacy-mutex-semaphore.yaml"). + When(). + CreateConfigMap("my-config", map[string]string{"workflow": "1"}, map[string]string{}). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeSucceeded, 90*time.Second) +} + func TestSemaphoreSuite(t *testing.T) { suite.Run(t, new(SemaphoreSuite)) } diff --git a/test/e2e/testdata/semaphore-tmpl-level.yaml b/test/e2e/testdata/semaphore-tmpl-level.yaml index 049c531a1d1a..d4eee390b26f 100644 --- a/test/e2e/testdata/semaphore-tmpl-level.yaml +++ b/test/e2e/testdata/semaphore-tmpl-level.yaml @@ -22,9 +22,9 @@ spec: parameters: - name: seconds synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: template + semaphores: + - configMapKeyRef: + name: my-config + key: template container: image: argoproj/argosay:v2 diff --git a/test/e2e/testdata/semaphore-wf-level-1.yaml b/test/e2e/testdata/semaphore-wf-level-1.yaml index 16bb45c5069a..9f8c1bd88b80 100644 --- a/test/e2e/testdata/semaphore-wf-level-1.yaml +++ b/test/e2e/testdata/semaphore-wf-level-1.yaml @@ -5,10 +5,10 @@ metadata: spec: entrypoint: whalesay synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: workflow + semaphores: + - configMapKeyRef: + name: my-config + key: workflow templates: - name: whalesay container: diff --git a/test/e2e/testdata/semaphore-wf-level.yaml b/test/e2e/testdata/semaphore-wf-level.yaml index 09d99bfd5d7a..765daae2fe52 100644 --- a/test/e2e/testdata/semaphore-wf-level.yaml +++ b/test/e2e/testdata/semaphore-wf-level.yaml @@ -5,10 +5,10 @@ metadata: spec: entrypoint: whalesay synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: workflow + semaphores: + - configMapKeyRef: + name: my-config + key: workflow templates: - name: whalesay container: diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 32a7e2aa57ce..9ede00046354 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -59,7 +59,6 @@ import ( "github.com/argoproj/argo-workflows/v3/workflow/controller/indexes" "github.com/argoproj/argo-workflows/v3/workflow/metrics" "github.com/argoproj/argo-workflows/v3/workflow/progress" - argosync "github.com/argoproj/argo-workflows/v3/workflow/sync" "github.com/argoproj/argo-workflows/v3/workflow/templateresolution" wfutil "github.com/argoproj/argo-workflows/v3/workflow/util" "github.com/argoproj/argo-workflows/v3/workflow/validate" @@ -251,9 +250,9 @@ func (woc *wfOperationCtx) operate(ctx context.Context) { // Workflow Level Synchronization lock if woc.execWf.Spec.Synchronization != nil { - acquired, wfUpdate, msg, err := woc.controller.syncManager.TryAcquire(woc.wf, "", woc.execWf.Spec.Synchronization) + acquired, wfUpdate, msg, failedLockName, err := woc.controller.syncManager.TryAcquire(woc.wf, "", woc.execWf.Spec.Synchronization) if err != nil { - woc.log.Warn("Failed to acquire the lock") + woc.log.Warnf("Failed to acquire the lock %s", failedLockName) woc.markWorkflowFailed(ctx, fmt.Sprintf("Failed to acquire the synchronization lock. %s", err.Error())) return } @@ -1973,7 +1972,7 @@ func (woc *wfOperationCtx) executeTemplate(ctx context.Context, nodeName string, unlockedNode := false if processedTmpl.Synchronization != nil { - lockAcquired, wfUpdated, msg, err := woc.controller.syncManager.TryAcquire(woc.wf, woc.wf.NodeID(nodeName), processedTmpl.Synchronization) + lockAcquired, wfUpdated, msg, failedLockName, err := woc.controller.syncManager.TryAcquire(woc.wf, woc.wf.NodeID(nodeName), processedTmpl.Synchronization) if err != nil { return woc.initializeNodeOrMarkError(node, nodeName, templateScope, orgTmpl, opts.boundaryID, opts.nodeFlag, err), err } @@ -1981,14 +1980,8 @@ func (woc *wfOperationCtx) executeTemplate(ctx context.Context, nodeName string, if node == nil { node = woc.initializeExecutableNode(nodeName, wfutil.GetNodeType(processedTmpl), templateScope, processedTmpl, orgTmpl, opts.boundaryID, wfv1.NodePending, opts.nodeFlag, msg) } - lockName, err := argosync.GetLockName(processedTmpl.Synchronization, woc.wf.Namespace) - if err != nil { - // If an error were to be returned here, it would have been caught by TryAcquire. If it didn't, then it is - // unexpected behavior and is a bug. - panic("bug: GetLockName should not return an error after a call to TryAcquire") - } - woc.log.Infof("Could not acquire lock named: %s", lockName) - return woc.markNodeWaitingForLock(node.Name, lockName.EncodeName()) + woc.log.Infof("Could not acquire lock named: %s", failedLockName) + return woc.markNodeWaitingForLock(node.Name, failedLockName) } else { woc.log.Infof("Node %s acquired synchronization lock", nodeName) if node != nil { diff --git a/workflow/controller/operator_test.go b/workflow/controller/operator_test.go index f6fad1c0852f..19463ab7d09e 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -8512,7 +8512,7 @@ func TestMutexWfPendingWithNoPod(t *testing.T) { ctx := context.Background() controller.syncManager = sync.NewLockManager(GetSyncLimitFunc(ctx, controller.kubeclientset), func(key string) { }, workflowExistenceFunc) - _, _, _, err := controller.syncManager.TryAcquire(wf, "test", &wfv1.Synchronization{Mutex: &wfv1.Mutex{Name: "welcome"}}) + _, _, _, _, err := controller.syncManager.TryAcquire(wf, "test", &wfv1.Synchronization{Mutex: &wfv1.Mutex{Name: "welcome"}}) require.NoError(t, err) woc := newWorkflowOperationCtx(wf, controller) @@ -8521,7 +8521,7 @@ func TestMutexWfPendingWithNoPod(t *testing.T) { assert.Equal(t, wfv1.NodePending, woc.wf.Status.Nodes.FindByDisplayName("hello-world-mpdht").Phase) } -var wfGlopalArtifactNil = `apiVersion: argoproj.io/v1alpha1 +var wfGlobalArtifactNil = `apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: name: global-outputs-ttsfq @@ -8591,7 +8591,7 @@ spec: ` func TestWFGlobalArtifactNil(t *testing.T) { - wf := wfv1.MustUnmarshalWorkflow(wfGlopalArtifactNil) + wf := wfv1.MustUnmarshalWorkflow(wfGlobalArtifactNil) cancel, controller := newController(wf) defer cancel() diff --git a/workflow/sync/common.go b/workflow/sync/common.go index b4a19e9c5c84..182bf2ca07b7 100644 --- a/workflow/sync/common.go +++ b/workflow/sync/common.go @@ -2,8 +2,9 @@ package sync import "time" -type Semaphore interface { +type semaphore interface { acquire(holderKey string) bool + checkAcquire(holderKey string) (bool, bool, string) tryAcquire(holderKey string) (bool, string) release(key string) bool addToQueue(holderKey string, priority int32, creationTime time.Time) diff --git a/workflow/sync/lock_name.go b/workflow/sync/lock_name.go index 248d7e41b8d3..41d9902af8e1 100644 --- a/workflow/sync/lock_name.go +++ b/workflow/sync/lock_name.go @@ -8,22 +8,22 @@ import ( "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" ) -type LockKind string +type lockKind string const ( - LockKindConfigMap LockKind = "ConfigMap" - LockKindMutex LockKind = "Mutex" + lockKindConfigMap lockKind = "ConfigMap" + lockKindMutex lockKind = "Mutex" ) -type LockName struct { +type lockName struct { Namespace string ResourceName string Key string - Kind LockKind + Kind lockKind } -func NewLockName(namespace, resourceName, lockKey string, kind LockKind) *LockName { - return &LockName{ +func newLockName(namespace, resourceName, lockKey string, kind lockKind) *lockName { + return &lockName{ Namespace: namespace, ResourceName: resourceName, Key: lockKey, @@ -31,68 +31,76 @@ func NewLockName(namespace, resourceName, lockKey string, kind LockKind) *LockNa } } -func GetLockName(sync *v1alpha1.Synchronization, wfNamespace string) (*LockName, error) { - switch sync.GetType() { - case v1alpha1.SynchronizationTypeSemaphore: - if sync.Semaphore.ConfigMapKeyRef != nil { - namespace := sync.Semaphore.Namespace - if namespace == "" { - namespace = wfNamespace - } - return NewLockName(namespace, sync.Semaphore.ConfigMapKeyRef.Name, sync.Semaphore.ConfigMapKeyRef.Key, LockKindConfigMap), nil - } - return nil, fmt.Errorf("cannot get LockName for a Semaphore without a ConfigMapRef") - case v1alpha1.SynchronizationTypeMutex: - namespace := sync.Mutex.Namespace +func getSemaphoreLockName(sem *v1alpha1.SemaphoreRef, wfNamespace string) (*lockName, error) { + if sem.ConfigMapKeyRef != nil { + namespace := sem.Namespace if namespace == "" { namespace = wfNamespace } - return NewLockName(namespace, sync.Mutex.Name, "", LockKindMutex), nil + return newLockName(namespace, sem.ConfigMapKeyRef.Name, sem.ConfigMapKeyRef.Key, lockKindConfigMap), nil + } + return nil, fmt.Errorf("cannot get LockName for a Semaphore without a ConfigMapRef") +} + +func getMutexLockName(mtx *v1alpha1.Mutex, wfNamespace string) *lockName { + namespace := mtx.Namespace + if namespace == "" { + namespace = wfNamespace + } + return newLockName(namespace, mtx.Name, "", lockKindMutex) +} + +func getLockName(item *syncItem, wfNamespace string) (*lockName, error) { + switch { + case item.semaphore != nil: + return getSemaphoreLockName(item.semaphore, wfNamespace) + case item.mutex != nil: + return getMutexLockName(item.mutex, wfNamespace), nil default: - return nil, fmt.Errorf("cannot get LockName for a Sync of Unknown type") + return nil, fmt.Errorf("cannot getLockName if not semaphore or mutex") } } -func DecodeLockName(lockName string) (*LockName, error) { - items := strings.SplitN(lockName, "/", 3) +func DecodeLockName(name string) (*lockName, error) { + items := strings.SplitN(name, "/", 3) if len(items) < 3 { return nil, errors.New(errors.CodeBadRequest, "Invalid lock key: unknown format") } - var lock LockName - lockKind := LockKind(items[1]) + var lock lockName + lockKind := lockKind(items[1]) namespace := items[0] switch lockKind { - case LockKindMutex: - lock = LockName{Namespace: namespace, Kind: lockKind, ResourceName: items[2]} - case LockKindConfigMap: + case lockKindMutex: + lock = lockName{Namespace: namespace, Kind: lockKind, ResourceName: items[2]} + case lockKindConfigMap: components := strings.Split(items[2], "/") if len(components) != 2 { return nil, errors.New(errors.CodeBadRequest, "Invalid ConfigMap lock key: unknown format") } - lock = LockName{Namespace: namespace, Kind: lockKind, ResourceName: components[0], Key: components[1]} + lock = lockName{Namespace: namespace, Kind: lockKind, ResourceName: components[0], Key: components[1]} default: return nil, errors.New(errors.CodeBadRequest, fmt.Sprintf("Invalid lock key, unexpected kind: %s", lockKind)) } - err := lock.Validate() + err := lock.validate() if err != nil { return nil, err } return &lock, nil } -func (ln *LockName) EncodeName() string { - if ln.Kind == LockKindMutex { - return ln.ValidateEncoding(fmt.Sprintf("%s/%s/%s", ln.Namespace, ln.Kind, ln.ResourceName)) +func (ln *lockName) encodeName() string { + if ln.Kind == lockKindMutex { + return ln.validateEncoding(fmt.Sprintf("%s/%s/%s", ln.Namespace, ln.Kind, ln.ResourceName)) } - return ln.ValidateEncoding(fmt.Sprintf("%s/%s/%s/%s", ln.Namespace, ln.Kind, ln.ResourceName, ln.Key)) + return ln.validateEncoding(fmt.Sprintf("%s/%s/%s/%s", ln.Namespace, ln.Kind, ln.ResourceName, ln.Key)) } -func (ln *LockName) Validate() error { +func (ln *lockName) validate() error { if ln.Namespace == "" { return errors.New(errors.CodeBadRequest, "Invalid lock key: Namespace is missing") } @@ -102,13 +110,13 @@ func (ln *LockName) Validate() error { if ln.ResourceName == "" { return errors.New(errors.CodeBadRequest, "Invalid lock key: ResourceName is missing") } - if ln.Kind == LockKindConfigMap && ln.Key == "" { + if ln.Kind == lockKindConfigMap && ln.Key == "" { return errors.New(errors.CodeBadRequest, "Invalid lock key: Key is missing for ConfigMap lock") } return nil } -func (ln *LockName) ValidateEncoding(encoding string) string { +func (ln *lockName) validateEncoding(encoding string) string { decoded, err := DecodeLockName(encoding) if err != nil { panic(fmt.Sprintf("bug: unable to decode lock that was just encoded: %s", err)) diff --git a/workflow/sync/lock_name_test.go b/workflow/sync/lock_name_test.go index 7eef8d03189b..559c2becdefb 100644 --- a/workflow/sync/lock_name_test.go +++ b/workflow/sync/lock_name_test.go @@ -14,17 +14,17 @@ func TestDecodeLockName(t *testing.T) { tests := []struct { name string args args - want *LockName + want *lockName wantErr assert.ErrorAssertionFunc }{ { "TestMutexLockNameValidation", args{"default/Mutex/test"}, - &LockName{ + &lockName{ Namespace: "default", ResourceName: "test", Key: "", - Kind: LockKindMutex, + Kind: lockKindMutex, }, func(t assert.TestingT, err error, i ...interface{}) bool { return true @@ -33,11 +33,11 @@ func TestDecodeLockName(t *testing.T) { { "TestMutexLocksCanContainSlashes", args{"default/Mutex/test/foo/bar/baz"}, - &LockName{ + &lockName{ Namespace: "default", ResourceName: "test/foo/bar/baz", Key: "", - Kind: LockKindMutex, + Kind: lockKindMutex, }, func(t assert.TestingT, err error, i ...interface{}) bool { return true @@ -46,11 +46,11 @@ func TestDecodeLockName(t *testing.T) { { "TestConfigMapLockNamesWork", args{"default/ConfigMap/foo/bar"}, - &LockName{ + &lockName{ Namespace: "default", ResourceName: "foo", Key: "bar", - Kind: LockKindConfigMap, + Kind: lockKindConfigMap, }, func(t assert.TestingT, err error, i ...interface{}) bool { return true @@ -68,11 +68,11 @@ func TestDecodeLockName(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := DecodeLockName(tt.args.lockName) - if !tt.wantErr(t, err, fmt.Sprintf("DecodeLockName(%v)", tt.args.lockName)) { + if !tt.wantErr(t, err, fmt.Sprintf("decodeLockName(%v)", tt.args.lockName)) { return } - assert.Equalf(t, tt.want, got, "DecodeLockName(%v)", tt.args.lockName) - got.ValidateEncoding(tt.args.lockName) + assert.Equalf(t, tt.want, got, "decodeLockName(%v)", tt.args.lockName) + got.validateEncoding(tt.args.lockName) }) } } diff --git a/workflow/sync/multiple_test.go b/workflow/sync/multiple_test.go new file mode 100644 index 000000000000..cfe33e3514ee --- /dev/null +++ b/workflow/sync/multiple_test.go @@ -0,0 +1,424 @@ +package sync + +import ( + "context" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes/fake" + "k8s.io/utils/pointer" + + wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" +) + +var wfTmpl = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: %s + namespace: default +spec: + entrypoint: whalesay + synchronization: +%s + templates: + - name: whalesay + container: + image: docker/whalesay:latest + command: [cowsay] + args: ["hello world"] +` + +func templatedWorkflow(name string, syncBlock string) *wfv1.Workflow { + return wfv1.MustUnmarshalWorkflow(fmt.Sprintf(wfTmpl, name, syncBlock)) +} + +func TestMultipleMutexLock(t *testing.T) { + kube := fake.NewSimpleClientset() + syncLimitFunc := GetSyncLimitFunc(kube) + t.Run("MultipleMutex", func(t *testing.T) { + syncManager := NewLockManager(syncLimitFunc, func(key string) {}, + WorkflowExistenceFunc) + wfall := templatedWorkflow("all", + ` mutexes: + - name: one + - name: two + - name: three +`) + wf1 := templatedWorkflow("one", + ` mutexes: + - name: one +`) + wf2 := templatedWorkflow("two", + ` mutexes: + - name: two +`) + wf3 := templatedWorkflow("three", + ` mutexes: + - name: three +`) + // Acquire 1 + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Acquire 2 + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Acquire 3 + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf3, "", wf3.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Fail to acquire because one locked + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfall, "", wfall.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/one", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + syncManager.ReleaseAll(wf1) + // Fail to acquire because two locked + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfall, "", wfall.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/two", failedLockName) + assert.False(t, status) + assert.False(t, wfUpdate) + + syncManager.ReleaseAll(wf2) + // Fail to acquire because three locked + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfall, "", wfall.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/three", failedLockName) + assert.False(t, status) + assert.False(t, wfUpdate) + + syncManager.ReleaseAll(wf3) + // Now lock + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfall, "", wfall.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + }) + t.Run("MultipleMutexOrdering", func(t *testing.T) { + syncManager := NewLockManager(syncLimitFunc, func(key string) {}, + WorkflowExistenceFunc) + wfall := templatedWorkflow("all", + ` mutexes: + - name: one + - name: two + - name: three +`) + // Old style single mutex + wf1 := templatedWorkflow("one", + ` mutex: + name: one +`) + wf2 := templatedWorkflow("two", + ` mutexes: + - name: two +`) + // Acquire 1 + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Fail to acquire because one locked + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfall, "", wfall.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/one", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + // Attempt 2, but blocked by all + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/two", failedLockName) + assert.False(t, status) + assert.False(t, wfUpdate) + + // Fail to acquire because one locked + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfall, "", wfall.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/one", failedLockName) + assert.False(t, status) + assert.False(t, wfUpdate) + + syncManager.ReleaseAll(wf1) + syncManager.ReleaseAll(wf2) + + // Now lock + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfall, "", wfall.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + }) +} + +const multipleConfigMap = ` +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-config +data: + double: "2" +` + +func TestMutexAndSemaphore(t *testing.T) { + kube := fake.NewSimpleClientset() + var cm v1.ConfigMap + wfv1.MustUnmarshal([]byte(multipleConfigMap), &cm) + + ctx := context.Background() + _, err := kube.CoreV1().ConfigMaps("default").Create(ctx, &cm, metav1.CreateOptions{}) + require.NoError(t, err) + + syncLimitFunc := GetSyncLimitFunc(kube) + t.Run("MutexSemaphore", func(t *testing.T) { + syncManager := NewLockManager(syncLimitFunc, func(key string) {}, + WorkflowExistenceFunc) + wfmands1 := templatedWorkflow("mands1", + ` mutexes: + - name: one + semaphores: + - configMapKeyRef: + key: double + name: my-config +`) + wfmands1copy := wfmands1.DeepCopy() + wfmands2 := templatedWorkflow("mands2", + ` mutex: + name: two + semaphore: + configMapKeyRef: + key: double + name: my-config +`) + wf1 := templatedWorkflow("one", + ` mutexes: + - name: one +`) + wf2 := templatedWorkflow("two", + ` mutexes: + - name: two +`) + wfsem := templatedWorkflow("three", + ` semaphores: + - configMapKeyRef: + key: double + name: my-config +`) + // Acquire sem + 1 + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wfmands1, "", wfmands1.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Acquire sem + 2 + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfmands2, "", wfmands2.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Fail 1 + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/one", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + // Fail 2 + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/two", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + // Fail sem + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfsem, "", wfsem.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/double", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + // Release 1 and sem + syncManager.ReleaseAll(wfmands1) + + // Succeed 1 + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Fail 2 + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/two", failedLockName) + assert.False(t, status) + assert.False(t, wfUpdate) + + // Succeed sem + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfsem, "", wfsem.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + syncManager.ReleaseAll(wf1) + syncManager.ReleaseAll(wfsem) + + // And reacquire in a sem+mutex wf + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfmands1copy, "", wfmands1copy.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + }) +} +func TestPriority(t *testing.T) { + kube := fake.NewSimpleClientset() + syncLimitFunc := GetSyncLimitFunc(kube) + t.Run("Priority", func(t *testing.T) { + syncManager := NewLockManager(syncLimitFunc, func(key string) {}, + WorkflowExistenceFunc) + wflow := templatedWorkflow("prioritylow", + ` mutexes: + - name: one + - name: two +`) + wfhigh := wflow.DeepCopy() + wfhigh.Name = "priorityhigh" + wfhigh.Spec.Priority = pointer.Int32(5) + wf1 := templatedWorkflow("one", + ` mutexes: + - name: two +`) + // wf2 takes mutex two + wf2 := templatedWorkflow("two", + ` mutexes: + - name: two +`) + // Acquire 1 + 2 as low + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wflow, "", wflow.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + + // Attempt to acquire 2, fail + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/two", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + // Attempt get 1 + 2 as high but fail + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfhigh, "", wfhigh.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/one", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + // Attempt to acquire 2 again as two, fail + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/two", failedLockName) + assert.False(t, status) + assert.True(t, wfUpdate) + + // Release locks + syncManager.ReleaseAll(wflow) + + // Attempt to acquire 2 again, but priority blocks + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) + require.NoError(t, err) + assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/two", failedLockName) + assert.False(t, status) + assert.False(t, wfUpdate) + + // Attempt get 1 + 2 as high and priority succeeds + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wfhigh, "", wfhigh.Spec.Synchronization) + require.NoError(t, err) + assert.Empty(t, msg) + assert.Empty(t, failedLockName) + assert.True(t, status) + assert.True(t, wfUpdate) + }) +} + +func TestDuplicates(t *testing.T) { + kube := fake.NewSimpleClientset() + syncLimitFunc := GetSyncLimitFunc(kube) + t.Run("Mutex", func(t *testing.T) { + syncManager := NewLockManager(syncLimitFunc, func(key string) {}, + WorkflowExistenceFunc) + wfdupmutex := templatedWorkflow("mutex", + ` mutexes: + - name: one + - name: one +`) + _, _, _, _, err := syncManager.TryAcquire(wfdupmutex, "", wfdupmutex.Spec.Synchronization) + assert.Error(t, err) + }) + t.Run("Semaphore", func(t *testing.T) { + syncManager := NewLockManager(syncLimitFunc, func(key string) {}, + WorkflowExistenceFunc) + wfdupsemaphore := templatedWorkflow("semaphore", + ` semaphores: + - configMapKeyRef: + key: double + name: my-config + - configMapKeyRef: + key: double + name: my-config +`) + _, _, _, _, err := syncManager.TryAcquire(wfdupsemaphore, "", wfdupsemaphore.Spec.Synchronization) + assert.Error(t, err) + }) +} diff --git a/workflow/sync/mutex.go b/workflow/sync/mutex.go index ab90d305088d..c2c86fdc1ff1 100644 --- a/workflow/sync/mutex.go +++ b/workflow/sync/mutex.go @@ -1,6 +1,6 @@ package sync // NewMutex creates a size 1 semaphore -func NewMutex(name string, nextWorkflow NextWorkflow) *PrioritySemaphore { +func NewMutex(name string, nextWorkflow NextWorkflow) *prioritySemaphore { return NewSemaphore(name, 1, nextWorkflow, "mutex") } diff --git a/workflow/sync/mutex_test.go b/workflow/sync/mutex_test.go index 33be3daf52ac..fc3e5e19d95f 100644 --- a/workflow/sync/mutex_test.go +++ b/workflow/sync/mutex_test.go @@ -73,8 +73,7 @@ spec: mutex: name: test templates: - - - container: + - container: args: - hello world command: @@ -114,7 +113,7 @@ func TestMutexLock(t *testing.T) { kube := fake.NewSimpleClientset() syncLimitFunc := GetSyncLimitFunc(kube) t.Run("InitializeSynchronization", func(t *testing.T) { - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(mutexwfstatus) wfclientset := fakewfclientset.NewSimpleClientset(wf) @@ -122,115 +121,125 @@ func TestMutexLock(t *testing.T) { ctx := context.Background() wfList, err := wfclientset.ArgoprojV1alpha1().Workflows("default").List(ctx, metav1.ListOptions{}) require.NoError(t, err) - concurrenyMgr.Initialize(wfList.Items) - assert.Len(t, concurrenyMgr.syncLockMap, 1) + syncManager.Initialize(wfList.Items) + assert.Len(t, syncManager.syncLockMap, 1) }) t.Run("WfLevelMutexAcquireAndRelease", func(t *testing.T) { var nextWorkflow string - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { nextWorkflow = key }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(mutexWf) wf1 := wf.DeepCopy() wf2 := wf.DeepCopy() wf3 := wf.DeepCopy() - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Mutex) - assert.NotNil(t, wf.Status.Synchronization.Mutex.Holding) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Mutex) + require.NotNil(t, wf.Status.Synchronization.Mutex.Holding) assert.Equal(t, getHolderKey(wf, ""), wf.Status.Synchronization.Mutex.Holding[0].Holder) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.True(t, status) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.False(t, wfUpdate) wf1.Name = "two" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/test", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) wf2.Name = "three" wf2.Spec.Priority = ptr.To(int32(5)) holderKey2 := getHolderKey(wf2, "") - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/test", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) wf3.Name = "four" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf3, "", wf3.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf3, "", wf3.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/test", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) - concurrenyMgr.Release(wf, "", wf.Spec.Synchronization) + syncManager.Release(wf, "", wf.Spec.Synchronization) assert.Equal(t, holderKey2, nextWorkflow) - assert.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization) assert.Empty(t, wf.Status.Synchronization.Mutex.Holding) // Low priority workflow try to acquire the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/test", failedLockName) assert.False(t, status) assert.False(t, wfUpdate) // High Priority workflow acquires the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf2.Status.Synchronization) - assert.NotNil(t, wf2.Status.Synchronization.Mutex) + require.NotNil(t, wf2.Status.Synchronization) + require.NotNil(t, wf2.Status.Synchronization.Mutex) assert.Equal(t, getHolderKey(wf2, ""), wf2.Status.Synchronization.Mutex.Holding[0].Holder) - concurrenyMgr.ReleaseAll(wf2) + syncManager.ReleaseAll(wf2) assert.Nil(t, wf2.Status.Synchronization) }) t.Run("WfLevelMutexOthernamespace", func(t *testing.T) { var nextWorkflow string - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { nextWorkflow = key }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(mutexWfNamespaced) wf1 := wf.DeepCopy() wf2 := wf.DeepCopy() wf3 := wf.DeepCopy() - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Mutex) - assert.NotNil(t, wf.Status.Synchronization.Mutex.Holding) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Mutex) + require.NotNil(t, wf.Status.Synchronization.Mutex.Holding) expected := getHolderKey(wf, "") assert.Equal(t, expected, wf.Status.Synchronization.Mutex.Holding[0].Holder) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.True(t, status) + assert.Empty(t, failedLockName) assert.Empty(t, msg) assert.False(t, wfUpdate) wf1.Name = "two" wf1.Namespace = "two" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "other/Mutex/test", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) @@ -238,43 +247,47 @@ func TestMutexLock(t *testing.T) { wf2.Namespace = "three" wf2.Spec.Priority = ptr.To(int32(5)) holderKey2 := getHolderKey(wf2, "") - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "other/Mutex/test", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) wf3.Name = "four" wf3.Namespace = "four" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf3, "", wf3.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf3, "", wf3.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "other/Mutex/test", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) - concurrenyMgr.Release(wf, "", wf.Spec.Synchronization) + syncManager.Release(wf, "", wf.Spec.Synchronization) assert.Equal(t, holderKey2, nextWorkflow) - assert.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization) assert.Empty(t, wf.Status.Synchronization.Mutex.Holding) // Low priority workflow try to acquire the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "other/Mutex/test", failedLockName) assert.False(t, status) assert.False(t, wfUpdate) // High Priority workflow acquires the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf2.Status.Synchronization) - assert.NotNil(t, wf2.Status.Synchronization.Mutex) + require.NotNil(t, wf2.Status.Synchronization) + require.NotNil(t, wf2.Status.Synchronization.Mutex) expected = getHolderKey(wf2, "") assert.Equal(t, expected, wf2.Status.Synchronization.Mutex.Holding[0].Holder) - concurrenyMgr.ReleaseAll(wf2) + syncManager.ReleaseAll(wf2) assert.Nil(t, wf2.Status.Synchronization) }) } @@ -384,56 +397,60 @@ func TestMutexTmplLevel(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) t.Run("TemplateLevelAcquireAndRelease", func(t *testing.T) { // var nextKey string - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { // nextKey = key }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(mutexWfWithTmplLevel) tmpl := wf.Spec.Templates[1] - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474", tmpl.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Mutex) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Mutex) expected := getHolderKey(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474") assert.Equal(t, expected, wf.Status.Synchronization.Mutex.Holding[0].Holder) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-2216915482", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-2216915482", tmpl.Synchronization) require.NoError(t, err) assert.True(t, wfUpdate) + assert.Equal(t, "default/Mutex/welcome", failedLockName) assert.False(t, status) assert.NotEmpty(t, msg) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-1432992664", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-1432992664", tmpl.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/welcome", failedLockName) assert.False(t, wfUpdate) assert.False(t, status) expected = getHolderKey(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474") assert.Equal(t, expected, wf.Status.Synchronization.Mutex.Holding[0].Holder) - concurrenyMgr.Release(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474", tmpl.Synchronization) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Mutex) + syncManager.Release(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474", tmpl.Synchronization) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Mutex) assert.Empty(t, wf.Status.Synchronization.Mutex.Holding) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-2216915482", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-2216915482", tmpl.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Mutex) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Mutex) expected = getHolderKey(wf, "synchronization-tmpl-level-mutex-vjcdk-2216915482") assert.Equal(t, expected, wf.Status.Synchronization.Mutex.Holding[0].Holder) assert.NotEqual(t, "synchronization-tmpl-level-mutex-vjcdk-3941195474", wf.Status.Synchronization.Mutex.Holding[0].Holder) - concurrenyMgr.Release(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474", tmpl.Synchronization) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Mutex) + syncManager.Release(wf, "synchronization-tmpl-level-mutex-vjcdk-3941195474", tmpl.Synchronization) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Mutex) assert.NotEmpty(t, wf.Status.Synchronization.Mutex.Holding) }) } diff --git a/workflow/sync/semaphore.go b/workflow/sync/semaphore.go index 63be7239ddeb..fe97e6d29538 100644 --- a/workflow/sync/semaphore.go +++ b/workflow/sync/semaphore.go @@ -3,34 +3,31 @@ package sync import ( "fmt" "strings" - "sync" "time" log "github.com/sirupsen/logrus" sema "golang.org/x/sync/semaphore" ) -type PrioritySemaphore struct { +type prioritySemaphore struct { name string limit int pending *priorityQueue semaphore *sema.Weighted lockHolder map[string]bool - lock *sync.Mutex nextWorkflow NextWorkflow log *log.Entry } -var _ Semaphore = &PrioritySemaphore{} +var _ semaphore = &prioritySemaphore{} -func NewSemaphore(name string, limit int, nextWorkflow NextWorkflow, lockType string) *PrioritySemaphore { - return &PrioritySemaphore{ +func NewSemaphore(name string, limit int, nextWorkflow NextWorkflow, lockType string) *prioritySemaphore { + return &prioritySemaphore{ name: name, limit: limit, pending: &priorityQueue{itemByKey: make(map[string]*item)}, semaphore: sema.NewWeighted(int64(limit)), lockHolder: make(map[string]bool), - lock: &sync.Mutex{}, nextWorkflow: nextWorkflow, log: log.WithFields(log.Fields{ lockType: name, @@ -38,15 +35,15 @@ func NewSemaphore(name string, limit int, nextWorkflow NextWorkflow, lockType st } } -func (s *PrioritySemaphore) getName() string { +func (s *prioritySemaphore) getName() string { return s.name } -func (s *PrioritySemaphore) getLimit() int { +func (s *prioritySemaphore) getLimit() int { return s.limit } -func (s *PrioritySemaphore) getCurrentPending() []string { +func (s *prioritySemaphore) getCurrentPending() []string { var keys []string for _, item := range s.pending.items { keys = append(keys, item.key) @@ -54,7 +51,7 @@ func (s *PrioritySemaphore) getCurrentPending() []string { return keys } -func (s *PrioritySemaphore) getCurrentHolders() []string { +func (s *prioritySemaphore) getCurrentHolders() []string { var keys []string for k := range s.lockHolder { keys = append(keys, k) @@ -62,10 +59,7 @@ func (s *PrioritySemaphore) getCurrentHolders() []string { return keys } -func (s *PrioritySemaphore) resize(n int) bool { - s.lock.Lock() - defer s.lock.Unlock() - +func (s *prioritySemaphore) resize(n int) bool { cur := len(s.lockHolder) // downward case, acquired n locks if cur > n { @@ -82,9 +76,7 @@ func (s *PrioritySemaphore) resize(n int) bool { return status } -func (s *PrioritySemaphore) release(key string) bool { - s.lock.Lock() - defer s.lock.Unlock() +func (s *prioritySemaphore) release(key string) bool { if _, ok := s.lockHolder[key]; ok { delete(s.lockHolder, key) // When semaphore resized downward @@ -105,7 +97,7 @@ func (s *PrioritySemaphore) release(key string) bool { // notifyWaiters enqueues the next N workflows who are waiting for the semaphore to the workqueue, // where N is the availability of the semaphore. If semaphore is out of capacity, this does nothing. -func (s *PrioritySemaphore) notifyWaiters() { +func (s *prioritySemaphore) notifyWaiters() { triggerCount := s.limit - len(s.lockHolder) if s.pending.Len() < triggerCount { triggerCount = s.pending.Len() @@ -130,10 +122,7 @@ func workflowKey(i *item) string { } // addToQueue adds the holderkey into priority queue that maintains the priority order to acquire the lock. -func (s *PrioritySemaphore) addToQueue(holderKey string, priority int32, creationTime time.Time) { - s.lock.Lock() - defer s.lock.Unlock() - +func (s *prioritySemaphore) addToQueue(holderKey string, priority int32, creationTime time.Time) { if _, ok := s.lockHolder[holderKey]; ok { s.log.Debugf("Lock is already acquired by %s", holderKey) return @@ -143,15 +132,12 @@ func (s *PrioritySemaphore) addToQueue(holderKey string, priority int32, creatio s.log.Debugf("Added into queue: %s", holderKey) } -func (s *PrioritySemaphore) removeFromQueue(holderKey string) { - s.lock.Lock() - defer s.lock.Unlock() - +func (s *prioritySemaphore) removeFromQueue(holderKey string) { s.pending.remove(holderKey) s.log.Debugf("Removed from queue: %s", holderKey) } -func (s *PrioritySemaphore) acquire(holderKey string) bool { +func (s *prioritySemaphore) acquire(holderKey string) bool { if s.semaphore.TryAcquire(1) { s.lockHolder[holderKey] = true return true @@ -170,15 +156,22 @@ func isSameWorkflowNodeKeys(firstKey, secondKey string) bool { return firstItems[1] == secondItems[1] } -func (s *PrioritySemaphore) tryAcquire(holderKey string) (bool, string) { - s.lock.Lock() - defer s.lock.Unlock() +// checkAcquire examines if tryAcquire would succeed +// returns +// +// true, false if we would be able to take the lock +// false, true if we already have the lock +// false, false if the lock is not acquirable +// string return is a user facing message when not acquirable +func (s *prioritySemaphore) checkAcquire(holderKey string) (bool, bool, string) { + if holderKey == "" { + return false, false, "bug: attempt to check semaphore with empty holder key" + } if _, ok := s.lockHolder[holderKey]; ok { s.log.Debugf("%s is already holding a lock", holderKey) - return true, "" + return false, true, "" } - var nextKey string waitingMsg := fmt.Sprintf("Waiting for %s lock. Lock status: %d/%d", s.name, s.limit-len(s.lockHolder), s.limit) @@ -187,15 +180,32 @@ func (s *PrioritySemaphore) tryAcquire(holderKey string) (bool, string) { // If it is not a front key, it needs to wait for its turn. if s.pending.Len() > 0 { item := s.pending.peek() - if holderKey != nextKey && !isSameWorkflowNodeKeys(holderKey, item.key) { + if !isSameWorkflowNodeKeys(holderKey, item.key) { // Enqueue the front workflow if lock is available if len(s.lockHolder) < s.limit { s.nextWorkflow(workflowKey(item)) } - return false, waitingMsg + s.log.Infof("%s isn't at the front", holderKey) + return false, false, waitingMsg } } + if s.semaphore.TryAcquire(1) { + s.semaphore.Release(1) + return true, false, "" + } + + s.log.Debugf("Current semaphore Holders. %v", s.lockHolder) + return false, false, waitingMsg +} +func (s *prioritySemaphore) tryAcquire(holderKey string) (bool, string) { + acq, already, msg := s.checkAcquire(holderKey) + if already { + return true, msg + } + if !acq { + return false, msg + } if s.acquire(holderKey) { s.pending.pop() s.log.Infof("%s acquired by %s. Lock availability: %d/%d", s.name, holderKey, s.limit-len(s.lockHolder), s.limit) @@ -203,5 +213,5 @@ func (s *PrioritySemaphore) tryAcquire(holderKey string) (bool, string) { return true, "" } s.log.Debugf("Current semaphore Holders. %v", s.lockHolder) - return false, waitingMsg + return false, msg } diff --git a/workflow/sync/sync_manager.go b/workflow/sync/sync_manager.go index 40f874c6b390..fccf99857065 100644 --- a/workflow/sync/sync_manager.go +++ b/workflow/sync/sync_manager.go @@ -18,7 +18,7 @@ type ( ) type Manager struct { - syncLockMap map[string]Semaphore + syncLockMap map[string]semaphore lock *sync.Mutex nextWorkflow NextWorkflow getSyncLimit GetSyncLimit @@ -27,7 +27,7 @@ type Manager struct { func NewLockManager(getSyncLimit GetSyncLimit, nextWorkflow NextWorkflow, isWFDeleted IsWorkflowDeleted) *Manager { return &Manager{ - syncLockMap: make(map[string]Semaphore), + syncLockMap: make(map[string]semaphore), lock: &sync.Mutex{}, nextWorkflow: nextWorkflow, getSyncLimit: getSyncLimit, @@ -35,7 +35,7 @@ func NewLockManager(getSyncLimit GetSyncLimit, nextWorkflow NextWorkflow, isWFDe } } -func (cm *Manager) getWorkflowKey(key string) (string, error) { +func (sm *Manager) getWorkflowKey(key string) (string, error) { if key == "" { return "", fmt.Errorf("holderkey is empty") } @@ -46,19 +46,19 @@ func (cm *Manager) getWorkflowKey(key string) (string, error) { return fmt.Sprintf("%s/%s", items[0], items[1]), nil } -func (cm *Manager) CheckWorkflowExistence() { +func (sm *Manager) CheckWorkflowExistence() { defer runtimeutil.HandleCrash(runtimeutil.PanicHandlers...) log.Debug("Check the workflow existence") - for _, lock := range cm.syncLockMap { + for _, lock := range sm.syncLockMap { keys := lock.getCurrentHolders() keys = append(keys, lock.getCurrentPending()...) for _, holderKeys := range keys { - wfKey, err := cm.getWorkflowKey(holderKeys) + wfKey, err := sm.getWorkflowKey(holderKeys) if err != nil { continue } - if !cm.isWFDeleted(wfKey) { + if !sm.isWFDeleted(wfKey) { lock.release(holderKeys) lock.removeFromQueue(holderKeys) } @@ -107,27 +107,39 @@ const ( // due to ambiguity. Currently we just assume workflow level. func getWorkflowSyncLevelByName(wf *wfv1.Workflow, lockName string) (SyncLevelType, error) { if wf.Spec.Synchronization != nil { - syncLockName, err := GetLockName(wf.Spec.Synchronization, wf.Namespace) + syncItems, err := allSyncItems(wf.Spec.Synchronization) if err != nil { return ErrorLevel, err } - checkName := syncLockName.EncodeName() - if lockName == checkName { - return WorkflowLevel, nil + for _, syncItem := range syncItems { + syncLockName, err := getLockName(syncItem, wf.Namespace) + if err != nil { + return ErrorLevel, err + } + checkName := syncLockName.encodeName() + if lockName == checkName { + return WorkflowLevel, nil + } } } var lastErr error for _, template := range wf.Spec.Templates { if template.Synchronization != nil { - syncLockName, err := GetLockName(template.Synchronization, wf.Namespace) + syncItems, err := allSyncItems(template.Synchronization) if err != nil { - lastErr = err - continue + return ErrorLevel, err } - checkName := syncLockName.EncodeName() - if lockName == checkName { - return TemplateLevel, nil + for _, syncItem := range syncItems { + syncLockName, err := getLockName(syncItem, wf.Namespace) + if err != nil { + lastErr = err + continue + } + checkName := syncLockName.encodeName() + if lockName == checkName { + return TemplateLevel, nil + } } } } @@ -137,7 +149,7 @@ func getWorkflowSyncLevelByName(wf *wfv1.Workflow, lockName string) (SyncLevelTy return ErrorLevel, lastErr } -func (cm *Manager) Initialize(wfs []wfv1.Workflow) { +func (sm *Manager) Initialize(wfs []wfv1.Workflow) { for _, wf := range wfs { if wf.Status.Synchronization == nil { continue @@ -145,15 +157,14 @@ func (cm *Manager) Initialize(wfs []wfv1.Workflow) { if wf.Status.Synchronization.Semaphore != nil { for _, holding := range wf.Status.Synchronization.Semaphore.Holding { - - semaphore := cm.syncLockMap[holding.Semaphore] + semaphore := sm.syncLockMap[holding.Semaphore] if semaphore == nil { - semaphore, err := cm.initializeSemaphore(holding.Semaphore) + semaphore, err := sm.initializeSemaphore(holding.Semaphore) if err != nil { log.Warnf("cannot initialize semaphore '%s': %v", holding.Semaphore, err) continue } - cm.syncLockMap[holding.Semaphore] = semaphore + sm.syncLockMap[holding.Semaphore] = semaphore } for _, holders := range holding.Holders { @@ -173,10 +184,9 @@ func (cm *Manager) Initialize(wfs []wfv1.Workflow) { if wf.Status.Synchronization.Mutex != nil { for _, holding := range wf.Status.Synchronization.Mutex.Holding { - - mutex := cm.syncLockMap[holding.Mutex] + mutex := sm.syncLockMap[holding.Mutex] if mutex == nil { - mutex := cm.initializeMutex(holding.Mutex) + mutex := sm.initializeMutex(holding.Mutex) if holding.Holder != "" { level, err := getWorkflowSyncLevelByName(&wf, holding.Mutex) if err != nil { @@ -186,7 +196,7 @@ func (cm *Manager) Initialize(wfs []wfv1.Workflow) { key := getUpgradedKey(&wf, holding.Holder, level) mutex.acquire(key) } - cm.syncLockMap[holding.Mutex] = mutex + sm.syncLockMap[holding.Mutex] = mutex } } } @@ -195,94 +205,138 @@ func (cm *Manager) Initialize(wfs []wfv1.Workflow) { } // TryAcquire tries to acquire the lock from semaphore. -// It returns status of acquiring a lock , status of Workflow status updated, waiting message if lock is not available and any error encountered -func (cm *Manager) TryAcquire(wf *wfv1.Workflow, nodeName string, syncLockRef *wfv1.Synchronization) (bool, bool, string, error) { - cm.lock.Lock() - defer cm.lock.Unlock() +// It returns status of acquiring a lock , status of Workflow status updated, waiting message if lock is not available, the failed lock, and any error encountered +func (sm *Manager) TryAcquire(wf *wfv1.Workflow, nodeName string, syncLockRef *wfv1.Synchronization) (bool, bool, string, string, error) { + sm.lock.Lock() + defer sm.lock.Unlock() if syncLockRef == nil { - return false, false, "", fmt.Errorf("cannot acquire lock from nil Synchronization") + return false, false, "", "", fmt.Errorf("cannot acquire lock from nil Synchronization") } - syncLockName, err := GetLockName(syncLockRef, wf.Namespace) + failedLockName := "" + syncItems, err := allSyncItems(syncLockRef) if err != nil { - return false, false, "", fmt.Errorf("requested configuration is invalid: %w", err) + return false, false, "", failedLockName, fmt.Errorf("requested configuration is invalid: %w", err) } + holderKey := getHolderKey(wf, nodeName) - lockKey := syncLockName.EncodeName() - lock, found := cm.syncLockMap[lockKey] - if !found { - switch syncLockRef.GetType() { - case wfv1.SynchronizationTypeSemaphore: - lock, err = cm.initializeSemaphore(lockKey) - case wfv1.SynchronizationTypeMutex: - lock = cm.initializeMutex(lockKey) - default: - return false, false, "", fmt.Errorf("unknown Synchronization Type") - } + var msg string + lockKeys := make([]string, len(syncItems)) + allAcquirable := true + for i, syncItem := range syncItems { + syncLockName, err := getLockName(syncItem, wf.Namespace) if err != nil { - return false, false, "", err + return false, false, "", failedLockName, fmt.Errorf("requested configuration is invalid: %w", err) + } + lockKeys[i] = syncLockName.encodeName() + } + for i, lockKey := range lockKeys { + lock, found := sm.syncLockMap[lockKey] + if !found { + var err error + switch syncItems[i].getType() { + case wfv1.SynchronizationTypeSemaphore: + lock, err = sm.initializeSemaphore(lockKey) + case wfv1.SynchronizationTypeMutex: + lock = sm.initializeMutex(lockKey) + default: + return false, false, "", failedLockName, fmt.Errorf("unknown Synchronization Type") + } + if err != nil { + return false, false, "", failedLockName, err + } + sm.syncLockMap[lockKey] = lock } - cm.syncLockMap[lockKey] = lock - } - if syncLockRef.GetType() == wfv1.SynchronizationTypeSemaphore { - err := cm.checkAndUpdateSemaphoreSize(lock) - if err != nil { - return false, false, "", err + if syncItems[i].getType() == wfv1.SynchronizationTypeSemaphore { + err := sm.checkAndUpdateSemaphoreSize(lock) + if err != nil { + return false, false, "", "", err + } } - } - holderKey := getHolderKey(wf, nodeName) - var priority int32 - if wf.Spec.Priority != nil { - priority = *wf.Spec.Priority - } else { - priority = 0 - } - creationTime := wf.CreationTimestamp - lock.addToQueue(holderKey, priority, creationTime.Time) - - ensureInit(wf, syncLockRef.GetType()) - currentHolders := cm.getCurrentLockHolders(lockKey) - acquired, msg := lock.tryAcquire(holderKey) - if acquired { - updated := wf.Status.Synchronization.GetStatus(syncLockRef.GetType()).LockAcquired(holderKey, lockKey, currentHolders) - return true, updated, "", nil + var priority int32 + if wf.Spec.Priority != nil { + priority = *wf.Spec.Priority + } else { + priority = 0 + } + creationTime := wf.CreationTimestamp + lock.addToQueue(holderKey, priority, creationTime.Time) + + ensureInit(wf, syncItems[i].getType()) + acquired, already, newMsg := lock.checkAcquire(holderKey) + if !acquired && !already { + allAcquirable = false + if msg == "" { + msg = newMsg + } + if failedLockName == "" { + failedLockName = lockKey + } + } } - updated := wf.Status.Synchronization.GetStatus(syncLockRef.GetType()).LockWaiting(holderKey, lockKey, currentHolders) - return false, updated, msg, nil + switch { + case allAcquirable: + updated := false + for i, lockKey := range lockKeys { + lock := sm.syncLockMap[lockKey] + acquired, msg := lock.tryAcquire(holderKey) + if !acquired { + return false, false, "", failedLockName, fmt.Errorf("bug: failed to acquire something that should have been checked: %s", msg) + } + currentHolders := sm.getCurrentLockHolders(lockKey) + if wf.Status.Synchronization.GetStatus(syncItems[i].getType()).LockAcquired(holderKey, lockKey, currentHolders) { + updated = true + } + } + return true, updated, msg, failedLockName, nil + default: // Not all acquirable + updated := false + for i, lockKey := range lockKeys { + currentHolders := sm.getCurrentLockHolders(lockKey) + if wf.Status.Synchronization.GetStatus(syncItems[i].getType()).LockWaiting(holderKey, lockKey, currentHolders) { + updated = true + } + } + return false, updated, msg, failedLockName, nil + } } -func (cm *Manager) Release(wf *wfv1.Workflow, nodeName string, syncRef *wfv1.Synchronization) { +func (sm *Manager) Release(wf *wfv1.Workflow, nodeName string, syncRef *wfv1.Synchronization) { if syncRef == nil { return } - cm.lock.Lock() - defer cm.lock.Unlock() + sm.lock.Lock() + defer sm.lock.Unlock() holderKey := getHolderKey(wf, nodeName) - lockName, err := GetLockName(syncRef, wf.Namespace) - if err != nil { - return - } + // Ignoring error here is as good as it's going to be, we shouldn't get here as we should + // should never have acquired anything if this errored + syncItems, _ := allSyncItems(syncRef) - if syncLockHolder, ok := cm.syncLockMap[lockName.EncodeName()]; ok { - syncLockHolder.release(holderKey) - syncLockHolder.removeFromQueue(holderKey) - log.Debugf("%s sync lock is released by %s", lockName.EncodeName(), holderKey) - lockKey := lockName.EncodeName() - if wf.Status.Synchronization != nil { - wf.Status.Synchronization.GetStatus(syncRef.GetType()).LockReleased(holderKey, lockKey) + for _, syncItem := range syncItems { + lockName, err := getLockName(syncItem, wf.Namespace) + if err != nil { + return + } + if syncLockHolder, ok := sm.syncLockMap[lockName.encodeName()]; ok { + syncLockHolder.release(holderKey) + syncLockHolder.removeFromQueue(holderKey) + lockKey := lockName.encodeName() + if wf.Status.Synchronization != nil { + wf.Status.Synchronization.GetStatus(syncItem.getType()).LockReleased(holderKey, lockKey) + } } } } -func (cm *Manager) ReleaseAll(wf *wfv1.Workflow) bool { - cm.lock.Lock() - defer cm.lock.Unlock() +func (sm *Manager) ReleaseAll(wf *wfv1.Workflow) bool { + sm.lock.Lock() + defer sm.lock.Unlock() if wf.Status.Synchronization == nil { return true @@ -290,7 +344,7 @@ func (cm *Manager) ReleaseAll(wf *wfv1.Workflow) bool { if wf.Status.Synchronization.Semaphore != nil { for _, holding := range wf.Status.Synchronization.Semaphore.Holding { - syncLockHolder := cm.syncLockMap[holding.Semaphore] + syncLockHolder := sm.syncLockMap[holding.Semaphore] if syncLockHolder == nil { continue } @@ -304,7 +358,7 @@ func (cm *Manager) ReleaseAll(wf *wfv1.Workflow) bool { // Remove the pending Workflow level semaphore keys for _, waiting := range wf.Status.Synchronization.Semaphore.Waiting { - syncLockHolder := cm.syncLockMap[waiting.Semaphore] + syncLockHolder := sm.syncLockMap[waiting.Semaphore] if syncLockHolder == nil { continue } @@ -316,7 +370,7 @@ func (cm *Manager) ReleaseAll(wf *wfv1.Workflow) bool { if wf.Status.Synchronization.Mutex != nil { for _, holding := range wf.Status.Synchronization.Mutex.Holding { - syncLockHolder := cm.syncLockMap[holding.Mutex] + syncLockHolder := sm.syncLockMap[holding.Mutex] if syncLockHolder == nil { continue } @@ -328,7 +382,7 @@ func (cm *Manager) ReleaseAll(wf *wfv1.Workflow) bool { // Remove the pending Workflow level mutex keys for _, waiting := range wf.Status.Synchronization.Mutex.Waiting { - syncLockHolder := cm.syncLockMap[waiting.Mutex] + syncLockHolder := sm.syncLockMap[waiting.Mutex] if syncLockHolder == nil { continue } @@ -340,7 +394,7 @@ func (cm *Manager) ReleaseAll(wf *wfv1.Workflow) bool { for _, node := range wf.Status.Nodes { if node.SynchronizationStatus != nil && node.SynchronizationStatus.Waiting != "" { - lock, ok := cm.syncLockMap[node.SynchronizationStatus.Waiting] + lock, ok := sm.syncLockMap[node.SynchronizationStatus.Waiting] if ok { lock.removeFromQueue(getHolderKey(wf, node.ID)) } @@ -376,35 +430,35 @@ func getHolderKey(wf *wfv1.Workflow, nodeName string) string { return key } -func (cm *Manager) getCurrentLockHolders(lockName string) []string { - if concurrency, ok := cm.syncLockMap[lockName]; ok { +func (sm *Manager) getCurrentLockHolders(lockName string) []string { + if concurrency, ok := sm.syncLockMap[lockName]; ok { return concurrency.getCurrentHolders() } return nil } -func (cm *Manager) initializeSemaphore(semaphoreName string) (Semaphore, error) { - limit, err := cm.getSyncLimit(semaphoreName) +func (sm *Manager) initializeSemaphore(semaphoreName string) (semaphore, error) { + limit, err := sm.getSyncLimit(semaphoreName) if err != nil { return nil, err } - return NewSemaphore(semaphoreName, limit, cm.nextWorkflow, "semaphore"), nil + return NewSemaphore(semaphoreName, limit, sm.nextWorkflow, "semaphore"), nil } -func (cm *Manager) initializeMutex(mutexName string) Semaphore { - return NewMutex(mutexName, cm.nextWorkflow) +func (sm *Manager) initializeMutex(mutexName string) semaphore { + return NewMutex(mutexName, sm.nextWorkflow) } -func (cm *Manager) isSemaphoreSizeChanged(semaphore Semaphore) (bool, int, error) { - limit, err := cm.getSyncLimit(semaphore.getName()) +func (sm *Manager) isSemaphoreSizeChanged(semaphore semaphore) (bool, int, error) { + limit, err := sm.getSyncLimit(semaphore.getName()) if err != nil { return false, semaphore.getLimit(), err } return semaphore.getLimit() != limit, limit, nil } -func (cm *Manager) checkAndUpdateSemaphoreSize(semaphore Semaphore) error { - changed, newLimit, err := cm.isSemaphoreSizeChanged(semaphore) +func (sm *Manager) checkAndUpdateSemaphoreSize(semaphore semaphore) error { + changed, newLimit, err := sm.isSemaphoreSizeChanged(semaphore) if err != nil { return err } diff --git a/workflow/sync/sync_manager_test.go b/workflow/sync/sync_manager_test.go index 10aa74642f0a..4e926a12c8f1 100644 --- a/workflow/sync/sync_manager_test.go +++ b/workflow/sync/sync_manager_test.go @@ -305,7 +305,7 @@ var WorkflowExistenceFunc = func(s string) bool { } func GetSyncLimitFunc(kube *fake.Clientset) func(string) (int, error) { - syncLimitConfig := func(lockName string) (int, error) { + return func(lockName string) (int, error) { items := strings.Split(lockName, "/") if len(items) < 4 { return 0, argoErr.New(argoErr.CodeBadRequest, "Invalid Config Map Key") @@ -324,7 +324,6 @@ func GetSyncLimitFunc(kube *fake.Clientset) func(string) (int, error) { } return strconv.Atoi(value) } - return syncLimitConfig } func TestSemaphoreWfLevel(t *testing.T) { @@ -338,18 +337,18 @@ func TestSemaphoreWfLevel(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) t.Run("InitializeSynchronization", func(t *testing.T) { - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(wfWithStatus) wfclientset := fakewfclientset.NewSimpleClientset(wf) wfList, err := wfclientset.ArgoprojV1alpha1().Workflows("default").List(ctx, metav1.ListOptions{}) require.NoError(t, err) - concurrenyMgr.Initialize(wfList.Items) - assert.Len(t, concurrenyMgr.syncLockMap, 1) + syncManager.Initialize(wfList.Items) + assert.Len(t, syncManager.syncLockMap, 1) }) t.Run("InitializeSynchronizationWithInvalid", func(t *testing.T) { - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(wfWithStatus) invalidSync := []wfv1.SemaphoreHolding{{Semaphore: "default/configmap/my-config1/workflow", Holders: []string{"hello-world-vcrg5"}}} @@ -357,92 +356,99 @@ func TestSemaphoreWfLevel(t *testing.T) { wfclientset := fakewfclientset.NewSimpleClientset(wf) wfList, err := wfclientset.ArgoprojV1alpha1().Workflows("default").List(ctx, metav1.ListOptions{}) require.NoError(t, err) - concurrenyMgr.Initialize(wfList.Items) - assert.Empty(t, concurrenyMgr.syncLockMap) + syncManager.Initialize(wfList.Items) + assert.Empty(t, syncManager.syncLockMap) }) t.Run("WfLevelAcquireAndRelease", func(t *testing.T) { var nextKey string - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { nextKey = key }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(wfWithSemaphore) wf1 := wf.DeepCopy() wf2 := wf.DeepCopy() wf3 := wf.DeepCopy() - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Semaphore) - assert.NotNil(t, wf.Status.Synchronization.Semaphore.Holding) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Semaphore) + require.NotNil(t, wf.Status.Synchronization.Semaphore.Holding) key := getHolderKey(wf, "") assert.Equal(t, key, wf.Status.Synchronization.Semaphore.Holding[0].Holders[0]) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.True(t, status) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.False(t, wfUpdate) wf1.Name = "two" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/workflow", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) wf2.Name = "three" wf2.Spec.Priority = ptr.To(int32(5)) holderKey2 := getHolderKey(wf2, "") - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/workflow", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) wf3.Name = "four" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf3, "", wf3.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf3, "", wf3.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/workflow", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) - concurrenyMgr.Release(wf, "", wf.Spec.Synchronization) + syncManager.Release(wf, "", wf.Spec.Synchronization) assert.Equal(t, holderKey2, nextKey) - assert.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization) assert.Empty(t, wf.Status.Synchronization.Semaphore.Holding[0].Holders) // Low priority workflow try to acquire the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/workflow", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) // High Priority workflow acquires the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf2.Status.Synchronization) - assert.NotNil(t, wf2.Status.Synchronization.Semaphore) + require.NotNil(t, wf2.Status.Synchronization) + require.NotNil(t, wf2.Status.Synchronization.Semaphore) key = getHolderKey(wf2, "") assert.Equal(t, key, wf2.Status.Synchronization.Semaphore.Holding[0].Holders[0]) - concurrenyMgr.ReleaseAll(wf2) + syncManager.ReleaseAll(wf2) assert.Nil(t, wf2.Status.Synchronization) - sema := concurrenyMgr.syncLockMap["default/ConfigMap/my-config/workflow"].(*PrioritySemaphore) - assert.NotNil(t, sema) + sema := syncManager.syncLockMap["default/ConfigMap/my-config/workflow"].(*prioritySemaphore) + require.NotNil(t, sema) assert.Len(t, sema.pending.items, 2) - concurrenyMgr.ReleaseAll(wf1) + syncManager.ReleaseAll(wf1) assert.Len(t, sema.pending.items, 1) - concurrenyMgr.ReleaseAll(wf3) + syncManager.ReleaseAll(wf3) assert.Empty(t, sema.pending.items) }) } @@ -458,33 +464,36 @@ func TestResizeSemaphoreSize(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) t.Run("WfLevelAcquireAndRelease", func(t *testing.T) { - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(wfWithSemaphore) wf.CreationTimestamp = metav1.Time{Time: time.Now()} wf1 := wf.DeepCopy() wf2 := wf.DeepCopy() - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Semaphore) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Semaphore) key := getHolderKey(wf, "") assert.Equal(t, key, wf.Status.Synchronization.Semaphore.Holding[0].Holders[0]) wf1.Name = "two" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/workflow", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) wf2.Name = "three" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/workflow", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) @@ -495,23 +504,25 @@ func TestResizeSemaphoreSize(t *testing.T) { _, err = kube.CoreV1().ConfigMaps("default").Update(ctx, cm, metav1.UpdateOptions{}) require.NoError(t, err) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.True(t, status) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, wfUpdate) - assert.NotNil(t, wf1.Status.Synchronization) - assert.NotNil(t, wf1.Status.Synchronization.Semaphore) + require.NotNil(t, wf1.Status.Synchronization) + require.NotNil(t, wf1.Status.Synchronization.Semaphore) key = getHolderKey(wf1, "") assert.Equal(t, key, wf1.Status.Synchronization.Semaphore.Holding[0].Holders[0]) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf2.Status.Synchronization) - assert.NotNil(t, wf2.Status.Synchronization.Semaphore) + require.NotNil(t, wf2.Status.Synchronization) + require.NotNil(t, wf2.Status.Synchronization.Semaphore) key = getHolderKey(wf2, "") assert.Equal(t, key, wf2.Status.Synchronization.Semaphore.Holding[0].Holders[0]) }) @@ -529,47 +540,51 @@ func TestSemaphoreTmplLevel(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) t.Run("TemplateLevelAcquireAndRelease", func(t *testing.T) { // var nextKey string - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { // nextKey = key }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(wfWithTmplSemaphore) tmpl := wf.Spec.Templates[2] - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "semaphore-tmpl-level-xjvln-3448864205", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "semaphore-tmpl-level-xjvln-3448864205", tmpl.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Semaphore) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Semaphore) key := getHolderKey(wf, "semaphore-tmpl-level-xjvln-3448864205") assert.Equal(t, key, wf.Status.Synchronization.Semaphore.Holding[0].Holders[0]) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "semaphore-tmpl-level-xjvln-3448864205", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "semaphore-tmpl-level-xjvln-3448864205", tmpl.Synchronization) require.NoError(t, err) assert.True(t, status) + assert.Empty(t, failedLockName) assert.False(t, wfUpdate) assert.Empty(t, msg) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "semaphore-tmpl-level-xjvln-1607747183", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "semaphore-tmpl-level-xjvln-1607747183", tmpl.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/ConfigMap/my-config/template", failedLockName) assert.True(t, wfUpdate) assert.False(t, status) - concurrenyMgr.Release(wf, "semaphore-tmpl-level-xjvln-3448864205", tmpl.Synchronization) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Semaphore) + syncManager.Release(wf, "semaphore-tmpl-level-xjvln-3448864205", tmpl.Synchronization) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Semaphore) assert.Empty(t, wf.Status.Synchronization.Semaphore.Holding[0].Holders) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "semaphore-tmpl-level-xjvln-1607747183", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf, "semaphore-tmpl-level-xjvln-1607747183", tmpl.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Semaphore) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Semaphore) key = getHolderKey(wf, "semaphore-tmpl-level-xjvln-1607747183") assert.Equal(t, key, wf.Status.Synchronization.Semaphore.Holding[0].Holders[0]) }) @@ -589,16 +604,17 @@ func TestTriggerWFWithAvailableLock(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) t.Run("TriggerWfsWithAvailableLocks", func(t *testing.T) { triggerCount := 0 - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { triggerCount++ }, WorkflowExistenceFunc) var wfs []wfv1.Workflow for i := 0; i < 3; i++ { wf := wfv1.MustUnmarshalWorkflow(wfWithSemaphore) wf.Name = fmt.Sprintf("%s-%d", "acquired", i) - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.Empty(msg) + assert.Empty(failedLockName) assert.True(status) assert.True(wfUpdate) wfs = append(wfs, *wf) @@ -607,15 +623,16 @@ func TestTriggerWFWithAvailableLock(t *testing.T) { for i := 0; i < 3; i++ { wf := wfv1.MustUnmarshalWorkflow(wfWithSemaphore) wf.Name = fmt.Sprintf("%s-%d", "wait", i) - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(msg) + assert.Equal("default/ConfigMap/my-config/workflow", failedLockName) assert.False(status) assert.True(wfUpdate) } - concurrenyMgr.Release(&wfs[0], "", wfs[0].Spec.Synchronization) + syncManager.Release(&wfs[0], "", wfs[0].Spec.Synchronization) triggerCount = 0 - concurrenyMgr.Release(&wfs[1], "", wfs[1].Spec.Synchronization) + syncManager.Release(&wfs[1], "", wfs[1].Spec.Synchronization) assert.Equal(2, triggerCount) }) } @@ -625,42 +642,45 @@ func TestMutexWfLevel(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) t.Run("WorkflowLevelMutexAcquireAndRelease", func(t *testing.T) { // var nextKey string - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { // nextKey = key }, WorkflowExistenceFunc) wf := wfv1.MustUnmarshalWorkflow(wfWithMutex) wf1 := wf.DeepCopy() wf2 := wf.DeepCopy() - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "", wf.Spec.Synchronization) require.NoError(t, err) assert.Empty(t, msg) + assert.Empty(t, failedLockName) assert.True(t, status) assert.True(t, wfUpdate) - assert.NotNil(t, wf.Status.Synchronization) - assert.NotNil(t, wf.Status.Synchronization.Mutex) - assert.NotNil(t, wf.Status.Synchronization.Mutex.Holding) + require.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization.Mutex) + require.NotNil(t, wf.Status.Synchronization.Mutex.Holding) wf1.Name = "two" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf1, "", wf1.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/my-mutex", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) wf2.Name = "three" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) + status, wfUpdate, msg, failedLockName, err = syncManager.TryAcquire(wf2, "", wf2.Spec.Synchronization) require.NoError(t, err) assert.NotEmpty(t, msg) + assert.Equal(t, "default/Mutex/my-mutex", failedLockName) assert.False(t, status) assert.True(t, wfUpdate) - mutex := concurrenyMgr.syncLockMap["default/Mutex/my-mutex"].(*PrioritySemaphore) - assert.NotNil(t, mutex) + mutex := syncManager.syncLockMap["default/Mutex/my-mutex"].(*prioritySemaphore) + require.NotNil(t, mutex) assert.Len(t, mutex.pending.items, 2) - concurrenyMgr.ReleaseAll(wf1) + syncManager.ReleaseAll(wf1) assert.Len(t, mutex.pending.items, 1) - concurrenyMgr.ReleaseAll(wf2) + syncManager.ReleaseAll(wf2) assert.Empty(t, mutex.pending.items) }) } @@ -678,7 +698,7 @@ func TestCheckWorkflowExistence(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) t.Run("WorkflowDeleted", func(t *testing.T) { - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { // nextKey = key }, func(s string) bool { return strings.Contains(s, "test1") @@ -689,18 +709,18 @@ func TestCheckWorkflowExistence(t *testing.T) { wfSema := wfv1.MustUnmarshalWorkflow(wfWithSemaphore) wfSema1 := wfSema.DeepCopy() wfSema1.Name = "test2" - _, _, _, _ = concurrenyMgr.TryAcquire(wfMutex, "", wfMutex.Spec.Synchronization) - _, _, _, _ = concurrenyMgr.TryAcquire(wfMutex1, "", wfMutex.Spec.Synchronization) - _, _, _, _ = concurrenyMgr.TryAcquire(wfSema, "", wfSema.Spec.Synchronization) - _, _, _, _ = concurrenyMgr.TryAcquire(wfSema1, "", wfSema.Spec.Synchronization) - mutex := concurrenyMgr.syncLockMap["default/Mutex/my-mutex"].(*PrioritySemaphore) - semaphore := concurrenyMgr.syncLockMap["default/ConfigMap/my-config/workflow"] + _, _, _, _, _ = syncManager.TryAcquire(wfMutex, "", wfMutex.Spec.Synchronization) + _, _, _, _, _ = syncManager.TryAcquire(wfMutex1, "", wfMutex.Spec.Synchronization) + _, _, _, _, _ = syncManager.TryAcquire(wfSema, "", wfSema.Spec.Synchronization) + _, _, _, _, _ = syncManager.TryAcquire(wfSema1, "", wfSema.Spec.Synchronization) + mutex := syncManager.syncLockMap["default/Mutex/my-mutex"].(*prioritySemaphore) + semaphore := syncManager.syncLockMap["default/ConfigMap/my-config/workflow"] assert.Len(mutex.getCurrentHolders(), 1) assert.Len(mutex.getCurrentPending(), 1) assert.Len(semaphore.getCurrentHolders(), 1) assert.Len(semaphore.getCurrentPending(), 1) - concurrenyMgr.CheckWorkflowExistence() + syncManager.CheckWorkflowExistence() assert.Empty(mutex.getCurrentHolders()) assert.Len(mutex.getCurrentPending(), 1) assert.Empty(semaphore.getCurrentHolders()) @@ -847,27 +867,29 @@ status: `) syncLimitFunc := GetSyncLimitFunc(kube) - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncManager := NewLockManager(syncLimitFunc, func(key string) { // nextKey = key }, WorkflowExistenceFunc) t.Run("InitializeMutex", func(t *testing.T) { tmpl := wf.Spec.Templates[1] - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "synchronization-tmpl-level-sgg6t-1949670081", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "synchronization-tmpl-level-sgg6t-1949670081", tmpl.Synchronization) require.NoError(t, err) assert.Empty(msg) + assert.Empty(failedLockName) assert.True(status) assert.True(wfUpdate) - assert.NotNil(wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization) assert.NotNil(wf.Status.Synchronization.Mutex) }) t.Run("InitializeSemaphore", func(t *testing.T) { tmpl := wf.Spec.Templates[2] - status, wfUpdate, msg, err := concurrenyMgr.TryAcquire(wf, "synchronization-tmpl-level-sgg6t-1899337224", tmpl.Synchronization) + status, wfUpdate, msg, failedLockName, err := syncManager.TryAcquire(wf, "synchronization-tmpl-level-sgg6t-1899337224", tmpl.Synchronization) require.NoError(t, err) assert.Empty(msg) + assert.Empty(failedLockName) assert.True(status) assert.True(wfUpdate) - assert.NotNil(wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization) assert.NotNil(wf.Status.Synchronization.Semaphore) }) @@ -1109,13 +1131,13 @@ func TestMutexMigration(t *testing.T) { syncLimitFunc := GetSyncLimitFunc(kube) - concurrenyMgr := NewLockManager(syncLimitFunc, func(key string) { + syncMgr := NewLockManager(syncLimitFunc, func(key string) { }, WorkflowExistenceFunc) wfMutex := wfv1.MustUnmarshalWorkflow(wfWithMutex) t.Run("RunMigrationWorkflowLevel", func(t *testing.T) { - concurrenyMgr.syncLockMap = make(map[string]Semaphore) + syncMgr.syncLockMap = make(map[string]semaphore) wfMutex2 := wfv1.MustUnmarshalWorkflow(wfV2MutexMigrationWorkflowLevel) require.Len(wfMutex2.Status.Synchronization.Mutex.Holding, 1) @@ -1124,14 +1146,16 @@ func TestMutexMigration(t *testing.T) { holdingName := items[len(items)-1] assert.Equal(wfMutex2.Status.Synchronization.Mutex.Holding[0].Holder, holdingName) - concurrenyMgr.syncLockMap = make(map[string]Semaphore) + syncMgr.syncLockMap = make(map[string]semaphore) wfs := []wfv1.Workflow{*wfMutex2.DeepCopy()} - concurrenyMgr.Initialize(wfs) + syncMgr.Initialize(wfs) - lockName, err := GetLockName(wfMutex2.Spec.Synchronization, wfMutex2.Namespace) + syncItems, err := allSyncItems(wfMutex2.Spec.Synchronization) + require.NoError(err) + lockName, err := getLockName(syncItems[0], wfMutex2.Namespace) require.NoError(err) - sem, found := concurrenyMgr.syncLockMap[lockName.EncodeName()] + sem, found := syncMgr.syncLockMap[lockName.encodeName()] require.True(found) holders := sem.getCurrentHolders() @@ -1141,17 +1165,17 @@ func TestMutexMigration(t *testing.T) { assert.Equal(holderKey, holders[0]) // We should already have this lock since we acquired it above - status, _, _, err := concurrenyMgr.TryAcquire(wfMutex2, "", wfMutex.Spec.Synchronization) + status, _, _, _, err := syncMgr.TryAcquire(wfMutex2, "", wfMutex.Spec.Synchronization) require.NoError(err) // BUG NOT PRESENT: https://github.com/argoproj/argo-workflows/issues/8684 assert.True(status) }) - concurrenyMgr = NewLockManager(syncLimitFunc, func(key string) { + syncMgr = NewLockManager(syncLimitFunc, func(key string) { }, WorkflowExistenceFunc) t.Run("RunMigrationTemplateLevel", func(t *testing.T) { - concurrenyMgr.syncLockMap = make(map[string]Semaphore) + syncMgr.syncLockMap = make(map[string]semaphore) wfMutex3 := wfv1.MustUnmarshalWorkflow(wfV2MutexMigrationTemplateLevel) require.Len(wfMutex3.Status.Synchronization.Mutex.Holding, 1) @@ -1167,12 +1191,14 @@ func TestMutexMigration(t *testing.T) { assert.Equal(1, numFound) wfs := []wfv1.Workflow{*wfMutex3.DeepCopy()} - concurrenyMgr.Initialize(wfs) + syncMgr.Initialize(wfs) - lockName, err := GetLockName(wfMutex3.Spec.Templates[1].Synchronization, wfMutex3.Namespace) + syncItems, err := allSyncItems(wfMutex3.Spec.Templates[1].Synchronization) + require.NoError(err) + lockName, err := getLockName(syncItems[0], wfMutex3.Namespace) require.NoError(err) - sem, found := concurrenyMgr.syncLockMap[lockName.EncodeName()] + sem, found := syncMgr.syncLockMap[lockName.encodeName()] require.True(found) holders := sem.getCurrentHolders() @@ -1183,7 +1209,7 @@ func TestMutexMigration(t *testing.T) { // PROVE: bug absent assert.Equal(holderKey, holders[0]) - status, _, _, err := concurrenyMgr.TryAcquire(wfMutex3, foundNodeID, wfMutex.Spec.Synchronization) + status, _, _, _, err := syncMgr.TryAcquire(wfMutex3, foundNodeID, wfMutex.Spec.Synchronization) require.NoError(err) // BUG NOT PRESENT: https://github.com/argoproj/argo-workflows/issues/8684 assert.True(status) diff --git a/workflow/sync/syncitems.go b/workflow/sync/syncitems.go new file mode 100644 index 000000000000..8e8cd79a3860 --- /dev/null +++ b/workflow/sync/syncitems.go @@ -0,0 +1,52 @@ +package sync + +import ( + "errors" + "reflect" + + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" +) + +type syncItem struct { + semaphore *v1alpha1.SemaphoreRef + mutex *v1alpha1.Mutex +} + +func allSyncItems(sync *v1alpha1.Synchronization) ([]*syncItem, error) { + var syncItems []*syncItem + if sync.Semaphore != nil { + syncItems = append(syncItems, &syncItem{semaphore: sync.Semaphore}) + } + if sync.Mutex != nil { + syncItems = append(syncItems, &syncItem{mutex: sync.Mutex}) + } + for _, semaphore := range sync.Semaphores { + syncItems = append(syncItems, &syncItem{semaphore: semaphore}) + } + for _, mtx := range sync.Mutexes { + syncItems = append(syncItems, &syncItem{mutex: mtx}) + } + return syncItems, checkDuplicates(syncItems) +} + +func checkDuplicates(items []*syncItem) error { + for i, item := range items { + for j := i + 1; j < len(items); j++ { + if reflect.DeepEqual(*item, *items[j]) { + return errors.New("Duplicate synchronization item found") + } + } + } + return nil +} + +func (i *syncItem) getType() v1alpha1.SynchronizationType { + switch { + case i.semaphore != nil: + return v1alpha1.SynchronizationTypeSemaphore + case i.mutex != nil: + return v1alpha1.SynchronizationTypeMutex + default: + return v1alpha1.SynchronizationTypeUnknown + } +} diff --git a/workflow/sync/syncitems_test.go b/workflow/sync/syncitems_test.go new file mode 100644 index 000000000000..f7fe5974d195 --- /dev/null +++ b/workflow/sync/syncitems_test.go @@ -0,0 +1,142 @@ +package sync + +import ( + "testing" + + apiv1 "k8s.io/api/core/v1" + + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" + + "github.com/stretchr/testify/assert" + // "github.com/stretchr/testify/require" +) + +func TestNoDuplicates(t *testing.T) { + tests := []struct { + name string + items []*syncItem + }{ + { + name: "single", + items: []*syncItem{ + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + }, + }, + }, + }, + { + name: "two", + items: []*syncItem{ + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + }, + }, + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "beta", + }, + }, + }, + }, + { + name: "different namespace mutex", + items: []*syncItem{ + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + Namespace: "foo", + }, + }, + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + Namespace: "bar", + }, + }, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := checkDuplicates(test.items) + assert.NoError(t, err) + }) + } +} + +func TestExpectDuplicates(t *testing.T) { + tests := []struct { + name string + items []*syncItem + }{ + { + name: "simple duplicate mutex", + items: []*syncItem{ + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + }, + }, + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + }, + }, + }, + }, + { + name: "simple duplicate semaphore", + items: []*syncItem{ + &syncItem{ + semaphore: &v1alpha1.SemaphoreRef{ + ConfigMapKeyRef: &apiv1.ConfigMapKeySelector{ + LocalObjectReference: apiv1.LocalObjectReference{ + Name: "foo", + }, + Key: "alpha", + }, + }, + }, + &syncItem{ + semaphore: &v1alpha1.SemaphoreRef{ + ConfigMapKeyRef: &apiv1.ConfigMapKeySelector{ + LocalObjectReference: apiv1.LocalObjectReference{ + Name: "foo", + }, + Key: "alpha", + }, + }, + }, + }, + }, + { + name: "another duplicate mutex", + items: []*syncItem{ + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + }, + }, + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "beta", + }, + }, + &syncItem{ + mutex: &v1alpha1.Mutex{ + Name: "alpha", + }, + }, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + err := checkDuplicates(test.items) + assert.Error(t, err) + }) + } +} From 185bf9447c849a21f5fac300921f795c0bcca1a9 Mon Sep 17 00:00:00 2001 From: Alan Clucas Date: Wed, 4 Sep 2024 10:05:39 +0100 Subject: [PATCH 2/5] Update pkg/apis/workflow/v1alpha1/workflow_types.go Co-authored-by: Anton Gilgur <4970083+agilgur5@users.noreply.github.com> Signed-off-by: Alan Clucas --- pkg/apis/workflow/v1alpha1/workflow_types.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 3cd1840c0c4e..f202d60d9a4d 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -1646,9 +1646,9 @@ type Synchronization struct { Semaphore *SemaphoreRef `json:"semaphore,omitempty" protobuf:"bytes,1,opt,name=semaphore"` // Mutex holds the Mutex lock details - deprecated, use mutexes instead Mutex *Mutex `json:"mutex,omitempty" protobuf:"bytes,2,opt,name=mutex"` - // Semaphores holds the list of Semaphores configuration + // v3.6 and after: Semaphores holds the list of Semaphores configuration Semaphores []*SemaphoreRef `json:"semaphores,omitempty" protobuf:"bytes,3,opt,name=semaphores"` - // Mutexes holds the list of Mutex lock details + // v3.6 and after: Mutexes holds the list of Mutex lock details Mutexes []*Mutex `json:"mutexes,omitempty" protobuf:"bytes,4,opt,name=mutexes"` } From 7ee0f180fb8cf079f00ed551ae9d55c4519054b4 Mon Sep 17 00:00:00 2001 From: Alan Clucas Date: Wed, 4 Sep 2024 11:16:25 +0100 Subject: [PATCH 3/5] chore: updates because of comment change Signed-off-by: Alan Clucas --- api/jsonschema/schema.json | 4 ++-- api/openapi-spec/swagger.json | 4 ++-- docs/executor_swagger.md | 4 ++-- docs/fields.md | 4 ++-- pkg/apis/workflow/v1alpha1/generated.proto | 4 ++-- pkg/apis/workflow/v1alpha1/openapi_generated.go | 4 ++-- pkg/plugins/executor/swagger.yml | 4 ++-- .../docs/IoArgoprojWorkflowV1alpha1Synchronization.md | 4 ++-- .../io_argoproj_workflow_v1alpha1_synchronization.py | 8 ++++---- .../docs/IoArgoprojWorkflowV1alpha1Synchronization.md | 4 ++-- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index 4cc5094f0971..b66cf9c512a5 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -6955,7 +6955,7 @@ "description": "Mutex holds the Mutex lock details - deprecated, use mutexes instead" }, "mutexes": { - "description": "Mutexes holds the list of Mutex lock details", + "description": "v3.6 and after: Mutexes holds the list of Mutex lock details", "items": { "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Mutex" }, @@ -6966,7 +6966,7 @@ "description": "Semaphore holds the Semaphore configuration - deprecated, use semaphores instead" }, "semaphores": { - "description": "Semaphores holds the list of Semaphores configuration", + "description": "v3.6 and after: Semaphores holds the list of Semaphores configuration", "items": { "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.SemaphoreRef" }, diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index b5753e95f546..f13b2db09bb4 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -10974,7 +10974,7 @@ "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Mutex" }, "mutexes": { - "description": "Mutexes holds the list of Mutex lock details", + "description": "v3.6 and after: Mutexes holds the list of Mutex lock details", "type": "array", "items": { "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.Mutex" @@ -10985,7 +10985,7 @@ "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.SemaphoreRef" }, "semaphores": { - "description": "Semaphores holds the list of Semaphores configuration", + "description": "v3.6 and after: Semaphores holds the list of Semaphores configuration", "type": "array", "items": { "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.SemaphoreRef" diff --git a/docs/executor_swagger.md b/docs/executor_swagger.md index 183c89d14a28..95c7b97c7b30 100644 --- a/docs/executor_swagger.md +++ b/docs/executor_swagger.md @@ -3683,9 +3683,9 @@ otherwise). | Name | Type | Go type | Required | Default | Description | Example | |------|------|---------|:--------:| ------- |-------------|---------| | mutex | [Mutex](#mutex)| `Mutex` | | | | | -| mutexes | [][Mutex](#mutex)| `[]*Mutex` | | | Mutexes holds the list of Mutex lock details | | +| mutexes | [][Mutex](#mutex)| `[]*Mutex` | | | v3.6 and after: Mutexes holds the list of Mutex lock details | | | semaphore | [SemaphoreRef](#semaphore-ref)| `SemaphoreRef` | | | | | -| semaphores | [][SemaphoreRef](#semaphore-ref)| `[]*SemaphoreRef` | | | Semaphores holds the list of Semaphores configuration | | +| semaphores | [][SemaphoreRef](#semaphore-ref)| `[]*SemaphoreRef` | | | v3.6 and after: Semaphores holds the list of Semaphores configuration | | diff --git a/docs/fields.md b/docs/fields.md index 40c208ab0b3a..27c3238b0f92 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -1646,9 +1646,9 @@ Synchronization holds synchronization lock configuration | Field Name | Field Type | Description | |:----------:|:----------:|---------------| |`mutex`|[`Mutex`](#mutex)|Mutex holds the Mutex lock details - deprecated, use mutexes instead| -|`mutexes`|`Array<`[`Mutex`](#mutex)`>`|Mutexes holds the list of Mutex lock details| +|`mutexes`|`Array<`[`Mutex`](#mutex)`>`|v3.6 and after: Mutexes holds the list of Mutex lock details| |`semaphore`|[`SemaphoreRef`](#semaphoreref)|Semaphore holds the Semaphore configuration - deprecated, use semaphores instead| -|`semaphores`|`Array<`[`SemaphoreRef`](#semaphoreref)`>`|Semaphores holds the list of Semaphores configuration| +|`semaphores`|`Array<`[`SemaphoreRef`](#semaphoreref)`>`|v3.6 and after: Semaphores holds the list of Semaphores configuration| ## Template diff --git a/pkg/apis/workflow/v1alpha1/generated.proto b/pkg/apis/workflow/v1alpha1/generated.proto index dbe6f87cf7e7..29913c186d82 100644 --- a/pkg/apis/workflow/v1alpha1/generated.proto +++ b/pkg/apis/workflow/v1alpha1/generated.proto @@ -1567,10 +1567,10 @@ message Synchronization { // Mutex holds the Mutex lock details - deprecated, use mutexes instead optional Mutex mutex = 2; - // Semaphores holds the list of Semaphores configuration + // v3.6 and after: Semaphores holds the list of Semaphores configuration repeated SemaphoreRef semaphores = 3; - // Mutexes holds the list of Mutex lock details + // v3.6 and after: Mutexes holds the list of Mutex lock details repeated Mutex mutexes = 4; } diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index 7c17df2624a2..6a1ba33db0a1 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -6184,7 +6184,7 @@ func schema_pkg_apis_workflow_v1alpha1_Synchronization(ref common.ReferenceCallb }, "semaphores": { SchemaProps: spec.SchemaProps{ - Description: "Semaphores holds the list of Semaphores configuration", + Description: "v3.6 and after: Semaphores holds the list of Semaphores configuration", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6197,7 +6197,7 @@ func schema_pkg_apis_workflow_v1alpha1_Synchronization(ref common.ReferenceCallb }, "mutexes": { SchemaProps: spec.SchemaProps{ - Description: "Mutexes holds the list of Mutex lock details", + Description: "v3.6 and after: Mutexes holds the list of Mutex lock details", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ diff --git a/pkg/plugins/executor/swagger.yml b/pkg/plugins/executor/swagger.yml index 588d7190e343..b0806a1055c2 100644 --- a/pkg/plugins/executor/swagger.yml +++ b/pkg/plugins/executor/swagger.yml @@ -4222,14 +4222,14 @@ definitions: mutex: $ref: '#/definitions/Mutex' mutexes: - description: Mutexes holds the list of Mutex lock details + description: 'v3.6 and after: Mutexes holds the list of Mutex lock details' items: $ref: '#/definitions/Mutex' type: array semaphore: $ref: '#/definitions/SemaphoreRef' semaphores: - description: Semaphores holds the list of Semaphores configuration + description: 'v3.6 and after: Semaphores holds the list of Semaphores configuration' items: $ref: '#/definitions/SemaphoreRef' type: array diff --git a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md index 310e05a2f1d6..9cb40edb1f3d 100644 --- a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md +++ b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md @@ -9,9 +9,9 @@ Synchronization holds synchronization lock configuration Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **mutex** | [**IoArgoprojWorkflowV1alpha1Mutex**](IoArgoprojWorkflowV1alpha1Mutex.md) | | [optional] -**mutexes** | [**List<IoArgoprojWorkflowV1alpha1Mutex>**](IoArgoprojWorkflowV1alpha1Mutex.md) | Mutexes holds the list of Mutex lock details | [optional] +**mutexes** | [**List<IoArgoprojWorkflowV1alpha1Mutex>**](IoArgoprojWorkflowV1alpha1Mutex.md) | v3.6 and after: Mutexes holds the list of Mutex lock details | [optional] **semaphore** | [**IoArgoprojWorkflowV1alpha1SemaphoreRef**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | | [optional] -**semaphores** | [**List<IoArgoprojWorkflowV1alpha1SemaphoreRef>**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | Semaphores holds the list of Semaphores configuration | [optional] +**semaphores** | [**List<IoArgoprojWorkflowV1alpha1SemaphoreRef>**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | v3.6 and after: Semaphores holds the list of Semaphores configuration | [optional] diff --git a/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py index 95fa013e6b89..c92ea14a75b2 100644 --- a/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py +++ b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_synchronization.py @@ -149,9 +149,9 @@ def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 through its discriminator because we passed in _visited_composed_classes = (Animal,) mutex (IoArgoprojWorkflowV1alpha1Mutex): [optional] # noqa: E501 - mutexes ([IoArgoprojWorkflowV1alpha1Mutex]): Mutexes holds the list of Mutex lock details. [optional] # noqa: E501 + mutexes ([IoArgoprojWorkflowV1alpha1Mutex]): v3.6 and after: Mutexes holds the list of Mutex lock details. [optional] # noqa: E501 semaphore (IoArgoprojWorkflowV1alpha1SemaphoreRef): [optional] # noqa: E501 - semaphores ([IoArgoprojWorkflowV1alpha1SemaphoreRef]): Semaphores holds the list of Semaphores configuration. [optional] # noqa: E501 + semaphores ([IoArgoprojWorkflowV1alpha1SemaphoreRef]): v3.6 and after: Semaphores holds the list of Semaphores configuration. [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) @@ -234,9 +234,9 @@ def __init__(self, *args, **kwargs): # noqa: E501 through its discriminator because we passed in _visited_composed_classes = (Animal,) mutex (IoArgoprojWorkflowV1alpha1Mutex): [optional] # noqa: E501 - mutexes ([IoArgoprojWorkflowV1alpha1Mutex]): Mutexes holds the list of Mutex lock details. [optional] # noqa: E501 + mutexes ([IoArgoprojWorkflowV1alpha1Mutex]): v3.6 and after: Mutexes holds the list of Mutex lock details. [optional] # noqa: E501 semaphore (IoArgoprojWorkflowV1alpha1SemaphoreRef): [optional] # noqa: E501 - semaphores ([IoArgoprojWorkflowV1alpha1SemaphoreRef]): Semaphores holds the list of Semaphores configuration. [optional] # noqa: E501 + semaphores ([IoArgoprojWorkflowV1alpha1SemaphoreRef]): v3.6 and after: Semaphores holds the list of Semaphores configuration. [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) diff --git a/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md index 829ce269c1fc..c53c3e24cf2b 100644 --- a/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md +++ b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1Synchronization.md @@ -6,9 +6,9 @@ Synchronization holds synchronization lock configuration Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **mutex** | [**IoArgoprojWorkflowV1alpha1Mutex**](IoArgoprojWorkflowV1alpha1Mutex.md) | | [optional] -**mutexes** | [**[IoArgoprojWorkflowV1alpha1Mutex]**](IoArgoprojWorkflowV1alpha1Mutex.md) | Mutexes holds the list of Mutex lock details | [optional] +**mutexes** | [**[IoArgoprojWorkflowV1alpha1Mutex]**](IoArgoprojWorkflowV1alpha1Mutex.md) | v3.6 and after: Mutexes holds the list of Mutex lock details | [optional] **semaphore** | [**IoArgoprojWorkflowV1alpha1SemaphoreRef**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | | [optional] -**semaphores** | [**[IoArgoprojWorkflowV1alpha1SemaphoreRef]**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | Semaphores holds the list of Semaphores configuration | [optional] +**semaphores** | [**[IoArgoprojWorkflowV1alpha1SemaphoreRef]**](IoArgoprojWorkflowV1alpha1SemaphoreRef.md) | v3.6 and after: Semaphores holds the list of Semaphores configuration | [optional] **any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) From 8e26e16170ef39579316e99da341158234478912 Mon Sep 17 00:00:00 2001 From: Alan Clucas Date: Mon, 9 Sep 2024 10:32:16 +0100 Subject: [PATCH 4/5] chore(docs): more updates and examples Signed-off-by: Alan Clucas --- docs/fields.md | 54 +++++++++++++++++++ docs/synchronization.md | 7 ++- ...nchronization-mutex-tmpl-level-legacy.yaml | 45 ++++++++++++++++ ...synchronization-mutex-wf-level-legacy.yaml | 17 ++++++ .../synchronization-tmpl-level-legacy.yaml | 37 +++++++++++++ examples/synchronization-wf-level-legacy.yaml | 28 ++++++++++ 6 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 examples/synchronization-mutex-tmpl-level-legacy.yaml create mode 100644 examples/synchronization-mutex-wf-level-legacy.yaml create mode 100644 examples/synchronization-tmpl-level-legacy.yaml create mode 100644 examples/synchronization-wf-level-legacy.yaml diff --git a/docs/fields.md b/docs/fields.md index 27c3238b0f92..e9f1ecfa89d1 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -323,8 +323,12 @@ Workflow is the definition of a workflow resource - [`suspend-template.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) - [`template-defaults.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/template-defaults.yaml) @@ -755,8 +759,12 @@ WorkflowSpec is the specification of a Workflow. - [`suspend-template.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) - [`template-defaults.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/template-defaults.yaml) @@ -1200,8 +1208,12 @@ CronWorkflowSpec is the specification of a CronWorkflow - [`suspend-template.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) - [`template-defaults.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/template-defaults.yaml) @@ -1446,6 +1458,8 @@ Arguments to a template - [`suspend-template-outputs.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template-outputs.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) - [`work-avoidance.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/work-avoidance.yaml) @@ -1637,8 +1651,12 @@ Synchronization holds synchronization lock configuration
Examples with this field (click to open) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml)
@@ -1953,8 +1971,12 @@ SynchronizationStatus stores the status of semaphore and mutex.
Examples with this field (click to open) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml)
@@ -2248,6 +2270,8 @@ Parameter indicate a passed string parameter to a service template with an optio - [`suspend-template-outputs.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template-outputs.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) - [`work-avoidance.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/work-avoidance.yaml) @@ -2364,6 +2388,14 @@ Backoff is a backoff strategy to use within retryStrategy Mutex holds Mutex configuration +
+Examples with this field (click to open) + +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) +
+ ### Fields | Field Name | Field Type | Description | |:----------:|:----------:|---------------| @@ -3114,6 +3146,8 @@ WorkflowStep is a reference to a template to execute in a series of step - [`suspend-template.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) - [`template-defaults.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/template-defaults.yaml) @@ -3244,6 +3278,14 @@ NodeSynchronizationStatus stores the status of a node MutexStatus contains which objects hold mutex locks, and which objects this workflow is waiting on to release locks. +
+Examples with this field (click to open) + +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) +
+ ### Fields | Field Name | Field Type | Description | |:----------:|:----------:|---------------| @@ -4872,8 +4914,12 @@ ObjectMeta is metadata that all persisted resources must have, which includes al - [`suspend-template.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) - [`template-defaults.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/template-defaults.yaml) @@ -5460,8 +5506,12 @@ A single application container that you want to run within a pod. - [`suspend-template.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) - [`template-defaults.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/template-defaults.yaml) @@ -6222,8 +6272,12 @@ PersistentVolumeClaimSpec describes the common attributes of storage devices and - [`suspend-template.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/suspend-template.yaml) +- [`synchronization-mutex-tmpl-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) + - [`synchronization-mutex-tmpl-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +- [`synchronization-mutex-wf-level-legacy.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) + - [`synchronization-mutex-wf-level.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) - [`template-defaults.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/template-defaults.yaml) diff --git a/docs/synchronization.md b/docs/synchronization.md index 94f8891e4d4e..8c5ef695ce90 100644 --- a/docs/synchronization.md +++ b/docs/synchronization.md @@ -1,7 +1,6 @@ # Synchronization > v2.10 and after -> v3.6 for multiple You can limit the parallel execution of workflows or templates: @@ -152,6 +151,10 @@ Examples: 1. [Workflow level mutex](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level.yaml) 1. [Step level semaphore](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-tmpl-level.yaml) 1. [Step level mutex](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level.yaml) +1. [Legacy workflow level semaphore](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-wf-level-legacy.yaml) +1. [Legacy workflow level mutex](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-wf-level-legacy.yaml) +1. [Legacy step level semaphore](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-tmpl-level-legacy.yaml) +1. [Legacy step level mutex](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-mutex-tmpl-level-legacy.yaml) ## Queuing @@ -165,6 +168,8 @@ Workflows can only acquire a lock if they are at the front of the queue for that ## Multiple locks +> v3.6 and after + You can specify multiple locks in a single workflow or template. ```yaml diff --git a/examples/synchronization-mutex-tmpl-level-legacy.yaml b/examples/synchronization-mutex-tmpl-level-legacy.yaml new file mode 100644 index 000000000000..9652e48a7d0a --- /dev/null +++ b/examples/synchronization-mutex-tmpl-level-legacy.yaml @@ -0,0 +1,45 @@ +# This example demonstrates the use of a Synchronization Mutex lock on template execution. Mutex lock limits +# only one of the template execution across the workflows in the namespace which has same Mutex lock. + +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: synchronization-tmpl-level-mutex- +spec: + entrypoint: synchronization-tmpl-level-mutex-example + templates: + - name: synchronization-tmpl-level-mutex-example + steps: + - - name: synchronization-acquire-lock + template: acquire-lock + arguments: + parameters: + - name: seconds + value: "{{item}}" + withParam: '["1","2","3","4","5"]' + + - name: synchronization-acquire-lock1 + template: acquire-lock-1 + arguments: + parameters: + - name: seconds + value: "{{item}}" + withParam: '["1","2","3","4","5"]' + + - name: acquire-lock + synchronization: + mutex: + name: welcome + container: + image: alpine:latest + command: [sh, -c] + args: ["sleep 20; echo acquired lock"] + + - name: acquire-lock-1 + synchronization: + mutex: + name: test + container: + image: alpine:latest + command: [sh, -c] + args: ["sleep 50; echo acquired lock"] \ No newline at end of file diff --git a/examples/synchronization-mutex-wf-level-legacy.yaml b/examples/synchronization-mutex-wf-level-legacy.yaml new file mode 100644 index 000000000000..f13b199c6aaa --- /dev/null +++ b/examples/synchronization-mutex-wf-level-legacy.yaml @@ -0,0 +1,17 @@ +# This example demonstrates the use of a Synchronization Mutex lock on workflow execution. Mutex lock limits +# only one of the workflow execution in the namespace which has same Mutex lock. +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: synchronization-wf-level- +spec: + entrypoint: hello-world + synchronization: + mutex: + name: test + templates: + - name: hello-world + container: + image: busybox + command: [echo] + args: ["hello world"] diff --git a/examples/synchronization-tmpl-level-legacy.yaml b/examples/synchronization-tmpl-level-legacy.yaml new file mode 100644 index 000000000000..b8c0f79c6c6f --- /dev/null +++ b/examples/synchronization-tmpl-level-legacy.yaml @@ -0,0 +1,37 @@ +# This example demonstrates the use of a Synchronization lock on template execution. Synchronization lock limits +# the number of concurrent template execution across the workflows in the namespace which has same Synchronization lock. +# Synchronization limit value can be configured in configmap. Eg.: +# apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: my-config +# data: +# template: "3" +#--- +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: synchronization-tmpl-level- +spec: + entrypoint: synchronization-tmpl-level-example + templates: + - name: synchronization-tmpl-level-example + steps: + - - name: synchronization-acquire-lock + template: acquire-lock + arguments: + parameters: + - name: seconds + value: "{{item}}" + withParam: '["1","2","3","4","5"]' + + - name: acquire-lock + synchronization: + semaphore: + configMapKeyRef: + name: my-config + key: template + container: + image: alpine:latest + command: [sh, -c] + args: ["sleep 10; echo acquired lock"] diff --git a/examples/synchronization-wf-level-legacy.yaml b/examples/synchronization-wf-level-legacy.yaml new file mode 100644 index 000000000000..b7ed90a092ca --- /dev/null +++ b/examples/synchronization-wf-level-legacy.yaml @@ -0,0 +1,28 @@ +# This example demonstrates the use of a Synchronization lock on workflow execution. Synchronization lock limits +# the number of concurrent workflow execution in the namespace which has same Synchronization lock. Synchronization +# limit value can be configured in configmap. +# Eg.: +# apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: my-config +# data: +# workflow: "3" +#--- +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: synchronization-wf-level- +spec: + entrypoint: hello-world + synchronization: + semaphore: + configMapKeyRef: + name: my-config + key: workflow + templates: + - name: hello-world + container: + image: busybox + command: [echo] + args: ["hello world"] From 4339403a354fa67b283d5783b66f6a63090bcc4d Mon Sep 17 00:00:00 2001 From: Alan Clucas Date: Wed, 18 Sep 2024 15:25:01 +0100 Subject: [PATCH 5/5] chore: more fixes Signed-off-by: Alan Clucas --- .../crds/full/argoproj.io_clusterworkflowtemplates.yaml | 3 +++ manifests/base/crds/full/argoproj.io_cronworkflows.yaml | 3 +++ manifests/base/crds/full/argoproj.io_workflows.yaml | 7 +++++++ manifests/base/crds/full/argoproj.io_workflowtasksets.yaml | 1 + .../base/crds/full/argoproj.io_workflowtemplates.yaml | 3 +++ workflow/sync/multiple_test.go | 4 ++-- 6 files changed, 19 insertions(+), 2 deletions(-) diff --git a/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml b/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml index c9afdfafe375..23bbf9f64ff5 100644 --- a/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml +++ b/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml @@ -2148,6 +2148,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -10644,6 +10645,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -19926,6 +19928,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean diff --git a/manifests/base/crds/full/argoproj.io_cronworkflows.yaml b/manifests/base/crds/full/argoproj.io_cronworkflows.yaml index d9b19ee4b4be..e61567626f59 100644 --- a/manifests/base/crds/full/argoproj.io_cronworkflows.yaml +++ b/manifests/base/crds/full/argoproj.io_cronworkflows.yaml @@ -2182,6 +2182,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -10678,6 +10679,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -19960,6 +19962,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean diff --git a/manifests/base/crds/full/argoproj.io_workflows.yaml b/manifests/base/crds/full/argoproj.io_workflows.yaml index b501d969e6e8..9a78c3e5806d 100644 --- a/manifests/base/crds/full/argoproj.io_workflows.yaml +++ b/manifests/base/crds/full/argoproj.io_workflows.yaml @@ -2162,6 +2162,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -10658,6 +10659,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -19940,6 +19942,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -33299,6 +33302,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -36220,6 +36224,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -44716,6 +44721,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -53998,6 +54004,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean diff --git a/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml b/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml index e58713d8b69f..bcac41078465 100644 --- a/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml +++ b/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml @@ -8511,6 +8511,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean diff --git a/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml b/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml index 124cb6dd17f5..be40a88a9365 100644 --- a/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml +++ b/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml @@ -2147,6 +2147,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -10643,6 +10644,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean @@ -19925,6 +19927,7 @@ spec: key: type: string name: + default: "" type: string optional: type: boolean diff --git a/workflow/sync/multiple_test.go b/workflow/sync/multiple_test.go index cfe33e3514ee..5eaf5179014c 100644 --- a/workflow/sync/multiple_test.go +++ b/workflow/sync/multiple_test.go @@ -10,7 +10,7 @@ import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" ) @@ -329,7 +329,7 @@ func TestPriority(t *testing.T) { `) wfhigh := wflow.DeepCopy() wfhigh.Name = "priorityhigh" - wfhigh.Spec.Priority = pointer.Int32(5) + wfhigh.Spec.Priority = ptr.To(int32(5)) wf1 := templatedWorkflow("one", ` mutexes: - name: two