diff --git a/.spelling b/.spelling index 56808b006eee..081512ac8697 100644 --- a/.spelling +++ b/.spelling @@ -183,6 +183,7 @@ memoizing metadata minikube mutex +mutexes namespace namespaces natively diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index 54b359072bea..c9f3020e944c 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -6878,11 +6878,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 3dcf26481085..7a82b10e159a 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -10818,12 +10818,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 2e35fbabe2db..01071f904106 100644 --- a/docs/executor_swagger.md +++ b/docs/executor_swagger.md @@ -3534,7 +3534,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 d74d4a6ad180..f1dc3fa2568a 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -1632,8 +1632,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 @@ -2349,14 +2351,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 | |:----------:|:----------:|---------------| @@ -3231,14 +3225,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/parallelism.md b/docs/parallelism.md new file mode 100644 index 000000000000..2c2a79c38614 --- /dev/null +++ b/docs/parallelism.md @@ -0,0 +1,38 @@ +# Limiting parallelism + +You can restrict the number of workflows being executed at any time using a number of mechanisms + +## Controller level + +You can limit the total number of workflows that can execute at any one time in the [workflow controller ConfigMap](./workflow-controller-configmap.yaml). + +```yaml +data: + parallelism: "10" +``` + +You can also limit the number of workflows that can execute in a single namespace. + +```yaml +data: + namespaceParallelism: "4" +``` + +Workflows that are executing but restricted from running more nodes due to the other mechanisms on this page will still count towards the parallelism limits. + +## Workflow level + +You can restrict parallelism within a workflow using `parallelism` within a workflow or template. +This only restricts total concurrent executions of steps or tasks within the same workflow. + +Examples + +1 [`parallelism-limit.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/parallelism-limit.yaml) restricts the parallelism of a [loop](./walk-through/loops.md) +1 [`parallelism-nested.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/parallelism-nested.yaml) restricts the parallelism of a nested loop +1 [`parallelism-nested-dag.yaml`](https://github.com/argoproj/argo-workflows/blob/main/examples/parallelism-nested-dag.yaml) restricts the number of dag tasks that can be run at any one time +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 + +## Synchronization + +You can use [mutexes and semaphores](./synchronization.md) to control the parallel execution of sections of a workflow. diff --git a/docs/synchronization.md b/docs/synchronization.md index 0897d96cb038..cc9054d8eb85 100644 --- a/docs/synchronization.md +++ b/docs/synchronization.md @@ -1,16 +1,15 @@ # Synchronization > v2.10 and after +> v3.6 for multiple ## Introduction -Synchronization enables users to limit the parallel execution of certain workflows or -templates within a workflow without having to restrict others. +You can use synchronization to limit the parallel execution of workflows or templates. +You can use mutexes to restrict workflows or templates to only having a single concurrent section. +You can use semaphores to restrict workflows or templates to a configured number of parallel runs. -Users can create multiple synchronization configurations in the `ConfigMap` that can be referred to -from a workflow or template within a workflow. Alternatively, users can -configure a mutex to prevent concurrent execution of templates or -workflows using the same mutex. +You can create multiple synchronization configurations in the `ConfigMap` that can be referred to from a workflow or template. For example: @@ -26,9 +25,10 @@ data: ### Workflow-level Synchronization -Workflow-level synchronization limits parallel execution of the workflow if workflows have the same synchronization reference. -In this example, Workflow refers to `workflow` synchronization key which is configured as limit 1, -so only one workflow instance will be executed at given time even multiple workflows created. +You can limit parallel execution of a workflow by using Workflow-level synchronization. +If multiple workflows have the same synchronization reference they will be limited by that synchronization reference. + +In this example, Workflow refers to `workflow` synchronization key which is configured as limit `"1"`, so only one workflow instance will be executed at given time even if multiple workflows are created. Using a semaphore configured by a `ConfigMap`: @@ -40,10 +40,10 @@ metadata: spec: entrypoint: whalesay synchronization: - semaphore: - configMapKeyRef: - name: my-config - key: workflow + semaphores: + - configMapKeyRef: + name: my-config + key: workflow templates: - name: whalesay container: @@ -52,7 +52,7 @@ spec: args: ["hello world"] ``` -Using a mutex: +Using a mutex achieves the same thing as a count `"1"` semaphore: ```yaml apiVersion: argoproj.io/v1alpha1 @@ -62,8 +62,8 @@ metadata: spec: entrypoint: whalesay synchronization: - mutex: - name: workflow + mutexes: + - name: workflow templates: - name: whalesay container: @@ -74,9 +74,11 @@ spec: ### Template-level Synchronization -Template-level synchronization limits parallel execution of the template across workflows, if templates have the same synchronization reference. -In this example, `acquire-lock` template has synchronization reference of `template` key which is configured as limit 2, -so two instances of templates will be executed at a given time: even multiple steps/tasks within workflow or different workflows referring to the same template. +You can limit parallel execution of a template by using Template-level synchronization. +If templates have the same synchronization reference they will be limited by that synchronization reference, across all workflows. + +In this example, `acquire-lock` template has synchronization reference of `template` key which is configured as limit `"2"` so a maximum of two instances of the `acquire-lock` template will be executed at a given time. +This applies even multiple steps or tasks within a workflow or different workflows refer to the same template. Using a semaphore configured by a `ConfigMap`: @@ -100,17 +102,17 @@ 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] args: ["sleep 10; echo acquired lock"] ``` -Using a mutex: +Using a mutex will limit to a single execution of the template at any one time: ```yaml apiVersion: argoproj.io/v1alpha1 @@ -132,8 +134,8 @@ spec: - name: acquire-lock synchronization: - mutex: - name: template + mutexes: + - name: template container: image: alpine:latest command: [sh, -c] @@ -142,13 +144,64 @@ spec: Examples: -1. [Workflow level semaphore](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-wf-level.yaml) +1. [Workflow level semaphore](https://github.com/argoproj/argo-workflows/blob/main/examples/synchronization-wf-level.yamlxb) 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) -### Other Parallelism support +### Multiple synchronization + +You can specify multiple mutexes and semaphores to lock 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 mutexes and semaphores are available. + +### Priority + +Workflows can have a `priority` set in their specification. +Workflows with a higher priority value will be queued to take a semaphore or mutex before a lower priority workflow, even if they have been waiting for less time. + +!!! Warning + A high priority workflow waiting on multiple mutexes or semaphore will make all other workflows which want to acquire those mutexes wait for it to acquire and release all the mutexes or semaphores it is waiting on. + This applies even if the lower priority workflows only wish to acquire a subset of those mutexes or semaphores. + +### Legacy + +In workflows prior to 3.6 you can only specify one mutex or semaphore to 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 mutex and semaphore will be taken in version 3.6 with this syntax. +This syntax can be mixed with `mutexes` and `semaphores`, all mutexes and semaphores will be used. + +## Parallelism -In addition to this synchronization, the workflow controller supports a parallelism setting that applies to all workflows -in the system (it is not granular to a class of workflows, or tasks withing them). Furthermore, there is a parallelism setting -at the workflow and template level, but this only restricts total concurrent executions of tasks within the same workflow. +See also [how you can restrict parallelism](./parallelism.md) in other ways. 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 30bae7caace9..ff1d6e6437b2 100644 --- a/examples/synchronization-mutex-wf-level.yaml +++ b/examples/synchronization-mutex-wf-level.yaml @@ -7,8 +7,8 @@ metadata: spec: entrypoint: whalesay synchronization: - mutex: - name: test + mutexes: + - name: test templates: - name: whalesay 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 f0d58a5d7666..0295bf410bea 100644 --- a/examples/synchronization-wf-level.yaml +++ b/examples/synchronization-wf-level.yaml @@ -1,4 +1,4 @@ -# This example demonstrates the use of a Synchronization lock on workflow execution. Synchronization lock limits +# 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.: @@ -16,10 +16,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/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml b/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml index 78a364fb9e80..9182f46eb30a 100644 --- a/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml +++ b/manifests/base/crds/full/argoproj.io_clusterworkflowtemplates.yaml @@ -1939,6 +1939,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -1956,6 +1965,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: @@ -9694,6 +9722,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -9711,6 +9748,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 @@ -18180,6 +18236,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -18197,6 +18262,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 3bd8d118f6a0..e5a067b666fd 100644 --- a/manifests/base/crds/full/argoproj.io_cronworkflows.yaml +++ b/manifests/base/crds/full/argoproj.io_cronworkflows.yaml @@ -1971,6 +1971,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -1988,6 +1997,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: @@ -9726,6 +9754,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -9743,6 +9780,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 @@ -18212,6 +18268,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -18229,6 +18294,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 d0c5aa874f0d..5bcb3b94372a 100644 --- a/manifests/base/crds/full/argoproj.io_workflows.yaml +++ b/manifests/base/crds/full/argoproj.io_workflows.yaml @@ -1953,6 +1953,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -1970,6 +1979,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: @@ -9708,6 +9736,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -9725,6 +9762,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 @@ -18194,6 +18250,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -18211,6 +18276,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 @@ -30491,6 +30575,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -30508,6 +30601,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 @@ -33154,6 +33266,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -33171,6 +33292,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: @@ -40909,6 +41049,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -40926,6 +41075,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 @@ -49395,6 +49563,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -49412,6 +49589,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 9f4475e344ee..8aadd47a4664 100644 --- a/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml +++ b/manifests/base/crds/full/argoproj.io_workflowtasksets.yaml @@ -7764,6 +7764,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -7781,6 +7790,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 e971cf10d51c..51380b5c92ba 100644 --- a/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml +++ b/manifests/base/crds/full/argoproj.io_workflowtemplates.yaml @@ -1938,6 +1938,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -1955,6 +1964,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: @@ -9693,6 +9721,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -9710,6 +9747,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 @@ -18179,6 +18235,15 @@ spec: namespace: type: string type: object + mutexes: + items: + properties: + name: + type: string + namespace: + type: string + type: object + type: array semaphore: properties: configMapKeyRef: @@ -18196,6 +18261,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/mkdocs.yml b/mkdocs.yml index 3403c489f3d3..b121645e439f 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -122,6 +122,7 @@ nav: - retries.md - lifecyclehook.md - synchronization.md + - parallelism.md - memoization.md - template-defaults.md - enhanced-depends-logic.md 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 e068bc96bf88..c311ebe108a4 100644 --- a/pkg/apis/workflow/v1alpha1/generated.pb.go +++ b/pkg/apis/workflow/v1alpha1/generated.pb.go @@ -4448,699 +4448,701 @@ func init() { } var fileDescriptor_724696e352c3df5f = []byte{ - // 11059 bytes of a gzipped FileDescriptorProto + // 11102 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x7d, 0x6b, 0x70, 0x24, 0xc7, 0x79, 0x18, 0x67, 0x81, 0x05, 0xb0, 0xdf, 0x02, 0x38, 0x5c, 0xdf, 0x6b, 0x09, 0x92, 0x07, 0x7a, 0x28, 0x32, 0xa4, 0x4d, 0xe1, 0xcc, 0xa3, 0x94, 0x30, 0x52, 0x22, 0x09, 0x8f, 0x03, 0xee, 0x88, 0xc3, 0x01, 0xec, 0xc5, 0xf1, 0x4c, 0x8a, 0x96, 0x34, 0xd8, 0x6d, 0xec, 0x0e, 0xb1, 0x3b, 0xb3, 0x9c, 0x99, 0xc5, 0x1d, 0xf8, 0x90, 0x14, 0x5a, 0xcf, 0x58, 0xb6, 0x62, 0x59, 0x92, 0x25, 0x25, 0xa9, 0x52, 0x14, 0x29, 0x61, 0xc9, 0xae, 0xb8, 0xec, 0x5f, 0x29, 0xbb, 0xf2, 0x27, 0x95, 0x72, - 0x29, 0xe5, 0x54, 0x45, 0xae, 0x28, 0x25, 0xfd, 0xb0, 0xc1, 0xe8, 0x92, 0xe8, 0x47, 0x12, 0x55, - 0x25, 0xaa, 0xd8, 0xb1, 0x2f, 0x8f, 0x4a, 0xf5, 0x73, 0xba, 0x67, 0x67, 0x71, 0x8b, 0xbb, 0x06, - 0x4e, 0x65, 0xff, 0x02, 0xf6, 0xeb, 0xee, 0xef, 0xeb, 0xee, 0xe9, 0xfe, 0xfa, 0x7b, 0xf5, 0xd7, - 0xb0, 0xde, 0xf0, 0x93, 0x66, 0x77, 0x73, 0xb6, 0x16, 0xb6, 0xcf, 0x79, 0x51, 0x23, 0xec, 0x44, - 0xe1, 0xcb, 0xec, 0x9f, 0x77, 0x5e, 0x0f, 0xa3, 0xed, 0xad, 0x56, 0x78, 0x3d, 0x3e, 0xb7, 0xf3, - 0xf4, 0xb9, 0xce, 0x76, 0xe3, 0x9c, 0xd7, 0xf1, 0xe3, 0x73, 0x12, 0x7a, 0x6e, 0xe7, 0x29, 0xaf, - 0xd5, 0x69, 0x7a, 0x4f, 0x9d, 0x6b, 0x90, 0x80, 0x44, 0x5e, 0x42, 0xea, 0xb3, 0x9d, 0x28, 0x4c, - 0x42, 0xf4, 0x81, 0x14, 0xe3, 0xac, 0xc4, 0xc8, 0xfe, 0xf9, 0xb0, 0xc2, 0x38, 0xbb, 0xf3, 0xf4, - 0x6c, 0x67, 0xbb, 0x31, 0x4b, 0x31, 0xce, 0x4a, 0xe8, 0xac, 0xc4, 0x38, 0xfd, 0x4e, 0xad, 0x4f, - 0x8d, 0xb0, 0x11, 0x9e, 0x63, 0x88, 0x37, 0xbb, 0x5b, 0xec, 0x17, 0xfb, 0xc1, 0xfe, 0xe3, 0x04, - 0xa7, 0xdd, 0xed, 0x67, 0xe2, 0x59, 0x3f, 0xa4, 0xfd, 0x3b, 0x57, 0x0b, 0x23, 0x72, 0x6e, 0xa7, - 0xa7, 0x53, 0xd3, 0xef, 0xd0, 0xea, 0x74, 0xc2, 0x96, 0x5f, 0xdb, 0xcd, 0xab, 0xf5, 0xae, 0xb4, - 0x56, 0xdb, 0xab, 0x35, 0xfd, 0x80, 0x44, 0xbb, 0xe9, 0xd0, 0xdb, 0x24, 0xf1, 0xf2, 0x5a, 0x9d, - 0xeb, 0xd7, 0x2a, 0xea, 0x06, 0x89, 0xdf, 0x26, 0x3d, 0x0d, 0xfe, 0xfa, 0xed, 0x1a, 0xc4, 0xb5, - 0x26, 0x69, 0x7b, 0x3d, 0xed, 0x9e, 0xee, 0xd7, 0xae, 0x9b, 0xf8, 0xad, 0x73, 0x7e, 0x90, 0xc4, - 0x49, 0x94, 0x6d, 0xe4, 0x5e, 0x80, 0x91, 0xb9, 0x76, 0xd8, 0x0d, 0x12, 0xf4, 0x5e, 0x28, 0xee, - 0x78, 0xad, 0x2e, 0xa9, 0x38, 0x0f, 0x3b, 0x8f, 0x97, 0xe6, 0x1f, 0xfd, 0xce, 0xde, 0xcc, 0x7d, - 0x37, 0xf7, 0x66, 0x8a, 0xcf, 0x53, 0xe0, 0xad, 0xbd, 0x99, 0x93, 0x24, 0xa8, 0x85, 0x75, 0x3f, - 0x68, 0x9c, 0x7b, 0x39, 0x0e, 0x83, 0xd9, 0x2b, 0xdd, 0xf6, 0x26, 0x89, 0x30, 0x6f, 0xe3, 0xfe, - 0xbb, 0x02, 0x1c, 0x9b, 0x8b, 0x6a, 0x4d, 0x7f, 0x87, 0x54, 0x13, 0x8a, 0xbf, 0xb1, 0x8b, 0x9a, - 0x30, 0x94, 0x78, 0x11, 0x43, 0x57, 0x3e, 0xbf, 0x3a, 0x7b, 0xb7, 0xdf, 0x7d, 0x76, 0xc3, 0x8b, - 0x24, 0xee, 0xf9, 0xd1, 0x9b, 0x7b, 0x33, 0x43, 0x1b, 0x5e, 0x84, 0x29, 0x09, 0xd4, 0x82, 0xe1, - 0x20, 0x0c, 0x48, 0xa5, 0xc0, 0x48, 0x5d, 0xb9, 0x7b, 0x52, 0x57, 0xc2, 0x40, 0x8d, 0x63, 0x7e, - 0xec, 0xe6, 0xde, 0xcc, 0x30, 0x85, 0x60, 0x46, 0x85, 0x8e, 0xeb, 0x55, 0xbf, 0x53, 0x19, 0xb2, - 0x35, 0xae, 0x17, 0xfd, 0x8e, 0x39, 0xae, 0x17, 0xfd, 0x0e, 0xa6, 0x24, 0xdc, 0xcf, 0x16, 0xa0, - 0x34, 0x17, 0x35, 0xba, 0x6d, 0x12, 0x24, 0x31, 0xfa, 0x18, 0x40, 0xc7, 0x8b, 0xbc, 0x36, 0x49, - 0x48, 0x14, 0x57, 0x9c, 0x87, 0x87, 0x1e, 0x2f, 0x9f, 0x5f, 0xb9, 0x7b, 0xf2, 0xeb, 0x12, 0xe7, - 0x3c, 0x12, 0x9f, 0x1c, 0x14, 0x28, 0xc6, 0x1a, 0x49, 0xf4, 0x1a, 0x94, 0xbc, 0x28, 0xf1, 0xb7, - 0xbc, 0x5a, 0x12, 0x57, 0x0a, 0x8c, 0xfe, 0xb3, 0x77, 0x4f, 0x7f, 0x4e, 0xa0, 0x9c, 0x3f, 0x2e, - 0xc8, 0x97, 0x24, 0x24, 0xc6, 0x29, 0x3d, 0xf7, 0xf7, 0x86, 0xa1, 0x3c, 0x17, 0x25, 0xcb, 0x0b, - 0xd5, 0xc4, 0x4b, 0xba, 0x31, 0xfa, 0x43, 0x07, 0x4e, 0xc4, 0x7c, 0xda, 0x7c, 0x12, 0xaf, 0x47, - 0x61, 0x8d, 0xc4, 0x31, 0xa9, 0x8b, 0x79, 0xd9, 0xb2, 0xd2, 0x2f, 0x49, 0x6c, 0xb6, 0xda, 0x4b, - 0xe8, 0x42, 0x90, 0x44, 0xbb, 0xf3, 0x4f, 0x89, 0x3e, 0x9f, 0xc8, 0xa9, 0xf1, 0xe6, 0xdb, 0x33, - 0x48, 0x0e, 0x85, 0x62, 0xe2, 0x9f, 0x18, 0xe7, 0xf5, 0x1a, 0x7d, 0xd5, 0x81, 0xf1, 0x4e, 0x58, - 0x8f, 0x31, 0xa9, 0x85, 0xdd, 0x0e, 0xa9, 0x8b, 0xe9, 0xfd, 0xb0, 0xdd, 0x61, 0xac, 0x6b, 0x14, - 0x78, 0xff, 0x4f, 0x8a, 0xfe, 0x8f, 0xeb, 0x45, 0xd8, 0xe8, 0x0a, 0x7a, 0x06, 0xc6, 0x83, 0x30, - 0xa9, 0x76, 0x48, 0xcd, 0xdf, 0xf2, 0x49, 0x9d, 0x2d, 0xfc, 0xb1, 0xb4, 0xe5, 0x15, 0xad, 0x0c, - 0x1b, 0x35, 0xa7, 0x97, 0xa0, 0xd2, 0x6f, 0xe6, 0xd0, 0x14, 0x0c, 0x6d, 0x93, 0x5d, 0xce, 0x6c, - 0x30, 0xfd, 0x17, 0x9d, 0x94, 0x0c, 0x88, 0x6e, 0xe3, 0x31, 0xc1, 0x59, 0xde, 0x53, 0x78, 0xc6, - 0x99, 0x7e, 0x3f, 0x1c, 0xef, 0xe9, 0xfa, 0x41, 0x10, 0xb8, 0xdf, 0x1d, 0x81, 0x31, 0xf9, 0x29, - 0xd0, 0xc3, 0x30, 0x1c, 0x78, 0x6d, 0xc9, 0xe7, 0xc6, 0xc5, 0x38, 0x86, 0xaf, 0x78, 0x6d, 0xba, - 0xc3, 0xbd, 0x36, 0xa1, 0x35, 0x3a, 0x5e, 0xd2, 0x64, 0x78, 0xb4, 0x1a, 0xeb, 0x5e, 0xd2, 0xc4, - 0xac, 0x04, 0x3d, 0x08, 0xc3, 0xed, 0xb0, 0x4e, 0xd8, 0x5c, 0x14, 0x39, 0x87, 0x58, 0x0d, 0xeb, - 0x04, 0x33, 0x28, 0x6d, 0xbf, 0x15, 0x85, 0xed, 0xca, 0xb0, 0xd9, 0x7e, 0x29, 0x0a, 0xdb, 0x98, - 0x95, 0xa0, 0xaf, 0x38, 0x30, 0x25, 0xd7, 0xf6, 0xe5, 0xb0, 0xe6, 0x25, 0x7e, 0x18, 0x54, 0x8a, - 0x8c, 0xa3, 0x60, 0x7b, 0x5b, 0x4a, 0x62, 0x9e, 0xaf, 0x88, 0x2e, 0x4c, 0x65, 0x4b, 0x70, 0x4f, - 0x2f, 0xd0, 0x79, 0x80, 0x46, 0x2b, 0xdc, 0xf4, 0x5a, 0x74, 0x42, 0x2a, 0x23, 0x6c, 0x08, 0x8a, - 0x33, 0x2c, 0xab, 0x12, 0xac, 0xd5, 0x42, 0x37, 0x60, 0xd4, 0xe3, 0xdc, 0xbf, 0x32, 0xca, 0x06, - 0xf1, 0x9c, 0x8d, 0x41, 0x18, 0xc7, 0xc9, 0x7c, 0xf9, 0xe6, 0xde, 0xcc, 0xa8, 0x00, 0x62, 0x49, - 0x0e, 0x3d, 0x09, 0x63, 0x61, 0x87, 0xf6, 0xdb, 0x6b, 0x55, 0xc6, 0xd8, 0xc2, 0x9c, 0x12, 0x7d, - 0x1d, 0x5b, 0x13, 0x70, 0xac, 0x6a, 0xa0, 0x27, 0x60, 0x34, 0xee, 0x6e, 0xd2, 0xef, 0x58, 0x29, - 0xb1, 0x81, 0x1d, 0x13, 0x95, 0x47, 0xab, 0x1c, 0x8c, 0x65, 0x39, 0x7a, 0x37, 0x94, 0x23, 0x52, - 0xeb, 0x46, 0x31, 0xa1, 0x1f, 0xb6, 0x02, 0x0c, 0xf7, 0x09, 0x51, 0xbd, 0x8c, 0xd3, 0x22, 0xac, - 0xd7, 0x43, 0xef, 0x83, 0x49, 0xfa, 0x81, 0x2f, 0xdc, 0xe8, 0x44, 0x24, 0x8e, 0xe9, 0x57, 0x2d, - 0x33, 0x42, 0xa7, 0x45, 0xcb, 0xc9, 0x25, 0xa3, 0x14, 0x67, 0x6a, 0xa3, 0xd7, 0x01, 0x3c, 0xc5, - 0x33, 0x2a, 0xe3, 0x6c, 0x32, 0x2f, 0xdb, 0x5b, 0x11, 0xcb, 0x0b, 0xf3, 0x93, 0xf4, 0x3b, 0xa6, - 0xbf, 0xb1, 0x46, 0x8f, 0xce, 0x4f, 0x9d, 0xb4, 0x48, 0x42, 0xea, 0x95, 0x09, 0x36, 0x60, 0x35, - 0x3f, 0x8b, 0x1c, 0x8c, 0x65, 0xb9, 0xfb, 0xf7, 0x0b, 0xa0, 0x61, 0x41, 0xf3, 0x30, 0x26, 0xf8, - 0x9a, 0xd8, 0x92, 0xf3, 0x8f, 0xc9, 0xef, 0x20, 0xbf, 0xe0, 0xad, 0xbd, 0x5c, 0x7e, 0xa8, 0xda, - 0xa1, 0x37, 0xa0, 0xdc, 0x09, 0xeb, 0xab, 0x24, 0xf1, 0xea, 0x5e, 0xe2, 0x89, 0xd3, 0xdc, 0xc2, - 0x09, 0x23, 0x31, 0xce, 0x1f, 0xa3, 0x9f, 0x6e, 0x3d, 0x25, 0x81, 0x75, 0x7a, 0xe8, 0x59, 0x40, - 0x31, 0x89, 0x76, 0xfc, 0x1a, 0x99, 0xab, 0xd5, 0xa8, 0x48, 0xc4, 0x36, 0xc0, 0x10, 0x1b, 0xcc, - 0xb4, 0x18, 0x0c, 0xaa, 0xf6, 0xd4, 0xc0, 0x39, 0xad, 0xdc, 0xef, 0x15, 0x60, 0x52, 0x1b, 0x6b, - 0x87, 0xd4, 0xd0, 0x5b, 0x0e, 0x1c, 0x53, 0xc7, 0xd9, 0xfc, 0xee, 0x15, 0xba, 0xaa, 0xf8, 0x61, - 0x45, 0x6c, 0x7e, 0x5f, 0x4a, 0x4b, 0xfd, 0x14, 0x74, 0x38, 0xaf, 0x3f, 0x23, 0xc6, 0x70, 0x2c, - 0x53, 0x8a, 0xb3, 0xdd, 0x9a, 0xfe, 0xb2, 0x03, 0x27, 0xf3, 0x50, 0xe4, 0xf0, 0xdc, 0xa6, 0xce, - 0x73, 0xad, 0x32, 0x2f, 0x4a, 0x95, 0x0e, 0x46, 0xe7, 0xe3, 0xff, 0xaf, 0x00, 0x53, 0xfa, 0x12, - 0x62, 0x92, 0xc0, 0xbf, 0x74, 0xe0, 0x94, 0x1c, 0x01, 0x26, 0x71, 0xb7, 0x95, 0x99, 0xde, 0xb6, - 0xd5, 0xe9, 0xe5, 0x27, 0xe9, 0x5c, 0x1e, 0x3d, 0x3e, 0xcd, 0x0f, 0x89, 0x69, 0x3e, 0x95, 0x5b, - 0x07, 0xe7, 0x77, 0x75, 0xfa, 0x9b, 0x0e, 0x4c, 0xf7, 0x47, 0x9a, 0x33, 0xf1, 0x1d, 0x73, 0xe2, - 0x5f, 0xb4, 0x37, 0x48, 0x4e, 0x9e, 0x4d, 0x3f, 0x1b, 0xac, 0xfe, 0x01, 0x7e, 0x6b, 0x0c, 0x7a, - 0xce, 0x10, 0xf4, 0x14, 0x94, 0x05, 0x3b, 0xbe, 0x1c, 0x36, 0x62, 0xd6, 0xc9, 0x31, 0xbe, 0xd7, - 0xe6, 0x52, 0x30, 0xd6, 0xeb, 0xa0, 0x3a, 0x14, 0xe2, 0xa7, 0x45, 0xd7, 0x2d, 0xb0, 0xb7, 0xea, - 0xd3, 0x4a, 0x8a, 0x1c, 0xb9, 0xb9, 0x37, 0x53, 0xa8, 0x3e, 0x8d, 0x0b, 0xf1, 0xd3, 0x54, 0x52, - 0x6f, 0xf8, 0x89, 0x3d, 0x49, 0x7d, 0xd9, 0x4f, 0x14, 0x1d, 0x26, 0xa9, 0x2f, 0xfb, 0x09, 0xa6, - 0x24, 0xa8, 0x06, 0xd2, 0x4c, 0x92, 0x0e, 0x3b, 0xf1, 0xad, 0x68, 0x20, 0x17, 0x37, 0x36, 0xd6, - 0x15, 0x2d, 0x26, 0x5f, 0x50, 0x08, 0x66, 0x54, 0xd0, 0x67, 0x1c, 0x3a, 0xe3, 0xbc, 0x30, 0x8c, - 0x76, 0x85, 0xe0, 0x70, 0xd5, 0xde, 0x12, 0x08, 0xa3, 0x5d, 0x45, 0x5c, 0x7c, 0x48, 0x55, 0x80, - 0x75, 0xd2, 0x6c, 0xe0, 0xf5, 0xad, 0x98, 0xc9, 0x09, 0x76, 0x06, 0xbe, 0xb8, 0x54, 0xcd, 0x0c, - 0x7c, 0x71, 0xa9, 0x8a, 0x19, 0x15, 0xfa, 0x41, 0x23, 0xef, 0xba, 0x90, 0x31, 0x2c, 0x7c, 0x50, - 0xec, 0x5d, 0x37, 0x3f, 0x28, 0xf6, 0xae, 0x63, 0x4a, 0x82, 0x52, 0x0a, 0xe3, 0x98, 0x89, 0x14, - 0x56, 0x28, 0xad, 0x55, 0xab, 0x26, 0xa5, 0xb5, 0x6a, 0x15, 0x53, 0x12, 0x6c, 0x91, 0xd6, 0x62, - 0x26, 0x8f, 0xd8, 0x59, 0xa4, 0x0b, 0x19, 0x4a, 0xcb, 0x0b, 0x55, 0x4c, 0x49, 0x50, 0x96, 0xe1, - 0xbd, 0xda, 0x8d, 0xb8, 0x30, 0x53, 0x3e, 0xbf, 0x66, 0x61, 0xbd, 0x50, 0x74, 0x8a, 0x5a, 0xe9, - 0xe6, 0xde, 0x4c, 0x91, 0x81, 0x30, 0x27, 0xe4, 0xfe, 0xc1, 0x50, 0xca, 0x2e, 0x24, 0x3f, 0x47, - 0xbf, 0xc6, 0x0e, 0x42, 0xc1, 0x0b, 0x84, 0xe8, 0xeb, 0x1c, 0x9a, 0xe8, 0x7b, 0x82, 0x9f, 0x78, - 0x06, 0x39, 0x9c, 0xa5, 0x8f, 0xbe, 0xe0, 0xf4, 0xea, 0xb6, 0x9e, 0xfd, 0xb3, 0x2c, 0x3d, 0x98, - 0xf9, 0x59, 0xb1, 0xaf, 0xca, 0x3b, 0xfd, 0x19, 0x27, 0x15, 0x22, 0xe2, 0x7e, 0xe7, 0xc0, 0x47, - 0xcc, 0x73, 0xc0, 0xa2, 0x42, 0xae, 0xf3, 0xfd, 0xcf, 0x3a, 0x30, 0x21, 0xe1, 0x54, 0x3c, 0x8e, - 0xd1, 0x0d, 0x18, 0x93, 0x3d, 0x15, 0x5f, 0xcf, 0xa6, 0x2d, 0x40, 0x09, 0xf1, 0xaa, 0x33, 0x8a, - 0x9a, 0xfb, 0xd6, 0x08, 0xa0, 0xf4, 0xac, 0xea, 0x84, 0xb1, 0xcf, 0x38, 0xd1, 0x1d, 0x9c, 0x42, - 0x81, 0x76, 0x0a, 0x3d, 0x6f, 0xf3, 0x14, 0x4a, 0xbb, 0x65, 0x9c, 0x47, 0x5f, 0xc8, 0xf0, 0x6d, - 0x7e, 0x30, 0x7d, 0xf8, 0x50, 0xf8, 0xb6, 0xd6, 0x85, 0xfd, 0x39, 0xf8, 0x8e, 0xe0, 0xe0, 0xfc, - 0xe8, 0xfa, 0x05, 0xbb, 0x1c, 0x5c, 0xeb, 0x45, 0x96, 0x97, 0x47, 0x9c, 0xc3, 0xf2, 0xb3, 0xeb, - 0x9a, 0x55, 0x0e, 0xab, 0x51, 0x35, 0x79, 0x6d, 0xc4, 0x79, 0xed, 0x88, 0x2d, 0x9a, 0x1a, 0xaf, - 0xcd, 0xd2, 0x54, 0x5c, 0xf7, 0x55, 0xc9, 0x75, 0xf9, 0xa9, 0xf5, 0x82, 0x65, 0xae, 0xab, 0xd1, - 0xed, 0xe5, 0xbf, 0xaf, 0xc0, 0xa9, 0xde, 0x7a, 0x98, 0x6c, 0xa1, 0x73, 0x50, 0xaa, 0x85, 0xc1, - 0x96, 0xdf, 0x58, 0xf5, 0x3a, 0x42, 0x5f, 0x53, 0xbc, 0x68, 0x41, 0x16, 0xe0, 0xb4, 0x0e, 0x7a, - 0x88, 0x33, 0x1e, 0x6e, 0x11, 0x29, 0x8b, 0xaa, 0x43, 0x2b, 0x64, 0x97, 0x71, 0xa1, 0xf7, 0x8c, - 0x7d, 0xe5, 0xeb, 0x33, 0xf7, 0x7d, 0xfc, 0x8f, 0x1f, 0xbe, 0xcf, 0xfd, 0xa3, 0x21, 0x78, 0x20, - 0x97, 0xa6, 0x90, 0xd6, 0x7f, 0xcb, 0x90, 0xd6, 0xb5, 0x72, 0xc1, 0x45, 0xae, 0xd9, 0x14, 0x64, - 0x35, 0xf4, 0x79, 0x72, 0xb9, 0x56, 0x8c, 0xf3, 0x3b, 0x45, 0x27, 0x2a, 0xf0, 0xda, 0x24, 0xee, - 0x78, 0x35, 0x22, 0x46, 0xaf, 0x26, 0xea, 0x8a, 0x2c, 0xc0, 0x69, 0x1d, 0xae, 0x42, 0x6f, 0x79, - 0xdd, 0x56, 0x22, 0x0c, 0x65, 0x9a, 0x0a, 0xcd, 0xc0, 0x58, 0x96, 0xa3, 0x7f, 0xe0, 0x00, 0xea, - 0xa5, 0x2a, 0x36, 0xe2, 0xc6, 0x61, 0xcc, 0xc3, 0xfc, 0xe9, 0x9b, 0x9a, 0x12, 0xae, 0x8d, 0x34, - 0xa7, 0x1f, 0xda, 0x37, 0xfd, 0x68, 0x7a, 0x0e, 0x71, 0xe5, 0x60, 0x00, 0x1b, 0x1a, 0x33, 0xb5, - 0xd4, 0x6a, 0x24, 0x8e, 0xb9, 0x39, 0x4e, 0x37, 0xb5, 0x30, 0x30, 0x96, 0xe5, 0x68, 0x06, 0x8a, - 0x24, 0x8a, 0xc2, 0x48, 0xe8, 0xda, 0x6c, 0x19, 0x5f, 0xa0, 0x00, 0xcc, 0xe1, 0xee, 0x8f, 0x0a, - 0x50, 0xe9, 0xa7, 0x9d, 0xa0, 0xdf, 0xd5, 0xf4, 0x6a, 0xa1, 0x39, 0x09, 0xc5, 0x2f, 0x3c, 0x3c, - 0x9d, 0x28, 0xab, 0x00, 0xf6, 0xd1, 0xb0, 0x45, 0x29, 0xce, 0x76, 0x70, 0xfa, 0x8b, 0x9a, 0x86, - 0xad, 0xa3, 0xc8, 0x39, 0xe0, 0xb7, 0xcc, 0x03, 0x7e, 0xdd, 0xf6, 0xa0, 0xf4, 0x63, 0xfe, 0x4f, - 0x8a, 0x70, 0x42, 0x96, 0x56, 0x09, 0x3d, 0x2a, 0x9f, 0xeb, 0x92, 0x68, 0x17, 0x7d, 0xdf, 0x81, - 0x93, 0x5e, 0xd6, 0x74, 0xe3, 0x93, 0x43, 0x98, 0x68, 0x8d, 0xea, 0xec, 0x5c, 0x0e, 0x45, 0x3e, - 0xd1, 0xe7, 0xc5, 0x44, 0x9f, 0xcc, 0xab, 0xd2, 0xc7, 0xee, 0x9e, 0x3b, 0x00, 0xf4, 0x0c, 0x8c, - 0x4b, 0x38, 0x33, 0xf7, 0xf0, 0x2d, 0xae, 0x8c, 0xdb, 0x73, 0x5a, 0x19, 0x36, 0x6a, 0xd2, 0x96, - 0x09, 0x69, 0x77, 0x5a, 0x5e, 0x42, 0x34, 0x43, 0x91, 0x6a, 0xb9, 0xa1, 0x95, 0x61, 0xa3, 0x26, - 0x7a, 0x0c, 0x46, 0x82, 0xb0, 0x4e, 0x2e, 0xd5, 0x85, 0x81, 0x78, 0x52, 0xb4, 0x19, 0xb9, 0xc2, - 0xa0, 0x58, 0x94, 0xa2, 0x47, 0x53, 0x6b, 0x5c, 0x91, 0x6d, 0xa1, 0x72, 0x9e, 0x25, 0x0e, 0xfd, - 0x23, 0x07, 0x4a, 0xb4, 0xc5, 0xc6, 0x6e, 0x87, 0xd0, 0xb3, 0x8d, 0x7e, 0x91, 0xfa, 0xe1, 0x7c, - 0x91, 0x2b, 0x92, 0x8c, 0x69, 0xea, 0x28, 0x29, 0xf8, 0x9b, 0x6f, 0xcf, 0x8c, 0xc9, 0x1f, 0x38, - 0xed, 0xd5, 0xf4, 0x32, 0xdc, 0xdf, 0xf7, 0x6b, 0x1e, 0xc8, 0x15, 0xf0, 0xb7, 0x60, 0xd2, 0xec, - 0xc4, 0x81, 0xfc, 0x00, 0xff, 0x5c, 0xdb, 0x76, 0x7c, 0x5c, 0x82, 0x9f, 0xdd, 0x33, 0x69, 0x56, - 0x2d, 0x86, 0x45, 0xb1, 0xf4, 0xcc, 0xc5, 0xb0, 0x28, 0x16, 0xc3, 0xa2, 0xfb, 0x87, 0x4e, 0xba, - 0x35, 0x35, 0x31, 0x8f, 0x1e, 0xcc, 0xdd, 0xa8, 0x25, 0x18, 0xb1, 0x3a, 0x98, 0xaf, 0xe2, 0xcb, - 0x98, 0xc2, 0xd1, 0x17, 0x35, 0xee, 0x48, 0x9b, 0x75, 0x85, 0x5b, 0xc3, 0x92, 0x89, 0xde, 0x40, - 0xdc, 0xcb, 0xff, 0x44, 0x01, 0xce, 0x76, 0xc1, 0xfd, 0x42, 0x01, 0x1e, 0xda, 0x57, 0x68, 0xcd, - 0xed, 0xb8, 0x73, 0xcf, 0x3b, 0x4e, 0x8f, 0xb5, 0x88, 0x74, 0xc2, 0xab, 0xf8, 0xb2, 0xf8, 0x5e, - 0xea, 0x58, 0xc3, 0x1c, 0x8c, 0x65, 0x39, 0x15, 0x1d, 0xb6, 0xc9, 0xee, 0x52, 0x18, 0xb5, 0xbd, - 0x44, 0x70, 0x07, 0x25, 0x3a, 0xac, 0xc8, 0x02, 0x9c, 0xd6, 0x71, 0xbf, 0xef, 0x40, 0xb6, 0x03, - 0xc8, 0x83, 0xc9, 0x6e, 0x4c, 0x22, 0x7a, 0xa4, 0x56, 0x49, 0x2d, 0x22, 0x72, 0x79, 0x3e, 0x3a, - 0xcb, 0xbd, 0xfd, 0x74, 0x84, 0xb3, 0xb5, 0x30, 0x22, 0xb3, 0x3b, 0x4f, 0xcd, 0xf2, 0x1a, 0x2b, - 0x64, 0xb7, 0x4a, 0x5a, 0x84, 0xe2, 0x98, 0x47, 0x37, 0xf7, 0x66, 0x26, 0xaf, 0x1a, 0x08, 0x70, - 0x06, 0x21, 0x25, 0xd1, 0xf1, 0xe2, 0xf8, 0x7a, 0x18, 0xd5, 0x05, 0x89, 0xc2, 0x81, 0x49, 0xac, - 0x1b, 0x08, 0x70, 0x06, 0xa1, 0xfb, 0x3d, 0xaa, 0x3e, 0xea, 0x52, 0x2b, 0xfa, 0x3a, 0x95, 0x7d, - 0x28, 0x64, 0xbe, 0x15, 0x6e, 0x2e, 0x84, 0x41, 0xe2, 0xf9, 0x01, 0x91, 0xc1, 0x02, 0x1b, 0x96, - 0x64, 0x64, 0x03, 0x77, 0x6a, 0xc3, 0xef, 0x2d, 0xc3, 0x39, 0x7d, 0xa1, 0x32, 0xce, 0x66, 0x2b, - 0xdc, 0xcc, 0x7a, 0x01, 0x69, 0x25, 0xcc, 0x4a, 0xdc, 0x9f, 0x38, 0x70, 0xa6, 0x8f, 0x30, 0x8e, - 0xbe, 0xec, 0xc0, 0xc4, 0xe6, 0x4f, 0xc5, 0xd8, 0xcc, 0x6e, 0xa0, 0xf7, 0xc1, 0x24, 0x05, 0xd0, - 0x93, 0x48, 0xac, 0xcd, 0x82, 0xe9, 0xa1, 0x9a, 0x37, 0x4a, 0x71, 0xa6, 0xb6, 0xfb, 0xeb, 0x05, - 0xc8, 0xa1, 0x82, 0x9e, 0x84, 0x31, 0x12, 0xd4, 0x3b, 0xa1, 0x1f, 0x24, 0x82, 0x19, 0x29, 0xae, - 0x77, 0x41, 0xc0, 0xb1, 0xaa, 0x21, 0xf4, 0x0f, 0x31, 0x31, 0x85, 0x1e, 0xfd, 0x43, 0xf4, 0x3c, - 0xad, 0x83, 0x1a, 0x30, 0xe5, 0x71, 0xff, 0x0a, 0x5b, 0x7b, 0x6c, 0x99, 0x0e, 0x1d, 0x64, 0x99, - 0x9e, 0x64, 0xee, 0xcf, 0x0c, 0x0a, 0xdc, 0x83, 0x14, 0xbd, 0x1b, 0xca, 0xdd, 0x98, 0x54, 0x17, - 0x57, 0x16, 0x22, 0x52, 0xe7, 0x5a, 0xb1, 0xe6, 0xf7, 0xbb, 0x9a, 0x16, 0x61, 0xbd, 0x9e, 0xfb, - 0xaf, 0x1c, 0x18, 0x9d, 0xf7, 0x6a, 0xdb, 0xe1, 0xd6, 0x16, 0x9d, 0x8a, 0x7a, 0x37, 0x4a, 0x0d, - 0x5b, 0xda, 0x54, 0x2c, 0x0a, 0x38, 0x56, 0x35, 0xd0, 0x06, 0x8c, 0xf0, 0x0d, 0x2f, 0xb6, 0xdd, - 0xcf, 0x6b, 0xe3, 0x51, 0x71, 0x3c, 0x6c, 0x39, 0x74, 0x13, 0xbf, 0x35, 0xcb, 0xe3, 0x78, 0x66, - 0x2f, 0x05, 0xc9, 0x5a, 0x54, 0x4d, 0x22, 0x3f, 0x68, 0xcc, 0x03, 0x3d, 0x2e, 0x96, 0x18, 0x0e, - 0x2c, 0x70, 0xd1, 0x61, 0xb4, 0xbd, 0x1b, 0x92, 0x9c, 0x60, 0x3f, 0x6a, 0x18, 0xab, 0x69, 0x11, - 0xd6, 0xeb, 0xb9, 0x7f, 0xe4, 0x40, 0x69, 0xde, 0x8b, 0xfd, 0xda, 0x5f, 0x22, 0xe6, 0xf3, 0x21, - 0x28, 0x2e, 0x78, 0xb5, 0x26, 0x41, 0x57, 0xb3, 0x4a, 0x6f, 0xf9, 0xfc, 0xe3, 0x79, 0x64, 0x94, - 0x02, 0xac, 0x53, 0x9a, 0xe8, 0xa7, 0x1a, 0xbb, 0x6f, 0x3b, 0x30, 0xb9, 0xd0, 0xf2, 0x49, 0x90, - 0x2c, 0x90, 0x28, 0x61, 0x13, 0xd7, 0x80, 0xa9, 0x9a, 0x82, 0xdc, 0xc9, 0xd4, 0xb1, 0xd5, 0xba, - 0x90, 0x41, 0x81, 0x7b, 0x90, 0xa2, 0x3a, 0x1c, 0xe3, 0xb0, 0x74, 0x57, 0x1c, 0x68, 0xfe, 0x98, - 0x75, 0x74, 0xc1, 0xc4, 0x80, 0xb3, 0x28, 0xdd, 0x1f, 0x3b, 0x70, 0x66, 0xa1, 0xd5, 0x8d, 0x13, - 0x12, 0x5d, 0x13, 0xdc, 0x48, 0x8a, 0xb7, 0xe8, 0x23, 0x30, 0xd6, 0x96, 0x1e, 0x5b, 0xe7, 0x36, - 0x0b, 0x98, 0xf1, 0x33, 0x5a, 0x9b, 0x76, 0x66, 0x6d, 0xf3, 0x65, 0x52, 0x4b, 0x56, 0x49, 0xe2, - 0xa5, 0xe1, 0x05, 0x29, 0x0c, 0x2b, 0xac, 0xa8, 0x03, 0xc3, 0x71, 0x87, 0xd4, 0xec, 0x45, 0x77, - 0xc9, 0x31, 0x54, 0x3b, 0xa4, 0x96, 0xf2, 0x75, 0xe6, 0x6b, 0x64, 0x94, 0xdc, 0xff, 0xed, 0xc0, - 0x03, 0x7d, 0xc6, 0x7b, 0xd9, 0x8f, 0x13, 0xf4, 0x52, 0xcf, 0x98, 0x67, 0x07, 0x1b, 0x33, 0x6d, - 0xcd, 0x46, 0xac, 0x18, 0x82, 0x84, 0x68, 0xe3, 0xfd, 0x28, 0x14, 0xfd, 0x84, 0xb4, 0xa5, 0x19, - 0xda, 0x82, 0xc1, 0xa8, 0xcf, 0x58, 0xe6, 0x27, 0x64, 0x8c, 0xdf, 0x25, 0x4a, 0x0f, 0x73, 0xb2, - 0xee, 0x36, 0x8c, 0x2c, 0x84, 0xad, 0x6e, 0x3b, 0x18, 0x2c, 0x52, 0x26, 0xd9, 0xed, 0x90, 0xec, - 0x19, 0xc9, 0xc4, 0x7f, 0x56, 0x22, 0x0d, 0x47, 0x43, 0xf9, 0x86, 0x23, 0xf7, 0x5f, 0x3b, 0x40, - 0x77, 0x55, 0xdd, 0x17, 0x9e, 0x44, 0x8e, 0x8e, 0x13, 0x7c, 0x48, 0x47, 0x77, 0x6b, 0x6f, 0x66, - 0x42, 0x55, 0xd4, 0xf0, 0x7f, 0x08, 0x46, 0x62, 0xa6, 0x92, 0x8b, 0x3e, 0x2c, 0x49, 0xf9, 0x99, - 0x2b, 0xea, 0xb7, 0xf6, 0x66, 0x06, 0x0a, 0xdb, 0x9c, 0x55, 0xb8, 0x85, 0xd3, 0x53, 0x60, 0xa5, - 0x02, 0x5f, 0x9b, 0xc4, 0xb1, 0xd7, 0x90, 0x1a, 0x9e, 0x12, 0xf8, 0x56, 0x39, 0x18, 0xcb, 0x72, - 0xf7, 0x4b, 0x0e, 0x4c, 0xa8, 0xc3, 0x8b, 0x8a, 0xef, 0xe8, 0x8a, 0x7e, 0xcc, 0xf1, 0x95, 0xf2, - 0x50, 0x1f, 0x8e, 0x23, 0x0e, 0xf2, 0xfd, 0x4f, 0xc1, 0x77, 0xc1, 0x78, 0x9d, 0x74, 0x48, 0x50, - 0x27, 0x41, 0x8d, 0xaa, 0xdf, 0x74, 0x85, 0x94, 0xe6, 0xa7, 0xa8, 0xbe, 0xb9, 0xa8, 0xc1, 0xb1, - 0x51, 0xcb, 0xfd, 0x86, 0x03, 0xf7, 0x2b, 0x74, 0x55, 0x92, 0x60, 0x92, 0x44, 0xbb, 0x2a, 0x4c, - 0xf3, 0x60, 0xa7, 0xd5, 0x35, 0x2a, 0xff, 0x26, 0x11, 0x27, 0x7e, 0x67, 0xc7, 0x55, 0x99, 0x4b, - 0xcb, 0x0c, 0x09, 0x96, 0xd8, 0xdc, 0x5f, 0x1d, 0x82, 0x93, 0x7a, 0x27, 0x15, 0x83, 0xf9, 0x25, - 0x07, 0x40, 0xcd, 0x00, 0x3d, 0x90, 0x87, 0xec, 0xf8, 0xae, 0x8c, 0x2f, 0x95, 0xb2, 0x20, 0x05, - 0x8e, 0xb1, 0x46, 0x16, 0xbd, 0x00, 0xe3, 0x3b, 0x74, 0x53, 0x90, 0x55, 0x2a, 0x2e, 0xc4, 0x95, - 0x21, 0xd6, 0x8d, 0x99, 0xbc, 0x8f, 0xf9, 0x7c, 0x5a, 0x2f, 0x35, 0x07, 0x68, 0xc0, 0x18, 0x1b, - 0xa8, 0xa8, 0xa6, 0x33, 0x11, 0xe9, 0x9f, 0x44, 0xd8, 0xc4, 0x3f, 0x68, 0x71, 0x8c, 0xd9, 0xaf, - 0x3e, 0x7f, 0xfc, 0xe6, 0xde, 0xcc, 0x84, 0x01, 0xc2, 0x66, 0x27, 0xdc, 0x17, 0x80, 0xcd, 0x85, - 0x1f, 0x74, 0xc9, 0x5a, 0x80, 0x1e, 0x91, 0x36, 0x3a, 0xee, 0x57, 0x51, 0x9c, 0x43, 0xb7, 0xd3, - 0x51, 0x5d, 0x76, 0xcb, 0xf3, 0x5b, 0x2c, 0x7c, 0x91, 0xd6, 0x52, 0xba, 0xec, 0x12, 0x83, 0x62, - 0x51, 0xea, 0xce, 0xc2, 0xe8, 0x02, 0x1d, 0x3b, 0x89, 0x28, 0x5e, 0x3d, 0xea, 0x78, 0xc2, 0x88, - 0x3a, 0x96, 0xd1, 0xc5, 0x1b, 0x70, 0x6a, 0x21, 0x22, 0x5e, 0x42, 0xaa, 0x4f, 0xcf, 0x77, 0x6b, - 0xdb, 0x24, 0xe1, 0xa1, 0x5d, 0x31, 0x7a, 0x2f, 0x4c, 0x84, 0xec, 0xc8, 0xb8, 0x1c, 0xd6, 0xb6, - 0xfd, 0xa0, 0x21, 0x4c, 0xae, 0xa7, 0x04, 0x96, 0x89, 0x35, 0xbd, 0x10, 0x9b, 0x75, 0xdd, 0xff, - 0x54, 0x80, 0xf1, 0x85, 0x28, 0x0c, 0x24, 0x5b, 0x3c, 0x82, 0xa3, 0x2c, 0x31, 0x8e, 0x32, 0x0b, - 0xee, 0x4e, 0xbd, 0xff, 0xfd, 0x8e, 0x33, 0xf4, 0xba, 0x62, 0x91, 0x43, 0xb6, 0x54, 0x10, 0x83, - 0x2e, 0xc3, 0x9d, 0x7e, 0x6c, 0x93, 0x81, 0xba, 0xff, 0xd9, 0x81, 0x29, 0xbd, 0xfa, 0x11, 0x9c, - 0xa0, 0xb1, 0x79, 0x82, 0x5e, 0xb1, 0x3b, 0xde, 0x3e, 0xc7, 0xe6, 0xbf, 0x18, 0x35, 0xc7, 0xc9, - 0x7c, 0xdd, 0x5f, 0x71, 0x60, 0xfc, 0xba, 0x06, 0x10, 0x83, 0xb5, 0x2d, 0xc4, 0xbc, 0x43, 0xb2, - 0x19, 0x1d, 0x7a, 0x2b, 0xf3, 0x1b, 0x1b, 0x3d, 0xa1, 0x7c, 0x3f, 0xae, 0x35, 0x49, 0xbd, 0xdb, - 0x92, 0xc7, 0xb7, 0x9a, 0xd2, 0xaa, 0x80, 0x63, 0x55, 0x03, 0xbd, 0x04, 0xc7, 0x6b, 0x61, 0x50, - 0xeb, 0x46, 0x11, 0x09, 0x6a, 0xbb, 0xeb, 0xec, 0x8e, 0x84, 0x38, 0x10, 0x67, 0x45, 0xb3, 0xe3, - 0x0b, 0xd9, 0x0a, 0xb7, 0xf2, 0x80, 0xb8, 0x17, 0x11, 0x77, 0x16, 0xc4, 0xf4, 0xc8, 0x12, 0x0a, - 0x97, 0xe6, 0x2c, 0x60, 0x60, 0x2c, 0xcb, 0xd1, 0x55, 0x38, 0x13, 0x27, 0x5e, 0x94, 0xf8, 0x41, - 0x63, 0x91, 0x78, 0xf5, 0x96, 0x1f, 0x50, 0x55, 0x22, 0x0c, 0xea, 0xdc, 0x95, 0x38, 0x34, 0xff, - 0xc0, 0xcd, 0xbd, 0x99, 0x33, 0xd5, 0xfc, 0x2a, 0xb8, 0x5f, 0x5b, 0xf4, 0x21, 0x98, 0x16, 0xee, - 0x88, 0xad, 0x6e, 0xeb, 0xd9, 0x70, 0x33, 0xbe, 0xe8, 0xc7, 0x54, 0x8f, 0xbf, 0xec, 0xb7, 0xfd, - 0x84, 0x39, 0x0c, 0x8b, 0xf3, 0x67, 0x6f, 0xee, 0xcd, 0x4c, 0x57, 0xfb, 0xd6, 0xc2, 0xfb, 0x60, - 0x40, 0x18, 0x4e, 0x73, 0xe6, 0xd7, 0x83, 0x7b, 0x94, 0xe1, 0x9e, 0xbe, 0xb9, 0x37, 0x73, 0x7a, - 0x29, 0xb7, 0x06, 0xee, 0xd3, 0x92, 0x7e, 0xc1, 0xc4, 0x6f, 0x93, 0x57, 0xc3, 0x80, 0xb0, 0x40, - 0x15, 0xed, 0x0b, 0x6e, 0x08, 0x38, 0x56, 0x35, 0xd0, 0xcb, 0xe9, 0x4a, 0xa4, 0xdb, 0x45, 0x04, - 0x9c, 0x1c, 0x9c, 0xc3, 0x31, 0xd5, 0xe4, 0x9a, 0x86, 0x89, 0x45, 0x52, 0x1a, 0xb8, 0xd1, 0x27, - 0x1c, 0x18, 0x8f, 0x93, 0x50, 0xdd, 0x6b, 0x10, 0x11, 0x27, 0x16, 0x96, 0x7d, 0x55, 0xc3, 0xca, - 0x05, 0x1f, 0x1d, 0x82, 0x0d, 0xaa, 0xe8, 0xe7, 0xa0, 0x24, 0x17, 0x70, 0x5c, 0x29, 0x33, 0x59, - 0x89, 0xa9, 0x71, 0x72, 0x7d, 0xc7, 0x38, 0x2d, 0x77, 0x7f, 0x34, 0x04, 0xa8, 0x97, 0xad, 0xa1, - 0x15, 0x18, 0xf1, 0x6a, 0x89, 0xbf, 0x23, 0xa3, 0x09, 0x1f, 0xc9, 0x3b, 0xf2, 0xf9, 0xf4, 0x60, - 0xb2, 0x45, 0xe8, 0xaa, 0x26, 0x29, 0x2f, 0x9c, 0x63, 0x4d, 0xb1, 0x40, 0x81, 0x42, 0x38, 0xde, - 0xf2, 0xe2, 0x44, 0xd2, 0xaf, 0xd3, 0xcf, 0x24, 0x0e, 0x83, 0x9f, 0x1d, 0xec, 0x43, 0xd0, 0x16, - 0xf3, 0xa7, 0xe8, 0x6e, 0xbb, 0x9c, 0x45, 0x84, 0x7b, 0x71, 0xa3, 0x8f, 0x31, 0xd9, 0x89, 0x0b, - 0xb6, 0x52, 0x68, 0x59, 0xb1, 0x22, 0x57, 0x70, 0x9c, 0x86, 0xdc, 0x24, 0xc8, 0x60, 0x8d, 0x24, - 0x3a, 0x07, 0x25, 0xb6, 0x2b, 0x48, 0x9d, 0xf0, 0xbd, 0x3d, 0x94, 0x8a, 0xb8, 0x55, 0x59, 0x80, - 0xd3, 0x3a, 0x9a, 0x0c, 0xc1, 0xb7, 0x73, 0x1f, 0x19, 0x02, 0x3d, 0x03, 0xc5, 0x4e, 0xd3, 0x8b, - 0x65, 0x84, 0xba, 0x2b, 0x79, 0xf2, 0x3a, 0x05, 0x32, 0xc6, 0xa3, 0x7d, 0x4b, 0x06, 0xc4, 0xbc, - 0x81, 0xfb, 0x6f, 0x00, 0x46, 0x17, 0xe7, 0x96, 0x37, 0xbc, 0x78, 0x7b, 0x00, 0x0d, 0x87, 0x6e, - 0x32, 0x21, 0x8a, 0x66, 0xd9, 0xa4, 0x14, 0x51, 0xb1, 0xaa, 0x81, 0x02, 0x18, 0xf1, 0x03, 0xca, - 0x57, 0x2a, 0x93, 0xb6, 0xbc, 0x08, 0x4a, 0x5b, 0x63, 0x66, 0x9e, 0x4b, 0x0c, 0x3b, 0x16, 0x54, - 0xd0, 0xeb, 0x50, 0xf2, 0xe4, 0x05, 0x21, 0x71, 0xba, 0xaf, 0xd8, 0x30, 0x8f, 0x0b, 0x94, 0x7a, - 0x80, 0x92, 0x00, 0xe1, 0x94, 0x20, 0xfa, 0xb8, 0x03, 0x65, 0x39, 0x74, 0x4c, 0xb6, 0x84, 0xe7, - 0x7a, 0xd5, 0xde, 0x98, 0x31, 0xd9, 0xe2, 0xd1, 0x2b, 0x1a, 0x00, 0xeb, 0x24, 0x7b, 0x34, 0xa2, - 0xe2, 0x20, 0x1a, 0x11, 0xba, 0x0e, 0xa5, 0xeb, 0x7e, 0xd2, 0x64, 0xe7, 0xb7, 0xf0, 0x98, 0x2d, - 0xdd, 0x7d, 0xaf, 0x29, 0xba, 0x74, 0xc6, 0xae, 0x49, 0x02, 0x38, 0xa5, 0x45, 0xb7, 0x03, 0xfd, - 0xc1, 0x2e, 0x58, 0x31, 0xce, 0x5f, 0x32, 0x1b, 0xb0, 0x02, 0x9c, 0xd6, 0xa1, 0x53, 0x3c, 0x4e, - 0x7f, 0x55, 0xc9, 0x2b, 0x5d, 0xca, 0x5a, 0x44, 0x44, 0xa2, 0x85, 0x75, 0x25, 0x31, 0xf2, 0xc9, - 0xba, 0xa6, 0xd1, 0xc0, 0x06, 0x45, 0xba, 0x47, 0xae, 0x37, 0x49, 0x20, 0x6e, 0x4c, 0xa8, 0x3d, - 0x72, 0xad, 0x49, 0x02, 0xcc, 0x4a, 0xd0, 0xeb, 0x5c, 0x43, 0xe3, 0xaa, 0x82, 0xe0, 0xf5, 0x97, - 0xed, 0x68, 0x2f, 0x1c, 0x27, 0xbf, 0xb4, 0x90, 0xfe, 0xc6, 0x1a, 0x3d, 0xca, 0x31, 0xc2, 0xe0, - 0xc2, 0x0d, 0x3f, 0x11, 0x57, 0x2d, 0x14, 0xc7, 0x58, 0x63, 0x50, 0x2c, 0x4a, 0x79, 0x64, 0x06, - 0x5d, 0x04, 0x31, 0xbb, 0x57, 0x51, 0xd2, 0x23, 0x33, 0x18, 0x18, 0xcb, 0x72, 0xf4, 0x0f, 0x1d, - 0x28, 0x36, 0xc3, 0x70, 0x3b, 0xae, 0x4c, 0xb0, 0xc5, 0x61, 0x41, 0x62, 0x16, 0x1c, 0x67, 0xf6, - 0x22, 0x45, 0x6b, 0x5e, 0x1e, 0x2b, 0x32, 0xd8, 0xad, 0xbd, 0x99, 0xc9, 0xcb, 0xfe, 0x16, 0xa9, - 0xed, 0xd6, 0x5a, 0x84, 0x41, 0xde, 0x7c, 0x5b, 0x83, 0x5c, 0xd8, 0x21, 0x41, 0x82, 0x79, 0xaf, - 0xa6, 0x3f, 0xeb, 0x00, 0xa4, 0x88, 0x72, 0x5c, 0xa0, 0xc4, 0x0c, 0x1a, 0xb0, 0xa0, 0x2e, 0x1b, - 0x5d, 0xd3, 0x7d, 0xaa, 0xff, 0xd6, 0x81, 0x32, 0x1d, 0x9c, 0x64, 0x81, 0x8f, 0xc1, 0x48, 0xe2, - 0x45, 0x0d, 0x22, 0xdd, 0x00, 0xea, 0x73, 0x6c, 0x30, 0x28, 0x16, 0xa5, 0x28, 0x80, 0x62, 0xe2, - 0xc5, 0xdb, 0x52, 0x48, 0xbf, 0x64, 0x6d, 0x8a, 0x53, 0xf9, 0x9c, 0xfe, 0x8a, 0x31, 0x27, 0x83, - 0x1e, 0x87, 0x31, 0x7a, 0x74, 0x2c, 0x79, 0xb1, 0x8c, 0xcc, 0x19, 0xa7, 0x4c, 0x7c, 0x49, 0xc0, - 0xb0, 0x2a, 0x75, 0x7f, 0xbd, 0x00, 0xc3, 0x8b, 0x5c, 0x5d, 0x1b, 0x89, 0xc3, 0x6e, 0x54, 0x23, - 0x42, 0x6c, 0xb7, 0xb0, 0xa6, 0x29, 0xde, 0x2a, 0xc3, 0xa9, 0x29, 0x4c, 0xec, 0x37, 0x16, 0xb4, - 0xd0, 0x17, 0x1d, 0x98, 0x4c, 0x22, 0x2f, 0x88, 0xb7, 0x98, 0xc3, 0xc5, 0x0f, 0x03, 0x31, 0x45, - 0x16, 0x56, 0xe1, 0x86, 0x81, 0xb7, 0x9a, 0x90, 0x4e, 0xea, 0xf7, 0x31, 0xcb, 0x70, 0xa6, 0x0f, - 0xee, 0x6f, 0x38, 0x00, 0x69, 0xef, 0xd1, 0x67, 0x1c, 0x98, 0xf0, 0xf4, 0x88, 0x50, 0x31, 0x47, - 0x6b, 0xf6, 0xbc, 0xb3, 0x0c, 0x2d, 0xb7, 0x54, 0x18, 0x20, 0x6c, 0x12, 0x76, 0xdf, 0x0d, 0x45, - 0xb6, 0x3b, 0x98, 0x4a, 0x23, 0x2c, 0xdb, 0x59, 0x53, 0x96, 0xb4, 0x78, 0x63, 0x55, 0xc3, 0x7d, - 0x09, 0x26, 0x2f, 0xdc, 0x20, 0xb5, 0x6e, 0x12, 0x46, 0xdc, 0xae, 0xdf, 0xe7, 0x06, 0x90, 0x73, - 0x47, 0x37, 0x80, 0xbe, 0xed, 0x40, 0x59, 0x0b, 0x0f, 0xa4, 0x27, 0x75, 0x63, 0xa1, 0xca, 0xcd, - 0x17, 0x62, 0xaa, 0x56, 0xac, 0x04, 0x20, 0x72, 0x94, 0xe9, 0x31, 0xa2, 0x40, 0x38, 0x25, 0x78, - 0x9b, 0xf0, 0x3d, 0xf7, 0x0f, 0x1c, 0x38, 0x95, 0x1b, 0xcb, 0x78, 0x8f, 0xbb, 0x6d, 0xb8, 0xd0, - 0x0b, 0x03, 0xb8, 0xd0, 0x7f, 0xc7, 0x81, 0x14, 0x13, 0x65, 0x45, 0x9b, 0x69, 0xcf, 0x35, 0x56, - 0x24, 0x28, 0x89, 0x52, 0xf4, 0x3a, 0x9c, 0x31, 0xbf, 0xe0, 0x1d, 0x7a, 0x53, 0xb8, 0xea, 0x99, - 0x8f, 0x09, 0xf7, 0x23, 0xe1, 0x7e, 0xd5, 0x81, 0xe2, 0xb2, 0xd7, 0x6d, 0x90, 0x81, 0x8c, 0x61, - 0x94, 0x8f, 0x45, 0xc4, 0x6b, 0x25, 0x52, 0x75, 0x10, 0x7c, 0x0c, 0x0b, 0x18, 0x56, 0xa5, 0x68, - 0x0e, 0x4a, 0x61, 0x87, 0x18, 0x1e, 0xc0, 0x47, 0xe4, 0xec, 0xad, 0xc9, 0x02, 0x7a, 0xec, 0x30, - 0xea, 0x0a, 0x82, 0xd3, 0x56, 0xee, 0xf7, 0x8b, 0x50, 0xd6, 0x6e, 0xbd, 0x50, 0x59, 0x20, 0x22, - 0x9d, 0x30, 0x2b, 0x2f, 0xd3, 0x05, 0x83, 0x59, 0x09, 0xdd, 0x83, 0x11, 0xd9, 0xf1, 0x63, 0xce, - 0xb6, 0x8c, 0x3d, 0x88, 0x05, 0x1c, 0xab, 0x1a, 0x68, 0x06, 0x8a, 0x75, 0xd2, 0x49, 0x9a, 0xac, - 0x7b, 0xc3, 0x3c, 0xf4, 0x6f, 0x91, 0x02, 0x30, 0x87, 0xd3, 0x0a, 0x5b, 0x24, 0xa9, 0x35, 0x99, - 0xdd, 0x57, 0xc4, 0x06, 0x2e, 0x51, 0x00, 0xe6, 0xf0, 0x1c, 0x1f, 0x65, 0xf1, 0xf0, 0x7d, 0x94, - 0x23, 0x96, 0x7d, 0x94, 0xa8, 0x03, 0x27, 0xe2, 0xb8, 0xb9, 0x1e, 0xf9, 0x3b, 0x5e, 0x42, 0xd2, - 0xd5, 0x37, 0x7a, 0x10, 0x3a, 0x67, 0xd8, 0x3d, 0xf4, 0xea, 0xc5, 0x2c, 0x16, 0x9c, 0x87, 0x1a, - 0x55, 0xe1, 0x94, 0x1f, 0xc4, 0xa4, 0xd6, 0x8d, 0xc8, 0xa5, 0x46, 0x10, 0x46, 0xe4, 0x62, 0x18, - 0x53, 0x74, 0xe2, 0x16, 0xad, 0x8a, 0x96, 0xbd, 0x94, 0x57, 0x09, 0xe7, 0xb7, 0x45, 0xcb, 0x70, - 0xbc, 0xee, 0xc7, 0xde, 0x66, 0x8b, 0x54, 0xbb, 0x9b, 0xed, 0x90, 0x2b, 0xde, 0x25, 0x86, 0xf0, - 0x7e, 0x69, 0x25, 0x5a, 0xcc, 0x56, 0xc0, 0xbd, 0x6d, 0xd0, 0x33, 0x30, 0x1e, 0xfb, 0x41, 0xa3, - 0x45, 0xe6, 0x23, 0x2f, 0xa8, 0x35, 0xc5, 0xf5, 0x5b, 0x65, 0x4d, 0xaf, 0x6a, 0x65, 0xd8, 0xa8, - 0xc9, 0xf6, 0x3c, 0x6f, 0x93, 0x91, 0x06, 0x45, 0x6d, 0x51, 0xea, 0xfe, 0xc0, 0x81, 0x71, 0x3d, - 0x52, 0x9d, 0x4a, 0xda, 0xd0, 0x5c, 0x5c, 0xaa, 0xf2, 0xb3, 0xc0, 0xde, 0x89, 0x7f, 0x51, 0xe1, - 0x4c, 0x95, 0xe5, 0x14, 0x86, 0x35, 0x9a, 0x03, 0xdc, 0x3b, 0x7f, 0x04, 0x8a, 0x5b, 0x21, 0x15, - 0x48, 0x86, 0x4c, 0x33, 0xfc, 0x12, 0x05, 0x62, 0x5e, 0xe6, 0xfe, 0x4f, 0x07, 0x4e, 0xe7, 0x07, - 0xe1, 0xff, 0x34, 0x0c, 0xf2, 0x3c, 0x00, 0x1d, 0x8a, 0xc1, 0xd4, 0xb5, 0xcc, 0x13, 0xb2, 0x04, - 0x6b, 0xb5, 0x06, 0x1b, 0xf6, 0x9f, 0x51, 0xa1, 0x38, 0xa5, 0xf3, 0x39, 0x07, 0x26, 0x28, 0xd9, - 0x95, 0x68, 0xd3, 0x18, 0xed, 0x9a, 0x9d, 0xd1, 0x2a, 0xb4, 0xa9, 0xb7, 0xc1, 0x00, 0x63, 0x93, - 0x38, 0xfa, 0x39, 0x28, 0x79, 0xf5, 0x7a, 0x44, 0xe2, 0x58, 0xf9, 0xed, 0x98, 0x2d, 0x6a, 0x4e, - 0x02, 0x71, 0x5a, 0x4e, 0x99, 0x68, 0xb3, 0xbe, 0x15, 0x53, 0xbe, 0x24, 0x18, 0xb7, 0x62, 0xa2, - 0x94, 0x08, 0x85, 0x63, 0x55, 0xc3, 0xfd, 0x95, 0x61, 0x30, 0x69, 0xa3, 0x3a, 0x1c, 0xdb, 0x8e, - 0x36, 0x17, 0x58, 0xd8, 0xc3, 0x9d, 0x84, 0x1f, 0xb0, 0xb0, 0x80, 0x15, 0x13, 0x03, 0xce, 0xa2, - 0x14, 0x54, 0x56, 0xc8, 0x6e, 0xe2, 0x6d, 0xde, 0x71, 0xf0, 0xc1, 0x8a, 0x89, 0x01, 0x67, 0x51, - 0xa2, 0x77, 0x43, 0x79, 0x3b, 0xda, 0x94, 0x2c, 0x3a, 0x1b, 0xc9, 0xb2, 0x92, 0x16, 0x61, 0xbd, - 0x1e, 0x9d, 0xc2, 0xed, 0x68, 0x93, 0x9e, 0x8a, 0x32, 0x0f, 0x83, 0x9a, 0xc2, 0x15, 0x01, 0xc7, - 0xaa, 0x06, 0xea, 0x00, 0xda, 0x96, 0xb3, 0xa7, 0x82, 0x3c, 0xc4, 0x49, 0x32, 0x78, 0x8c, 0x08, - 0x8b, 0xae, 0x5f, 0xe9, 0xc1, 0x83, 0x73, 0x70, 0xa3, 0x17, 0xe0, 0xcc, 0x76, 0xb4, 0x29, 0x84, - 0x85, 0xf5, 0xc8, 0x0f, 0x6a, 0x7e, 0xc7, 0xc8, 0xb9, 0x30, 0x23, 0xba, 0x7b, 0x66, 0x25, 0xbf, - 0x1a, 0xee, 0xd7, 0xde, 0xfd, 0xdd, 0x61, 0x60, 0xb7, 0x45, 0x29, 0x2f, 0x6c, 0x93, 0xa4, 0x19, - 0xd6, 0xb3, 0xf2, 0xcf, 0x2a, 0x83, 0x62, 0x51, 0x2a, 0x63, 0x48, 0x0b, 0x7d, 0x62, 0x48, 0xaf, - 0xc3, 0x68, 0x93, 0x78, 0x75, 0x12, 0x49, 0x0b, 0xe2, 0x65, 0x3b, 0xf7, 0x5b, 0x2f, 0x32, 0xa4, - 0xa9, 0x1a, 0xce, 0x7f, 0xc7, 0x58, 0x52, 0x43, 0xef, 0x81, 0x49, 0x2a, 0xc8, 0x84, 0xdd, 0x44, - 0x9a, 0xf8, 0xb9, 0x05, 0x91, 0x9d, 0xa8, 0x1b, 0x46, 0x09, 0xce, 0xd4, 0x44, 0x8b, 0x30, 0x25, - 0xcc, 0xf1, 0xca, 0x32, 0x29, 0x26, 0x56, 0x25, 0xc3, 0xa8, 0x66, 0xca, 0x71, 0x4f, 0x0b, 0x16, - 0x03, 0x18, 0xd6, 0xb9, 0x47, 0x56, 0x8f, 0x01, 0x0c, 0xeb, 0xbb, 0x98, 0x95, 0xa0, 0x57, 0x61, - 0x8c, 0xfe, 0x5d, 0x8a, 0xc2, 0xb6, 0xb0, 0xcd, 0xac, 0xdb, 0x99, 0x1d, 0x4a, 0x43, 0x68, 0x8a, - 0x4c, 0xc0, 0x9b, 0x17, 0x54, 0xb0, 0xa2, 0x47, 0xf5, 0x15, 0x79, 0x0e, 0x57, 0xb7, 0xfd, 0xce, - 0xf3, 0x24, 0xf2, 0xb7, 0x76, 0x99, 0xd0, 0x30, 0x96, 0xea, 0x2b, 0x97, 0x7a, 0x6a, 0xe0, 0x9c, - 0x56, 0xee, 0xe7, 0x0a, 0x30, 0xae, 0x5f, 0x3a, 0xbe, 0x5d, 0x60, 0x71, 0x9c, 0x2e, 0x0a, 0xae, - 0x9d, 0x5e, 0xb4, 0x30, 0xec, 0xdb, 0x2d, 0x88, 0x26, 0x0c, 0x7b, 0x5d, 0x21, 0x2d, 0x5a, 0x31, - 0x82, 0xb1, 0x11, 0x77, 0x93, 0x26, 0xbf, 0x9d, 0xc6, 0x42, 0x7e, 0x19, 0x05, 0xf7, 0x93, 0x43, - 0x30, 0x26, 0x0b, 0xd1, 0x27, 0x1c, 0x80, 0x34, 0xf4, 0x4a, 0xb0, 0xd2, 0x75, 0x1b, 0x71, 0x39, - 0x7a, 0xd4, 0x98, 0x66, 0x4b, 0x57, 0x70, 0xac, 0xd1, 0x45, 0x09, 0x8c, 0x84, 0xb4, 0x73, 0xe7, - 0xed, 0x5d, 0x9c, 0x5f, 0xa3, 0x84, 0xcf, 0x33, 0xea, 0xa9, 0xd9, 0x8c, 0xc1, 0xb0, 0xa0, 0x45, - 0x35, 0xc0, 0x4d, 0x19, 0x11, 0x68, 0xcf, 0xc4, 0xac, 0x82, 0x0c, 0x53, 0x85, 0x4e, 0x81, 0x70, - 0x4a, 0xd0, 0x7d, 0x0a, 0x26, 0xcd, 0xcd, 0x40, 0x35, 0x82, 0xcd, 0xdd, 0x84, 0x70, 0x7b, 0xc3, - 0x38, 0xd7, 0x08, 0xe6, 0x29, 0x00, 0x73, 0xb8, 0xfb, 0x3d, 0x2a, 0x07, 0x28, 0xf6, 0x32, 0x80, - 0x89, 0xff, 0x11, 0xdd, 0x58, 0xd6, 0x4f, 0xed, 0xfa, 0x18, 0x94, 0xd8, 0x3f, 0x6c, 0xa3, 0x0f, - 0xd9, 0xf2, 0xdf, 0xa7, 0xfd, 0x14, 0x5b, 0x9d, 0xc9, 0x04, 0xcf, 0x4b, 0x42, 0x38, 0xa5, 0xe9, - 0x86, 0x30, 0x95, 0xad, 0x8d, 0x3e, 0x08, 0xe3, 0xb1, 0x3c, 0x56, 0xd3, 0x2b, 0x74, 0x03, 0x1e, - 0xbf, 0xdc, 0x7b, 0xa6, 0x35, 0xc7, 0x06, 0x32, 0x77, 0x0d, 0x46, 0xac, 0x4e, 0xa1, 0xfb, 0x2d, - 0x07, 0x4a, 0xcc, 0x81, 0xd9, 0x88, 0xbc, 0x76, 0xda, 0x64, 0x68, 0x9f, 0x59, 0x8f, 0x61, 0x94, - 0xeb, 0xe8, 0x32, 0xf0, 0xc7, 0x02, 0x97, 0xe1, 0xf9, 0xee, 0x52, 0x2e, 0xc3, 0x8d, 0x01, 0x31, - 0x96, 0x94, 0xdc, 0x4f, 0x15, 0x60, 0xe4, 0x52, 0xd0, 0xe9, 0xfe, 0x95, 0xcf, 0xb9, 0xb6, 0x0a, - 0xc3, 0x97, 0x12, 0xd2, 0x36, 0x53, 0x03, 0x8e, 0xcf, 0x3f, 0xaa, 0xa7, 0x05, 0xac, 0x98, 0x69, - 0x01, 0xb1, 0x77, 0x5d, 0xc6, 0xc5, 0x09, 0x1b, 0x71, 0x7a, 0x8d, 0xf0, 0x49, 0x28, 0x5d, 0xf6, - 0x36, 0x49, 0x6b, 0x85, 0xec, 0xb2, 0x4b, 0x7f, 0x3c, 0x46, 0xc3, 0x49, 0x15, 0x7b, 0x23, 0x9e, - 0x62, 0x11, 0x26, 0x59, 0x6d, 0xb5, 0x19, 0xa8, 0xe6, 0x40, 0xd2, 0xbc, 0x4a, 0x8e, 0xa9, 0x39, - 0x68, 0x39, 0x95, 0xb4, 0x5a, 0xee, 0x2c, 0x94, 0x53, 0x2c, 0x03, 0x50, 0xfd, 0x49, 0x01, 0x26, - 0x0c, 0x53, 0xb7, 0xe1, 0x00, 0x74, 0x6e, 0xeb, 0x00, 0x34, 0x1c, 0x72, 0x85, 0x7b, 0xed, 0x90, - 0x1b, 0x3a, 0x7a, 0x87, 0x9c, 0xf9, 0x91, 0x86, 0x07, 0xfa, 0x48, 0x2d, 0x18, 0xbe, 0xec, 0x07, - 0xdb, 0x83, 0xf1, 0x99, 0xb8, 0x16, 0x76, 0x7a, 0xf8, 0x4c, 0x95, 0x02, 0x31, 0x2f, 0x93, 0x92, - 0xcb, 0x50, 0xbe, 0xe4, 0xe2, 0x7e, 0xc2, 0x81, 0xf1, 0x55, 0x2f, 0xf0, 0xb7, 0x48, 0x9c, 0xb0, - 0x75, 0x95, 0x1c, 0xea, 0xe5, 0xaf, 0xf1, 0x3e, 0x69, 0x0c, 0xde, 0x74, 0xe0, 0xf8, 0x2a, 0x69, - 0x87, 0xfe, 0xab, 0x5e, 0x1a, 0x76, 0x4a, 0xfb, 0xde, 0xf4, 0x13, 0x11, 0x65, 0xa7, 0xfa, 0x7e, - 0xd1, 0x4f, 0x30, 0x85, 0xdf, 0xc6, 0x8e, 0xcb, 0xae, 0x55, 0x50, 0x05, 0x4d, 0xbb, 0x90, 0x98, - 0x06, 0x94, 0xca, 0x02, 0x9c, 0xd6, 0x71, 0x7f, 0xcf, 0x81, 0x51, 0xde, 0x09, 0x15, 0xa9, 0xeb, - 0xf4, 0xc1, 0xdd, 0x84, 0x22, 0x6b, 0x27, 0x56, 0xf5, 0xb2, 0x05, 0xf1, 0x87, 0xa2, 0xe3, 0x7b, - 0x90, 0xfd, 0x8b, 0x39, 0x01, 0xa6, 0xb6, 0x78, 0x37, 0xe6, 0x54, 0xc4, 0x6d, 0xaa, 0xb6, 0x30, - 0x28, 0x16, 0xa5, 0xee, 0xd7, 0x86, 0x60, 0x4c, 0x65, 0xef, 0x62, 0xb9, 0x15, 0x82, 0x20, 0x4c, - 0x3c, 0x1e, 0xeb, 0xc0, 0x79, 0xf5, 0x07, 0xed, 0x65, 0x0f, 0x9b, 0x9d, 0x4b, 0xb1, 0x73, 0xff, - 0x9d, 0x52, 0x42, 0xb5, 0x12, 0xac, 0x77, 0x02, 0x7d, 0x14, 0x46, 0x5a, 0x94, 0xfb, 0x48, 0xd6, - 0xfd, 0xbc, 0xc5, 0xee, 0x30, 0xb6, 0x26, 0x7a, 0xa2, 0x66, 0x88, 0x03, 0xb1, 0xa0, 0x3a, 0xfd, - 0x3e, 0x98, 0xca, 0xf6, 0xfa, 0x76, 0xf7, 0x25, 0x4b, 0xfa, 0x6d, 0xcb, 0xbf, 0x29, 0xb8, 0xe7, - 0xc1, 0x9b, 0xba, 0xcf, 0x41, 0x79, 0x95, 0x24, 0x91, 0x5f, 0x63, 0x08, 0x6e, 0xb7, 0xb8, 0x06, - 0x92, 0x1f, 0x3e, 0xcd, 0x16, 0x2b, 0xc5, 0x19, 0xa3, 0xd7, 0x01, 0x3a, 0x51, 0x48, 0xf5, 0x57, - 0xd2, 0x95, 0x1f, 0xdb, 0x82, 0x3c, 0xbc, 0xae, 0x70, 0x72, 0x97, 0x73, 0xfa, 0x1b, 0x6b, 0xf4, - 0xdc, 0x17, 0xa1, 0xb8, 0xda, 0x4d, 0xc8, 0x8d, 0x01, 0x38, 0xd6, 0x41, 0x13, 0x08, 0xb8, 0x1f, - 0x84, 0x71, 0x86, 0xfb, 0x62, 0xd8, 0xa2, 0xc7, 0x2a, 0x9d, 0x9a, 0x36, 0xfd, 0x9d, 0x75, 0x0a, - 0xb0, 0x4a, 0x98, 0x97, 0xd1, 0x2d, 0xd3, 0x0c, 0x5b, 0x75, 0x75, 0x99, 0x4a, 0x2d, 0x88, 0x8b, - 0x0c, 0x8a, 0x45, 0xa9, 0xfb, 0x4b, 0x05, 0x28, 0xb3, 0x86, 0x82, 0xdd, 0xec, 0xc2, 0x68, 0x93, - 0xd3, 0x11, 0x73, 0x68, 0x21, 0x44, 0x4b, 0xef, 0xbd, 0xa6, 0xcb, 0x71, 0x00, 0x96, 0xf4, 0x28, - 0xe9, 0xeb, 0x9e, 0x9f, 0x50, 0xd2, 0x85, 0xc3, 0x25, 0x7d, 0x8d, 0x93, 0xc1, 0x92, 0x9e, 0xfb, - 0x8b, 0xc0, 0x2e, 0x29, 0x2f, 0xb5, 0xbc, 0x06, 0x9f, 0xb9, 0x70, 0x9b, 0xd4, 0x05, 0xcf, 0xd5, - 0x66, 0x8e, 0x42, 0xb1, 0x28, 0xe5, 0x17, 0x3f, 0x93, 0xc8, 0x57, 0xc1, 0xcd, 0xda, 0xc5, 0x4f, - 0x06, 0x96, 0xa1, 0xec, 0x75, 0xf7, 0x4b, 0x05, 0x00, 0x96, 0xeb, 0x8d, 0xdf, 0x2d, 0xfe, 0x79, - 0x19, 0xa9, 0x64, 0x3a, 0x12, 0x55, 0xa4, 0x12, 0xbb, 0x3d, 0xad, 0x47, 0x28, 0xe9, 0x77, 0x0e, - 0x0a, 0xfb, 0xdf, 0x39, 0x40, 0x1d, 0x18, 0x0d, 0xbb, 0x09, 0x95, 0x55, 0xc5, 0x61, 0x6f, 0xc1, - 0x8f, 0xbe, 0xc6, 0x11, 0xf2, 0x40, 0x7d, 0xf1, 0x03, 0x4b, 0x32, 0xe8, 0x19, 0x18, 0xeb, 0x44, - 0x61, 0x83, 0x9e, 0xdd, 0xe2, 0x78, 0x7f, 0x50, 0xca, 0x43, 0xeb, 0x02, 0x7e, 0x4b, 0xfb, 0x1f, - 0xab, 0xda, 0xee, 0x1f, 0x4f, 0xf1, 0x79, 0x11, 0x6b, 0x6f, 0x1a, 0x0a, 0xbe, 0xb4, 0x4c, 0x81, - 0x40, 0x51, 0xb8, 0xb4, 0x88, 0x0b, 0x7e, 0x5d, 0xed, 0xab, 0x42, 0xdf, 0x7d, 0xf5, 0x6e, 0x28, - 0xd7, 0xfd, 0xb8, 0xd3, 0xf2, 0x76, 0xaf, 0xe4, 0x98, 0x05, 0x17, 0xd3, 0x22, 0xac, 0xd7, 0x43, - 0x4f, 0x8a, 0x1b, 0x26, 0xc3, 0x86, 0x29, 0x48, 0xde, 0x30, 0x49, 0xef, 0xae, 0xf3, 0xcb, 0x25, - 0xd9, 0x3b, 0xfe, 0xc5, 0x81, 0xef, 0xf8, 0x67, 0x25, 0xb1, 0x91, 0xa3, 0x97, 0xc4, 0xde, 0x0b, - 0x13, 0xf2, 0x27, 0x13, 0x8f, 0x2a, 0x27, 0x59, 0xef, 0x95, 0xb9, 0x7a, 0x43, 0x2f, 0xc4, 0x66, - 0xdd, 0x74, 0xd1, 0x8e, 0x0e, 0xba, 0x68, 0xcf, 0x03, 0x6c, 0x86, 0xdd, 0xa0, 0xee, 0x45, 0xbb, - 0x97, 0x16, 0x45, 0x3c, 0xaa, 0x12, 0xfc, 0xe6, 0x55, 0x09, 0xd6, 0x6a, 0xe9, 0x0b, 0xbd, 0x74, - 0x9b, 0x85, 0xfe, 0x41, 0x28, 0xb1, 0xd8, 0x5d, 0x52, 0x9f, 0x4b, 0x44, 0x88, 0xd1, 0x41, 0x42, - 0x26, 0xd3, 0xa0, 0x43, 0x89, 0x04, 0xa7, 0xf8, 0xd0, 0x87, 0x00, 0xb6, 0xfc, 0xc0, 0x8f, 0x9b, - 0x0c, 0x7b, 0xf9, 0xc0, 0xd8, 0xd5, 0x38, 0x97, 0x14, 0x16, 0xac, 0x61, 0x44, 0x2f, 0xc1, 0x71, - 0x12, 0x27, 0x7e, 0xdb, 0x4b, 0x48, 0x5d, 0xdd, 0xc9, 0xac, 0x30, 0x5b, 0xa6, 0x8a, 0x9e, 0xbe, - 0x90, 0xad, 0x70, 0x2b, 0x0f, 0x88, 0x7b, 0x11, 0x19, 0x3b, 0x72, 0xfa, 0x20, 0x3b, 0x12, 0xfd, - 0xb9, 0x03, 0xc7, 0x23, 0xc2, 0xe3, 0x4e, 0x62, 0xd5, 0xb1, 0x53, 0x8c, 0x1d, 0xd7, 0x6c, 0xa4, - 0x51, 0x57, 0xf9, 0x52, 0x70, 0x96, 0x0a, 0x17, 0x5c, 0x88, 0x1c, 0x7d, 0x4f, 0xf9, 0xad, 0x3c, - 0xe0, 0x9b, 0x6f, 0xcf, 0xcc, 0xf4, 0xa6, 0xf3, 0x57, 0xc8, 0xe9, 0xce, 0xfb, 0xbb, 0x6f, 0xcf, - 0x4c, 0xc9, 0xdf, 0xe9, 0xa4, 0xf5, 0x0c, 0x92, 0x1e, 0xab, 0x9d, 0xb0, 0x7e, 0x69, 0x5d, 0xc4, - 0x82, 0xa9, 0x63, 0x75, 0x9d, 0x02, 0x31, 0x2f, 0x43, 0x8f, 0xc3, 0x58, 0xdd, 0x23, 0xed, 0x30, - 0x50, 0x09, 0x71, 0x99, 0x34, 0xbf, 0x28, 0x60, 0x58, 0x95, 0x52, 0x1d, 0x22, 0x10, 0x47, 0x4a, - 0xe5, 0x01, 0x5b, 0x3a, 0x84, 0x3c, 0xa4, 0x38, 0x55, 0xf9, 0x0b, 0x2b, 0x4a, 0xa8, 0x05, 0x23, - 0x3e, 0x33, 0x54, 0x88, 0x70, 0x53, 0x0b, 0xd6, 0x11, 0x6e, 0xf8, 0x90, 0xc1, 0xa6, 0x8c, 0xf5, - 0x0b, 0x1a, 0xfa, 0x59, 0x73, 0xec, 0x68, 0xce, 0x9a, 0xc7, 0x61, 0xac, 0xd6, 0xf4, 0x5b, 0xf5, - 0x88, 0x04, 0x95, 0x29, 0xa6, 0xb1, 0xb3, 0x99, 0x58, 0x10, 0x30, 0xac, 0x4a, 0xd1, 0xdf, 0x80, - 0x89, 0xb0, 0x9b, 0x30, 0xd6, 0x42, 0xe7, 0x29, 0xae, 0x1c, 0x67, 0xd5, 0x59, 0xf0, 0xd0, 0x9a, - 0x5e, 0x80, 0xcd, 0x7a, 0x94, 0xc5, 0x37, 0xc3, 0x98, 0xa5, 0xf6, 0x61, 0x2c, 0xfe, 0xb4, 0xc9, - 0xe2, 0x2f, 0x6a, 0x65, 0xd8, 0xa8, 0x89, 0xbe, 0xe2, 0xc0, 0xf1, 0x76, 0x56, 0x81, 0xab, 0x9c, - 0x61, 0x33, 0x53, 0xb5, 0x21, 0xe8, 0x67, 0x50, 0xf3, 0xb0, 0xef, 0x1e, 0x30, 0xee, 0xed, 0x04, - 0x4b, 0xb2, 0x15, 0xef, 0x06, 0xb5, 0x66, 0x14, 0x06, 0x66, 0xf7, 0xee, 0xb7, 0x75, 0xb5, 0x8c, - 0xed, 0xed, 0x3c, 0x12, 0xf3, 0xf7, 0xdf, 0xdc, 0x9b, 0x39, 0x95, 0x5b, 0x84, 0xf3, 0x3b, 0x35, - 0xbd, 0x08, 0xa7, 0xf3, 0xf9, 0xc3, 0xed, 0x34, 0x8e, 0x21, 0x5d, 0xe3, 0x58, 0x82, 0xfb, 0xfb, - 0x76, 0x8a, 0x9e, 0x34, 0x52, 0xda, 0x74, 0xcc, 0x93, 0xa6, 0x47, 0x3a, 0x9c, 0x84, 0x71, 0xfd, - 0xfd, 0x07, 0xf7, 0xff, 0x0e, 0x01, 0xa4, 0x76, 0x72, 0xe4, 0xc1, 0x24, 0xb7, 0xc9, 0x5f, 0x5a, - 0xbc, 0xe3, 0x4b, 0xf1, 0x0b, 0x06, 0x02, 0x9c, 0x41, 0x88, 0xda, 0x80, 0x38, 0x84, 0xff, 0xbe, - 0x13, 0xdf, 0x2a, 0x73, 0x45, 0x2e, 0xf4, 0x20, 0xc1, 0x39, 0x88, 0xe9, 0x88, 0x92, 0x70, 0x9b, - 0x04, 0x57, 0xf1, 0xe5, 0x3b, 0xc9, 0xac, 0xc0, 0xbd, 0x71, 0x06, 0x02, 0x9c, 0x41, 0x88, 0x5c, - 0x18, 0x61, 0xb6, 0x19, 0x19, 0xa0, 0xcd, 0xd8, 0x0b, 0x93, 0x34, 0x62, 0x2c, 0x4a, 0xd0, 0x97, - 0x1c, 0x98, 0x94, 0x09, 0x22, 0x98, 0x35, 0x54, 0x86, 0x66, 0x5f, 0xb5, 0xe5, 0xe7, 0xb8, 0xa0, - 0x63, 0x4f, 0x03, 0x1f, 0x0d, 0x70, 0x8c, 0x33, 0x9d, 0x70, 0x5f, 0x80, 0x13, 0x39, 0xcd, 0xad, - 0x68, 0xb4, 0xdf, 0x76, 0xa0, 0xac, 0xe5, 0x2d, 0x44, 0xaf, 0x43, 0x29, 0xac, 0x5a, 0x8f, 0xb6, - 0x5b, 0xab, 0xf6, 0x44, 0xdb, 0x29, 0x10, 0x4e, 0x09, 0x0e, 0x12, 0x24, 0x98, 0x9b, 0x64, 0xf1, - 0x1e, 0x77, 0xfb, 0xc0, 0x41, 0x82, 0xbf, 0x52, 0x84, 0x14, 0xd3, 0x01, 0x13, 0x97, 0xa4, 0x21, - 0x85, 0x85, 0x7d, 0x43, 0x0a, 0xeb, 0x70, 0xcc, 0x63, 0xbe, 0xe4, 0x3b, 0x4c, 0x57, 0xc2, 0xd3, - 0xd6, 0x9a, 0x18, 0x70, 0x16, 0x25, 0xa5, 0x12, 0xa7, 0x4d, 0x19, 0x95, 0xe1, 0x03, 0x53, 0xa9, - 0x9a, 0x18, 0x70, 0x16, 0x25, 0x7a, 0x09, 0x2a, 0x35, 0x76, 0xfd, 0x96, 0x8f, 0xf1, 0xd2, 0xd6, - 0x95, 0x30, 0x59, 0x8f, 0x48, 0x4c, 0x82, 0x44, 0x24, 0x26, 0x7b, 0x58, 0xcc, 0x42, 0x65, 0xa1, - 0x4f, 0x3d, 0xdc, 0x17, 0x03, 0x55, 0x53, 0x98, 0x33, 0xda, 0x4f, 0x76, 0x19, 0x13, 0x11, 0x5e, - 0x7a, 0xa5, 0xa6, 0x54, 0xf5, 0x42, 0x6c, 0xd6, 0x45, 0xbf, 0xec, 0xc0, 0x44, 0x4b, 0x9a, 0xeb, - 0x71, 0xb7, 0x25, 0xb3, 0x6c, 0x62, 0x2b, 0xcb, 0xef, 0xb2, 0x8e, 0x99, 0xcb, 0x12, 0x06, 0x08, - 0x9b, 0xb4, 0xb3, 0xb9, 0x63, 0xc6, 0x06, 0xcc, 0x1d, 0xf3, 0x3d, 0x07, 0xa6, 0xb2, 0xd4, 0xd0, - 0x36, 0x3c, 0xd4, 0xf6, 0xa2, 0xed, 0x4b, 0xc1, 0x56, 0xc4, 0x2e, 0x62, 0x24, 0x7c, 0x31, 0xcc, - 0x6d, 0x25, 0x24, 0x5a, 0xf4, 0x76, 0xb9, 0xfb, 0xb3, 0xa8, 0x9e, 0x69, 0x7a, 0x68, 0x75, 0xbf, - 0xca, 0x78, 0x7f, 0x5c, 0xa8, 0x0a, 0xa7, 0x68, 0x05, 0x96, 0x5a, 0xce, 0x0f, 0x83, 0x94, 0x48, - 0x81, 0x11, 0x51, 0xc1, 0x80, 0xab, 0x79, 0x95, 0x70, 0x7e, 0x5b, 0xf7, 0x02, 0x8c, 0xf0, 0x7b, - 0x71, 0x77, 0xe5, 0x3f, 0x72, 0xff, 0x7d, 0x01, 0xa4, 0x60, 0xf8, 0x57, 0xdb, 0x1d, 0x47, 0x0f, - 0xd1, 0x88, 0x99, 0x94, 0x84, 0xb5, 0x83, 0x1d, 0xa2, 0x22, 0x89, 0xa3, 0x28, 0xa1, 0x12, 0x33, - 0xb9, 0xe1, 0x27, 0x0b, 0x61, 0x5d, 0xda, 0x38, 0x98, 0xc4, 0x7c, 0x41, 0xc0, 0xb0, 0x2a, 0x75, - 0x3f, 0xe1, 0xc0, 0x04, 0x1d, 0x65, 0xab, 0x45, 0x5a, 0xd5, 0x84, 0x74, 0x62, 0x14, 0x43, 0x31, - 0xa6, 0xff, 0xd8, 0x33, 0x05, 0xa6, 0x77, 0x29, 0x49, 0x47, 0x73, 0xd6, 0x50, 0x22, 0x98, 0xd3, - 0x72, 0xdf, 0x1a, 0x82, 0x92, 0x9a, 0xec, 0x01, 0xec, 0xa9, 0xe7, 0xd3, 0xfc, 0xaa, 0x9c, 0x03, - 0x57, 0xb4, 0xdc, 0xaa, 0xb7, 0xe8, 0xd4, 0x05, 0xbb, 0x3c, 0xd1, 0x44, 0x9a, 0x68, 0xf5, 0x49, - 0xd3, 0xd5, 0x7c, 0x5a, 0x5f, 0x7f, 0x5a, 0x7d, 0xe1, 0x73, 0xbe, 0xa1, 0x7b, 0xfa, 0x87, 0x6d, - 0x9d, 0x66, 0xca, 0x8d, 0xd9, 0xdf, 0xc5, 0x9f, 0x79, 0x7a, 0xa7, 0x38, 0xd0, 0xd3, 0x3b, 0x4f, - 0xc0, 0x30, 0x09, 0xba, 0x6d, 0x26, 0x2a, 0x95, 0x98, 0x8a, 0x30, 0x7c, 0x21, 0xe8, 0xb6, 0xcd, - 0x91, 0xb1, 0x2a, 0xe8, 0x7d, 0x50, 0xae, 0x93, 0xb8, 0x16, 0xf9, 0x2c, 0x7b, 0x82, 0xb0, 0xec, - 0x3c, 0xc8, 0xcc, 0x65, 0x29, 0xd8, 0x6c, 0xa8, 0x37, 0x70, 0x5f, 0x85, 0x91, 0xf5, 0x56, 0xb7, - 0xe1, 0x07, 0xa8, 0x03, 0x23, 0x3c, 0x97, 0x82, 0x38, 0xed, 0x2d, 0xe8, 0x9d, 0x9c, 0x55, 0x68, - 0x51, 0x28, 0xfc, 0x4a, 0xad, 0xa0, 0xe3, 0xfe, 0x76, 0x01, 0xa8, 0x6a, 0xbe, 0xbc, 0x80, 0xfe, - 0x76, 0xcf, 0x4b, 0x33, 0x3f, 0x93, 0xf3, 0xd2, 0xcc, 0x04, 0xab, 0x9c, 0xf3, 0xc8, 0x4c, 0x0b, - 0x26, 0x98, 0x73, 0x44, 0x9e, 0x81, 0x42, 0xac, 0x7e, 0x7a, 0xc0, 0xf4, 0x03, 0x7a, 0x53, 0x71, - 0x22, 0xe8, 0x20, 0x6c, 0x22, 0x47, 0xbb, 0x70, 0x82, 0xa7, 0xe9, 0x5c, 0x24, 0x2d, 0x6f, 0xd7, - 0x48, 0xc7, 0x35, 0x70, 0xca, 0x03, 0xd9, 0x8a, 0x07, 0x78, 0x2f, 0xf6, 0xa2, 0xc3, 0x79, 0x34, - 0xdc, 0xdf, 0x1f, 0x06, 0xcd, 0x7d, 0x31, 0xc0, 0xce, 0x7a, 0x25, 0xe3, 0xac, 0x5a, 0xb5, 0xe2, - 0xac, 0x92, 0x1e, 0x20, 0xce, 0xad, 0x4c, 0xff, 0x14, 0xed, 0x54, 0x93, 0xb4, 0x3a, 0x62, 0x5f, - 0xaa, 0x4e, 0x5d, 0x24, 0xad, 0x0e, 0x66, 0x25, 0xea, 0xf2, 0xe1, 0x70, 0xdf, 0xcb, 0x87, 0x4d, - 0x28, 0x36, 0xbc, 0x6e, 0x83, 0x88, 0x68, 0x4d, 0x0b, 0x7e, 0x49, 0x76, 0x1d, 0x82, 0xfb, 0x25, - 0xd9, 0xbf, 0x98, 0x13, 0xa0, 0x8c, 0xa1, 0x29, 0xc3, 0x57, 0x84, 0x41, 0xd7, 0x02, 0x63, 0x50, - 0x11, 0x31, 0x9c, 0x31, 0xa8, 0x9f, 0x38, 0x25, 0x86, 0x3a, 0x30, 0x5a, 0xe3, 0x09, 0x53, 0x84, - 0x7c, 0x73, 0xc9, 0xc6, 0xed, 0x4a, 0x86, 0x90, 0x5b, 0x5e, 0xc4, 0x0f, 0x2c, 0xc9, 0xb8, 0xe7, - 0xa0, 0xac, 0x3d, 0x8e, 0x41, 0x3f, 0x83, 0xca, 0xd5, 0xa1, 0x7d, 0x86, 0x45, 0x2f, 0xf1, 0x30, - 0x2b, 0x71, 0xbf, 0x31, 0x0c, 0xca, 0xee, 0xa6, 0xdf, 0x05, 0xf4, 0x6a, 0x5a, 0x66, 0x21, 0xe3, - 0x5e, 0x7c, 0x18, 0x60, 0x51, 0x4a, 0x65, 0xc0, 0x36, 0x89, 0x1a, 0x4a, 0xe7, 0x16, 0xac, 0x5d, - 0xc9, 0x80, 0xab, 0x7a, 0x21, 0x36, 0xeb, 0x52, 0x01, 0xbe, 0x2d, 0xdc, 0xf9, 0xd9, 0x60, 0x69, - 0xe9, 0xe6, 0xc7, 0xaa, 0x06, 0x4b, 0x4d, 0xd0, 0xd6, 0xbc, 0xff, 0x22, 0x68, 0xd3, 0x86, 0xf3, - 0x49, 0xc3, 0xca, 0x83, 0xab, 0x74, 0x08, 0x36, 0xa8, 0xa2, 0x65, 0x38, 0x1e, 0x93, 0x64, 0xed, - 0x7a, 0x40, 0x22, 0x95, 0x36, 0x40, 0xe4, 0xbe, 0x50, 0x37, 0x25, 0xaa, 0xd9, 0x0a, 0xb8, 0xb7, - 0x4d, 0x6e, 0x9c, 0x6b, 0xf1, 0xc0, 0x71, 0xae, 0x8b, 0x30, 0xb5, 0xe5, 0xf9, 0xad, 0x6e, 0x44, - 0xfa, 0x46, 0xcb, 0x2e, 0x65, 0xca, 0x71, 0x4f, 0x0b, 0x76, 0x59, 0xa7, 0xe5, 0x35, 0xe2, 0xca, - 0xa8, 0x76, 0x59, 0x87, 0x02, 0x30, 0x87, 0xbb, 0xbf, 0xe9, 0x00, 0x4f, 0x3a, 0x34, 0xb7, 0xb5, - 0xe5, 0x07, 0x7e, 0xb2, 0x8b, 0xbe, 0xea, 0xc0, 0x54, 0x10, 0xd6, 0xc9, 0x5c, 0x90, 0xf8, 0x12, - 0x68, 0x2f, 0x13, 0x3c, 0xa3, 0x75, 0x25, 0x83, 0x9e, 0x67, 0xb0, 0xc8, 0x42, 0x71, 0x4f, 0x37, - 0xdc, 0x33, 0x70, 0x2a, 0x17, 0x81, 0xfb, 0xbd, 0x21, 0x30, 0x73, 0x27, 0xa1, 0xe7, 0xa0, 0xd8, - 0x62, 0xd9, 0x3c, 0x9c, 0x3b, 0x4c, 0x8a, 0xc5, 0xe6, 0x8a, 0xa7, 0xfb, 0xe0, 0x98, 0xd0, 0x22, - 0x94, 0x59, 0x42, 0x26, 0x91, 0x6b, 0xa5, 0x60, 0xa4, 0x39, 0x28, 0xe3, 0xb4, 0xe8, 0x96, 0xf9, - 0x13, 0xeb, 0xcd, 0xd0, 0x6b, 0x30, 0xba, 0xc9, 0xd3, 0x52, 0xda, 0xf3, 0x0f, 0x8a, 0x3c, 0x97, - 0x4c, 0x8e, 0x92, 0x49, 0x2f, 0x6f, 0xa5, 0xff, 0x62, 0x49, 0x11, 0xed, 0xc2, 0x98, 0x27, 0xbf, - 0xe9, 0xb0, 0xad, 0xcb, 0x17, 0xc6, 0xfa, 0x11, 0xd1, 0x35, 0xf2, 0x1b, 0x2a, 0x72, 0x99, 0x30, - 0xa4, 0xe2, 0x40, 0x61, 0x48, 0xdf, 0x72, 0x00, 0xd2, 0x37, 0x3c, 0xd0, 0x0d, 0x18, 0x8b, 0x9f, - 0x36, 0x8c, 0x1a, 0x36, 0x6e, 0xdd, 0x0b, 0x8c, 0xda, 0xcd, 0x54, 0x01, 0xc1, 0x8a, 0xda, 0xed, - 0x0c, 0x31, 0x3f, 0x71, 0xe0, 0x64, 0xde, 0x5b, 0x23, 0xf7, 0xb0, 0xc7, 0x07, 0xb5, 0xc1, 0x88, - 0x06, 0xeb, 0x11, 0xd9, 0xf2, 0x6f, 0xe4, 0x24, 0x47, 0xe6, 0x05, 0x38, 0xad, 0xe3, 0xbe, 0x39, - 0x0a, 0x8a, 0xf0, 0x21, 0xd9, 0x6c, 0x1e, 0xa3, 0xfa, 0x55, 0x23, 0xbd, 0x2c, 0xa9, 0xea, 0x61, - 0x06, 0xc5, 0xa2, 0x94, 0xea, 0x58, 0x32, 0x80, 0x5e, 0xb0, 0x6c, 0xb6, 0x0a, 0x65, 0xa0, 0x3d, - 0x56, 0xa5, 0x79, 0x56, 0xa0, 0xe2, 0x91, 0x58, 0x81, 0x46, 0xec, 0x5b, 0x81, 0x9e, 0x80, 0xd1, - 0x28, 0x6c, 0x91, 0x39, 0x7c, 0x45, 0x68, 0x0e, 0x69, 0x00, 0x04, 0x07, 0x63, 0x59, 0x7e, 0x87, - 0x76, 0x10, 0xf4, 0x3b, 0xce, 0x3e, 0x86, 0xa6, 0x92, 0xad, 0x33, 0x21, 0x37, 0x93, 0x1c, 0x53, - 0x83, 0xee, 0xc4, 0x7a, 0xf5, 0x35, 0x07, 0x8e, 0x93, 0xa0, 0x16, 0xed, 0x32, 0x3c, 0x02, 0x9b, - 0xf0, 0x4f, 0x5f, 0xb5, 0xb1, 0xf9, 0x2e, 0x64, 0x91, 0x73, 0x37, 0x50, 0x0f, 0x18, 0xf7, 0x76, - 0x03, 0xad, 0xc1, 0x58, 0xcd, 0x13, 0x2b, 0xa2, 0x7c, 0x90, 0x15, 0xc1, 0xbd, 0x6c, 0x73, 0x62, - 0x29, 0x28, 0x24, 0xee, 0x8f, 0x0a, 0x70, 0x22, 0xa7, 0x4b, 0xec, 0xb2, 0x55, 0x9b, 0xae, 0xc8, - 0x4b, 0xf5, 0xec, 0x7e, 0x5c, 0x11, 0x70, 0xac, 0x6a, 0xa0, 0x75, 0x38, 0xb9, 0xdd, 0x8e, 0x53, - 0x2c, 0x0b, 0x61, 0x90, 0x90, 0x1b, 0x72, 0x77, 0x4a, 0xdf, 0xf5, 0xc9, 0x95, 0x9c, 0x3a, 0x38, - 0xb7, 0x25, 0x15, 0x5f, 0x48, 0xe0, 0x6d, 0xb6, 0x48, 0x5a, 0x24, 0xae, 0x0a, 0x2a, 0xf1, 0xe5, - 0x42, 0xa6, 0x1c, 0xf7, 0xb4, 0x40, 0x9f, 0x71, 0xe0, 0x81, 0x98, 0x44, 0x3b, 0x24, 0xaa, 0xfa, - 0x75, 0xb2, 0xd0, 0x8d, 0x93, 0xb0, 0x4d, 0xa2, 0x3b, 0x34, 0xad, 0xce, 0xdc, 0xdc, 0x9b, 0x79, - 0xa0, 0xda, 0x1f, 0x1b, 0xde, 0x8f, 0x94, 0xfb, 0x19, 0x07, 0x26, 0xab, 0x4c, 0xf1, 0x56, 0xb2, - 0xb4, 0xed, 0x5c, 0xa2, 0x8f, 0xa9, 0xe4, 0x16, 0x19, 0xae, 0x68, 0xa6, 0xa3, 0x70, 0x5f, 0x86, - 0xa9, 0x2a, 0x69, 0x7b, 0x9d, 0x26, 0xbb, 0xe7, 0xcb, 0x63, 0xb7, 0xce, 0x41, 0x29, 0x96, 0xb0, - 0xec, 0xf3, 0x41, 0xaa, 0x32, 0x4e, 0xeb, 0xa0, 0x47, 0x79, 0x9c, 0x99, 0xbc, 0x2d, 0x54, 0xe2, - 0x5a, 0x07, 0x0f, 0x4e, 0x8b, 0xb1, 0x2c, 0x73, 0xdf, 0x72, 0x60, 0x3c, 0x6d, 0x4f, 0xb6, 0x50, - 0x03, 0x8e, 0xd5, 0xb4, 0x9b, 0x76, 0xe9, 0x1d, 0x87, 0xc1, 0x2f, 0xe5, 0xf1, 0x14, 0xc7, 0x26, - 0x12, 0x9c, 0xc5, 0x7a, 0xf0, 0x30, 0xbd, 0xcf, 0x17, 0xe0, 0x98, 0xea, 0xaa, 0x70, 0x32, 0xbe, - 0x91, 0x8d, 0xa6, 0xc3, 0x36, 0xd2, 0xf4, 0x98, 0x73, 0xbf, 0x4f, 0x44, 0xdd, 0x1b, 0xd9, 0x88, - 0xba, 0x43, 0x25, 0xdf, 0xe3, 0x37, 0xfd, 0x56, 0x01, 0xc6, 0x54, 0xd2, 0xa0, 0xe7, 0xa0, 0xc8, - 0x54, 0xc9, 0xbb, 0x13, 0x88, 0x99, 0x5a, 0x8a, 0x39, 0x26, 0x8a, 0x92, 0x45, 0xec, 0xdc, 0x71, - 0xe2, 0xd9, 0x12, 0x37, 0x3e, 0x7a, 0x51, 0x82, 0x39, 0x26, 0xb4, 0x02, 0x43, 0x24, 0xa8, 0x0b, - 0xc9, 0xf8, 0xe0, 0x08, 0xd9, 0x43, 0x5f, 0x17, 0x82, 0x3a, 0xa6, 0x58, 0x58, 0xe6, 0x32, 0x2e, - 0x00, 0x65, 0x9e, 0x75, 0x11, 0xd2, 0x8f, 0x28, 0x75, 0xdf, 0x0f, 0x46, 0xce, 0x3a, 0x91, 0x0b, - 0x5f, 0x28, 0x5d, 0xbd, 0x6f, 0x71, 0x09, 0x6d, 0x2b, 0xad, 0xe3, 0xfe, 0xf2, 0x10, 0x8c, 0x54, - 0xbb, 0x9b, 0x54, 0x49, 0xf8, 0xa6, 0x03, 0x27, 0xae, 0x67, 0xd2, 0x3a, 0xa7, 0x9b, 0xe4, 0xaa, - 0x3d, 0x0b, 0xae, 0x1e, 0x76, 0xf6, 0x80, 0x7c, 0xf4, 0x3e, 0xa7, 0x10, 0xe7, 0x75, 0xc7, 0xc8, - 0xac, 0x3a, 0x74, 0x28, 0x99, 0x55, 0x6f, 0x1c, 0xf2, 0xbd, 0x8b, 0x89, 0x7e, 0x77, 0x2e, 0xdc, - 0xdf, 0x2f, 0x02, 0xf0, 0xaf, 0xb1, 0xd6, 0x49, 0x06, 0xb1, 0xb3, 0x3d, 0x03, 0xe3, 0x0d, 0x12, - 0x90, 0x48, 0x06, 0x15, 0x66, 0x9e, 0x1c, 0x5a, 0xd6, 0xca, 0xb0, 0x51, 0x93, 0x29, 0x35, 0x41, - 0x12, 0xed, 0x72, 0xc1, 0x37, 0x7b, 0xb7, 0x42, 0x95, 0x60, 0xad, 0x16, 0x9a, 0x35, 0x5c, 0x26, - 0xdc, 0xfb, 0x3e, 0xb9, 0x8f, 0x87, 0xe3, 0x7d, 0x30, 0x69, 0x26, 0x2a, 0x11, 0xd2, 0x9e, 0xf2, - 0x96, 0x9b, 0xf9, 0x4d, 0x70, 0xa6, 0x36, 0xdd, 0x05, 0xf5, 0x68, 0x17, 0x77, 0x03, 0x21, 0xf6, - 0xa9, 0x5d, 0xb0, 0xc8, 0xa0, 0x58, 0x94, 0xb2, 0x0c, 0x0f, 0xec, 0x00, 0xe4, 0x70, 0x91, 0x25, - 0x22, 0xcd, 0xf0, 0xa0, 0x95, 0x61, 0xa3, 0x26, 0xa5, 0x20, 0xec, 0x94, 0x60, 0xee, 0xb3, 0x8c, - 0x71, 0xb1, 0x03, 0x93, 0xa1, 0x69, 0x5f, 0xe1, 0x32, 0xd0, 0xbb, 0x06, 0x5c, 0x7a, 0x46, 0x5b, - 0x1e, 0xe5, 0x90, 0x31, 0xc7, 0x64, 0xf0, 0x53, 0xb9, 0x57, 0xbf, 0x82, 0x30, 0x6e, 0xc6, 0xa4, - 0xf6, 0xbd, 0x25, 0xb0, 0x0e, 0x27, 0x3b, 0x61, 0x7d, 0x3d, 0xf2, 0xc3, 0xc8, 0x4f, 0x76, 0x17, - 0x5a, 0x5e, 0x1c, 0xb3, 0x85, 0x31, 0x61, 0xca, 0x43, 0xeb, 0x39, 0x75, 0x70, 0x6e, 0x4b, 0xaa, - 0xa1, 0x74, 0x04, 0x90, 0x45, 0x86, 0x15, 0xb9, 0x44, 0x27, 0x2b, 0x62, 0x55, 0xea, 0x9e, 0x80, - 0xe3, 0xd5, 0x6e, 0xa7, 0xd3, 0xf2, 0x49, 0x5d, 0xb9, 0x24, 0xdc, 0xf7, 0xc3, 0x31, 0x91, 0x77, - 0x55, 0x49, 0x1f, 0x07, 0xca, 0x12, 0xee, 0xfe, 0xb9, 0x03, 0xc7, 0x32, 0x71, 0x38, 0xe8, 0xb5, - 0xac, 0xcc, 0x60, 0x27, 0x1f, 0xa8, 0x26, 0x2d, 0x88, 0xe4, 0x9e, 0x79, 0xf2, 0x47, 0x53, 0x06, - 0xd1, 0x5b, 0xbb, 0xbc, 0xc2, 0x42, 0xcd, 0xf9, 0x91, 0xa2, 0x47, 0xe2, 0xbb, 0x9f, 0x2e, 0x40, - 0x7e, 0xf0, 0x13, 0xfa, 0x68, 0xef, 0x04, 0x3c, 0x67, 0x71, 0x02, 0x44, 0xf4, 0x55, 0xff, 0x39, - 0x08, 0xcc, 0x39, 0x58, 0xb5, 0x34, 0x07, 0x82, 0x6e, 0xef, 0x4c, 0xfc, 0x2f, 0x07, 0xca, 0x1b, - 0x1b, 0x97, 0xd5, 0x39, 0x87, 0xe1, 0x74, 0xcc, 0x2f, 0xe7, 0x33, 0x1f, 0xf1, 0x42, 0xd8, 0xee, - 0x70, 0x97, 0xb1, 0x70, 0x65, 0xb3, 0x14, 0xb8, 0xd5, 0xdc, 0x1a, 0xb8, 0x4f, 0x4b, 0x74, 0x09, - 0x4e, 0xe8, 0x25, 0x55, 0xed, 0xc5, 0xc1, 0xa2, 0x48, 0x88, 0xd3, 0x5b, 0x8c, 0xf3, 0xda, 0x64, - 0x51, 0x09, 0x73, 0x27, 0x3b, 0xae, 0x72, 0x50, 0x89, 0x62, 0x9c, 0xd7, 0xc6, 0x5d, 0x83, 0xf2, - 0x86, 0x17, 0xa9, 0x81, 0x7f, 0x00, 0xa6, 0x6a, 0x61, 0x5b, 0x9a, 0x99, 0x2e, 0x93, 0x1d, 0xd2, - 0x12, 0x43, 0xe6, 0xcf, 0x7c, 0x64, 0xca, 0x70, 0x4f, 0x6d, 0xf7, 0xbf, 0x9f, 0x05, 0x75, 0xd9, - 0x70, 0x80, 0x13, 0xa6, 0xa3, 0xc2, 0x42, 0x8b, 0x96, 0xc3, 0x42, 0x15, 0xaf, 0xcd, 0x84, 0x86, - 0x26, 0x69, 0x68, 0xe8, 0x88, 0xed, 0xd0, 0x50, 0x25, 0x71, 0xf6, 0x84, 0x87, 0x7e, 0xd9, 0x81, - 0xf1, 0x20, 0xac, 0x13, 0xe5, 0xcb, 0x1b, 0x65, 0x62, 0xef, 0x4b, 0xf6, 0xa2, 0xec, 0x79, 0x98, - 0xa3, 0x40, 0xcf, 0x43, 0x96, 0xd5, 0x11, 0xa5, 0x17, 0x61, 0xa3, 0x1f, 0x68, 0x49, 0x33, 0x7c, - 0x72, 0xff, 0xc2, 0x83, 0x79, 0xfa, 0xca, 0x6d, 0xad, 0x98, 0x37, 0x34, 0xb9, 0xa9, 0x64, 0xcb, - 0xa0, 0x27, 0x6f, 0x90, 0x69, 0x6e, 0x12, 0x99, 0xc5, 0x39, 0x95, 0xa7, 0x5c, 0x18, 0xe1, 0xb1, - 0xcd, 0x22, 0xf5, 0x12, 0xf3, 0xde, 0xf1, 0xb8, 0x67, 0x2c, 0x4a, 0x50, 0x22, 0xe3, 0x05, 0xca, - 0xb6, 0xde, 0x64, 0x30, 0xe2, 0x11, 0xf2, 0x03, 0x06, 0xd0, 0xb3, 0xba, 0x1e, 0x3c, 0x3e, 0x88, - 0x1e, 0x3c, 0xd1, 0x57, 0x07, 0xfe, 0x9c, 0x03, 0xe3, 0x35, 0xed, 0x8d, 0x84, 0xca, 0xe3, 0xb6, - 0xde, 0x82, 0xce, 0x7b, 0xca, 0x82, 0x3b, 0x85, 0x8c, 0x37, 0x19, 0x0c, 0xea, 0x2c, 0xdf, 0x24, - 0x53, 0xfa, 0xd9, 0xd1, 0x6f, 0x25, 0xc5, 0x84, 0x69, 0x44, 0x90, 0x71, 0x97, 0x14, 0x86, 0x05, - 0x2d, 0xf4, 0x3a, 0x8c, 0xc9, 0xf0, 0x78, 0x11, 0x46, 0x8e, 0x6d, 0x58, 0xe9, 0x4d, 0x57, 0xa0, - 0x4c, 0x52, 0xc7, 0xa1, 0x58, 0x51, 0x44, 0x4d, 0x18, 0xaa, 0x7b, 0x0d, 0x11, 0x50, 0xbe, 0x6a, - 0x27, 0x09, 0xa8, 0xa4, 0xc9, 0xf4, 0xb3, 0xc5, 0xb9, 0x65, 0x4c, 0x49, 0xa0, 0x1b, 0x69, 0x92, - 0xf9, 0x29, 0x6b, 0xa7, 0xaf, 0x29, 0x26, 0x71, 0xb3, 0x46, 0x4f, 0xce, 0xfa, 0xba, 0xf0, 0x9e, - 0xfe, 0x35, 0x46, 0x76, 0xc9, 0x4e, 0x16, 0x51, 0x9e, 0xb2, 0x24, 0xf5, 0xc0, 0x52, 0x2a, 0xcd, - 0x24, 0xe9, 0x54, 0x7e, 0xd6, 0x16, 0x15, 0x96, 0x78, 0x83, 0x3f, 0xdb, 0xbd, 0xb1, 0xb1, 0x8e, - 0x19, 0x76, 0xd4, 0x82, 0x91, 0x0e, 0x0b, 0x02, 0xa9, 0xfc, 0x9c, 0xad, 0xb3, 0x85, 0x07, 0x95, - 0xf0, 0xb5, 0xc9, 0xff, 0xc7, 0x82, 0x06, 0xba, 0x00, 0xa3, 0xfc, 0xad, 0x14, 0x1e, 0xd0, 0x5f, - 0x3e, 0x3f, 0xdd, 0xff, 0xc5, 0x95, 0xf4, 0xa0, 0xe0, 0xbf, 0x63, 0x2c, 0xdb, 0xa2, 0xcf, 0x3b, - 0x30, 0x49, 0x39, 0x6a, 0xfa, 0xb8, 0x4b, 0x05, 0xd9, 0xe2, 0x59, 0x57, 0x63, 0x2a, 0x91, 0x48, - 0x5e, 0xa3, 0xd4, 0xa4, 0x4b, 0x06, 0x39, 0x9c, 0x21, 0x8f, 0xde, 0x80, 0xb1, 0xd8, 0xaf, 0x93, - 0x9a, 0x17, 0xc5, 0x95, 0x13, 0x87, 0xd3, 0x95, 0xd4, 0x5f, 0x23, 0x08, 0x61, 0x45, 0x12, 0xfd, - 0x1a, 0x7b, 0x5d, 0x53, 0xbc, 0x84, 0x5f, 0xe3, 0x62, 0xfd, 0x49, 0x5b, 0x7b, 0x5f, 0x7a, 0xa6, - 0x24, 0x66, 0xe1, 0xc6, 0x30, 0xc9, 0xe1, 0x2c, 0x7d, 0xf4, 0x77, 0x1c, 0x38, 0xc5, 0xf3, 0xe4, - 0x67, 0x1f, 0x76, 0x38, 0x75, 0x87, 0xf6, 0x19, 0x76, 0x13, 0x61, 0x2e, 0x0f, 0x25, 0xce, 0xa7, - 0xc4, 0xb2, 0xda, 0x9a, 0x6f, 0xf1, 0x9c, 0xb6, 0xea, 0xb7, 0x1c, 0xfc, 0xfd, 0x1d, 0xf4, 0x14, - 0x94, 0x3b, 0xe2, 0x38, 0xf4, 0xe3, 0x36, 0xbb, 0x57, 0x32, 0xc4, 0x6f, 0xfc, 0xad, 0xa7, 0x60, - 0xac, 0xd7, 0x31, 0x52, 0x1c, 0x3f, 0xb1, 0x5f, 0x8a, 0x63, 0x74, 0x15, 0xca, 0x49, 0xd8, 0x12, - 0x59, 0x3e, 0xe3, 0x4a, 0x85, 0xad, 0xc0, 0xb3, 0x79, 0x7b, 0x6b, 0x43, 0x55, 0x4b, 0x35, 0xd9, - 0x14, 0x16, 0x63, 0x1d, 0x0f, 0x8b, 0xe5, 0x15, 0xef, 0x0f, 0x44, 0x4c, 0x85, 0xbd, 0x3f, 0x13, - 0xcb, 0xab, 0x17, 0x62, 0xb3, 0x2e, 0x5a, 0x86, 0xe3, 0x9d, 0x1e, 0x1d, 0x98, 0xdf, 0x67, 0x53, - 0x21, 0x11, 0xbd, 0x0a, 0x70, 0x6f, 0x1b, 0x43, 0xfb, 0x7d, 0x60, 0x3f, 0xed, 0xb7, 0x4f, 0xc2, - 0xdf, 0x07, 0xef, 0x24, 0xe1, 0x2f, 0xaa, 0xc3, 0x83, 0x5e, 0x37, 0x09, 0x59, 0x72, 0x19, 0xb3, - 0x09, 0x0f, 0x6b, 0x7e, 0x98, 0x47, 0x4a, 0xdf, 0xdc, 0x9b, 0x79, 0x70, 0x6e, 0x9f, 0x7a, 0x78, - 0x5f, 0x2c, 0xe8, 0x55, 0x18, 0x23, 0x22, 0x69, 0x71, 0xe5, 0x67, 0x6c, 0x09, 0x09, 0x66, 0x1a, - 0x64, 0x19, 0x31, 0xca, 0x61, 0x58, 0xd1, 0x43, 0x1b, 0x50, 0x6e, 0x86, 0x71, 0x32, 0xd7, 0xf2, - 0xbd, 0x98, 0xc4, 0x95, 0x87, 0xd8, 0xa2, 0xc9, 0x95, 0xbd, 0x2e, 0xca, 0x6a, 0xe9, 0x9a, 0xb9, - 0x98, 0xb6, 0xc4, 0x3a, 0x1a, 0x44, 0x98, 0xf7, 0x92, 0xc5, 0x74, 0x4b, 0x47, 0xd0, 0x59, 0x36, - 0xb0, 0xc7, 0xf2, 0x30, 0xaf, 0x87, 0xf5, 0xaa, 0x59, 0x5b, 0xb9, 0x2f, 0x75, 0x20, 0xce, 0xe2, - 0x44, 0xcf, 0xc0, 0x78, 0x27, 0xac, 0x57, 0x3b, 0xa4, 0xb6, 0xee, 0x25, 0xb5, 0x66, 0x65, 0xc6, - 0xb4, 0xba, 0xad, 0x6b, 0x65, 0xd8, 0xa8, 0x89, 0x3a, 0x30, 0xda, 0xe6, 0x59, 0x07, 0x2a, 0x8f, - 0xd8, 0xd2, 0x6d, 0x44, 0x1a, 0x03, 0x2e, 0x2f, 0x88, 0x1f, 0x58, 0x92, 0x41, 0xff, 0xd8, 0x81, - 0x63, 0x99, 0x9b, 0x52, 0x95, 0x77, 0x58, 0x13, 0x59, 0x4c, 0xc4, 0xf3, 0x8f, 0xb1, 0xe9, 0x33, - 0x81, 0xb7, 0x7a, 0x41, 0x38, 0xdb, 0x23, 0x3e, 0x2f, 0x2c, 0x75, 0x48, 0xe5, 0x51, 0x7b, 0xf3, - 0xc2, 0x10, 0xca, 0x79, 0x61, 0x3f, 0xb0, 0x24, 0x83, 0x9e, 0x80, 0x51, 0x91, 0xe5, 0xaf, 0xf2, - 0x98, 0xe9, 0x82, 0x16, 0xc9, 0x00, 0xb1, 0x2c, 0x9f, 0x7e, 0x3f, 0x1c, 0xef, 0x51, 0xdd, 0x0e, - 0x94, 0xbf, 0xe2, 0x37, 0x1c, 0xd0, 0xaf, 0x56, 0x5b, 0x7f, 0x29, 0xe4, 0x19, 0x18, 0xaf, 0xf1, - 0x67, 0x19, 0xf9, 0xe5, 0xec, 0x61, 0xd3, 0xfe, 0xb9, 0xa0, 0x95, 0x61, 0xa3, 0xa6, 0x7b, 0x11, - 0x50, 0x6f, 0x1a, 0xf7, 0x3b, 0x4a, 0x8e, 0xf4, 0x4f, 0x1d, 0x98, 0x30, 0x64, 0x06, 0xeb, 0x4e, - 0xc6, 0x25, 0x40, 0x6d, 0x3f, 0x8a, 0xc2, 0x48, 0x7f, 0xff, 0x4e, 0x24, 0x50, 0x60, 0x57, 0xd4, - 0x56, 0x7b, 0x4a, 0x71, 0x4e, 0x0b, 0xf7, 0xb7, 0x87, 0x21, 0x0d, 0x99, 0x56, 0x79, 0x72, 0x9d, - 0xbe, 0x79, 0x72, 0x9f, 0x84, 0xb1, 0x97, 0xe3, 0x30, 0x58, 0x4f, 0xb3, 0xe9, 0xaa, 0x6f, 0xf1, - 0x6c, 0x75, 0xed, 0x0a, 0xab, 0xa9, 0x6a, 0xb0, 0xda, 0xaf, 0x2c, 0xf9, 0xad, 0xa4, 0x37, 0xdd, - 0xea, 0xb3, 0xcf, 0x71, 0x38, 0x56, 0x35, 0xd8, 0x53, 0x78, 0x3b, 0x44, 0x19, 0xc6, 0xd3, 0xa7, - 0xf0, 0xf8, 0x0b, 0x0d, 0xac, 0x0c, 0x9d, 0x83, 0x92, 0x32, 0xaa, 0x0b, 0x4b, 0xbd, 0x9a, 0x29, - 0x65, 0x79, 0xc7, 0x69, 0x1d, 0x26, 0x10, 0x0a, 0x43, 0xac, 0x30, 0xa1, 0x54, 0x6d, 0xa8, 0x27, - 0x19, 0xd3, 0x2e, 0xe7, 0xed, 0x12, 0x8c, 0x15, 0xc9, 0x3c, 0x47, 0x6b, 0xe9, 0x50, 0x1c, 0xad, - 0x5a, 0xfc, 0x7e, 0x71, 0xd0, 0xf8, 0x7d, 0x73, 0x6d, 0x8f, 0x0d, 0xb4, 0xb6, 0x3f, 0x39, 0x04, - 0xa3, 0xcf, 0x93, 0x88, 0x65, 0x19, 0x7f, 0x02, 0x46, 0x77, 0xf8, 0xbf, 0xd9, 0xcb, 0x9f, 0xa2, - 0x06, 0x96, 0xe5, 0xf4, 0xbb, 0x6d, 0x76, 0xfd, 0x56, 0x7d, 0x31, 0xdd, 0xc5, 0x69, 0x82, 0x42, - 0x59, 0x80, 0xd3, 0x3a, 0xb4, 0x41, 0x83, 0x4a, 0xf6, 0xed, 0xb6, 0xdf, 0xf3, 0xca, 0xfb, 0xb2, - 0x2c, 0xc0, 0x69, 0x1d, 0xf4, 0x18, 0x8c, 0x34, 0xfc, 0x64, 0xc3, 0x6b, 0x64, 0xdd, 0x84, 0xcb, - 0x0c, 0x8a, 0x45, 0x29, 0x73, 0x13, 0xf9, 0xc9, 0x46, 0x44, 0x98, 0x65, 0xb7, 0x27, 0xf7, 0xc4, - 0xb2, 0x56, 0x86, 0x8d, 0x9a, 0xac, 0x4b, 0xa1, 0x18, 0x99, 0x88, 0xe2, 0x4c, 0xbb, 0x24, 0x0b, - 0x70, 0x5a, 0x87, 0xae, 0xff, 0x5a, 0xd8, 0xee, 0xf8, 0x2d, 0x11, 0x5f, 0xac, 0xad, 0xff, 0x05, - 0x01, 0xc7, 0xaa, 0x06, 0xad, 0x4d, 0x59, 0x18, 0x65, 0x3f, 0xd9, 0x67, 0xc7, 0xd6, 0x05, 0x1c, - 0xab, 0x1a, 0xee, 0xf3, 0x30, 0xc1, 0x77, 0xf2, 0x42, 0xcb, 0xf3, 0xdb, 0xcb, 0x0b, 0xe8, 0x42, - 0x4f, 0xfc, 0xfe, 0x13, 0x39, 0xf1, 0xfb, 0xa7, 0x8c, 0x46, 0xbd, 0x71, 0xfc, 0xee, 0x0f, 0x0a, - 0x30, 0x76, 0x84, 0x2f, 0x37, 0x1e, 0xf9, 0x23, 0xc4, 0xe8, 0x46, 0xe6, 0xd5, 0xc6, 0x75, 0x9b, - 0xd7, 0x71, 0xf6, 0x7d, 0xb1, 0xf1, 0xbf, 0x14, 0xe0, 0xb4, 0xac, 0x2a, 0x75, 0xb9, 0xe5, 0x05, - 0xf6, 0x5e, 0xd6, 0xe1, 0x4f, 0x74, 0x64, 0x4c, 0xf4, 0xba, 0x3d, 0x6d, 0x74, 0x79, 0xa1, 0xef, - 0x54, 0xbf, 0x9a, 0x99, 0x6a, 0x6c, 0x95, 0xea, 0xfe, 0x93, 0xfd, 0x17, 0x0e, 0x4c, 0xe7, 0x4f, - 0xf6, 0x11, 0x3c, 0x94, 0xf9, 0x86, 0xf9, 0x50, 0xe6, 0x2f, 0xd8, 0x5b, 0x62, 0xe6, 0x50, 0xfa, - 0x3c, 0x99, 0xf9, 0x67, 0x0e, 0x9c, 0x94, 0x0d, 0xd8, 0xe9, 0x39, 0xef, 0x07, 0x2c, 0x92, 0xe5, - 0xf0, 0x97, 0xd9, 0xeb, 0xc6, 0x32, 0x7b, 0xd1, 0xde, 0xc0, 0xf5, 0x71, 0xf4, 0x7d, 0x60, 0xfc, - 0x4f, 0x1d, 0xa8, 0xe4, 0x35, 0x38, 0x82, 0x4f, 0xfe, 0x9a, 0xf9, 0xc9, 0x9f, 0x3f, 0x9c, 0x91, - 0xf7, 0xff, 0xe0, 0x95, 0x7e, 0x13, 0x85, 0x5a, 0x52, 0xae, 0x72, 0x6c, 0xf9, 0x68, 0x39, 0x89, - 0x7c, 0x01, 0xad, 0x05, 0x23, 0x31, 0x8b, 0xda, 0x10, 0x4b, 0xe0, 0xa2, 0x0d, 0x69, 0x8b, 0xe2, - 0x13, 0x36, 0x76, 0xf6, 0x3f, 0x16, 0x34, 0xdc, 0xdf, 0x2c, 0xc0, 0x19, 0xf5, 0x00, 0x2e, 0xd9, - 0x21, 0xad, 0x74, 0x7f, 0xb0, 0x37, 0x19, 0x3c, 0xf5, 0xd3, 0xde, 0x9b, 0x0c, 0x29, 0x89, 0x74, - 0x2f, 0xa4, 0x30, 0xac, 0xd1, 0x44, 0x55, 0x38, 0xc5, 0xde, 0x50, 0x58, 0xf2, 0x03, 0xaf, 0xe5, - 0xbf, 0x4a, 0x22, 0x4c, 0xda, 0xe1, 0x8e, 0xd7, 0x12, 0x92, 0xba, 0xba, 0xff, 0xbb, 0x94, 0x57, - 0x09, 0xe7, 0xb7, 0xed, 0xd1, 0xb8, 0x87, 0x06, 0xd5, 0xb8, 0xdd, 0x3f, 0x71, 0x60, 0xfc, 0x08, - 0x9f, 0x0b, 0x0e, 0xcd, 0x2d, 0xf1, 0xac, 0xbd, 0x2d, 0xd1, 0x67, 0x1b, 0xec, 0x15, 0xa1, 0xe7, - 0x05, 0x55, 0xf4, 0x29, 0x47, 0xc5, 0xb5, 0xf0, 0xe0, 0xc1, 0x0f, 0xd9, 0xeb, 0xc7, 0x41, 0x92, - 0x46, 0xa2, 0xaf, 0x65, 0x32, 0x69, 0x16, 0x6c, 0xa5, 0x83, 0xea, 0xe9, 0xcd, 0x1d, 0x64, 0xd4, - 0xfc, 0xb2, 0x03, 0xc0, 0xfb, 0x29, 0x12, 0x71, 0xd3, 0xbe, 0x6d, 0x1e, 0xda, 0x4c, 0x51, 0x22, - 0xbc, 0x6b, 0x6a, 0x0b, 0xa5, 0x05, 0x58, 0xeb, 0xc9, 0x5d, 0xa4, 0xca, 0xbc, 0xeb, 0x2c, 0x9d, - 0x9f, 0x77, 0xe0, 0x58, 0xa6, 0xbb, 0x39, 0xed, 0xb7, 0xcc, 0x27, 0x01, 0x2d, 0x48, 0x56, 0x66, - 0x7a, 0x66, 0xdd, 0x78, 0xf2, 0xdf, 0x5c, 0x30, 0x9e, 0x9e, 0x46, 0xaf, 0x41, 0x49, 0x5a, 0x3e, - 0xe4, 0xf2, 0xb6, 0xf9, 0x34, 0xaa, 0x52, 0x6f, 0x24, 0x24, 0xc6, 0x29, 0xbd, 0x4c, 0xd8, 0x5c, - 0x61, 0xa0, 0xb0, 0xb9, 0x7b, 0xfb, 0xb0, 0x6a, 0xbe, 0x5d, 0x7a, 0xf8, 0x50, 0xec, 0xd2, 0x0f, - 0x5a, 0xb7, 0x4b, 0x3f, 0x74, 0xc4, 0x76, 0x69, 0xcd, 0x49, 0x58, 0xbc, 0x0b, 0x27, 0xe1, 0x6b, - 0x70, 0x72, 0x27, 0x55, 0x3a, 0xd5, 0x4a, 0x12, 0x49, 0x88, 0x9e, 0xc8, 0xb5, 0x46, 0x53, 0x05, - 0x3a, 0x4e, 0x48, 0x90, 0x68, 0xea, 0x6a, 0x1a, 0xb1, 0xf7, 0x7c, 0x0e, 0x3a, 0x9c, 0x4b, 0x24, - 0xeb, 0xed, 0x19, 0x1d, 0xc0, 0xdb, 0xf3, 0x96, 0x03, 0xa7, 0xbc, 0x9e, 0x4b, 0x60, 0x98, 0x6c, - 0x89, 0x90, 0x93, 0x6b, 0xf6, 0x44, 0x08, 0x03, 0xbd, 0x70, 0xab, 0xe5, 0x15, 0xe1, 0xfc, 0x0e, - 0xa1, 0x47, 0x53, 0xd7, 0x3b, 0x8f, 0xf3, 0xcc, 0xf7, 0x93, 0x7f, 0x2d, 0x1b, 0xcf, 0x03, 0x6c, - 0xea, 0x3f, 0x62, 0x57, 0xdb, 0xb6, 0x10, 0xd3, 0x53, 0xbe, 0x8b, 0x98, 0x9e, 0x8c, 0xeb, 0x6d, - 0xdc, 0x92, 0xeb, 0x2d, 0x80, 0x29, 0xbf, 0xed, 0x35, 0xc8, 0x7a, 0xb7, 0xd5, 0xe2, 0x97, 0x48, - 0xe4, 0xe3, 0xb5, 0xb9, 0x16, 0xbc, 0xcb, 0x61, 0xcd, 0x6b, 0x65, 0x9f, 0x2d, 0x57, 0x97, 0x65, - 0x2e, 0x65, 0x30, 0xe1, 0x1e, 0xdc, 0x74, 0xc1, 0xb2, 0x6c, 0x78, 0x24, 0xa1, 0xb3, 0xcd, 0x02, - 0x47, 0xc6, 0xf8, 0x82, 0xbd, 0x98, 0x82, 0xb1, 0x5e, 0x07, 0xad, 0x40, 0xa9, 0x1e, 0xc4, 0xe2, - 0x3e, 0xeb, 0x31, 0xc6, 0xcc, 0xde, 0x49, 0x59, 0xe0, 0xe2, 0x95, 0xaa, 0xba, 0xc9, 0xfa, 0x60, - 0x4e, 0x7a, 0x47, 0x55, 0x8e, 0xd3, 0xf6, 0x68, 0x95, 0x21, 0x13, 0x2f, 0x7b, 0xf1, 0x78, 0x8e, - 0x87, 0xfb, 0x38, 0x8c, 0x16, 0xaf, 0xc8, 0xb7, 0xc9, 0x26, 0x04, 0x39, 0xf1, 0x44, 0x57, 0x8a, - 0x41, 0x7b, 0x44, 0xf8, 0xf8, 0xbe, 0x8f, 0x08, 0xb3, 0xbc, 0xae, 0x49, 0x4b, 0xb9, 0x87, 0xcf, - 0x5a, 0xcb, 0xeb, 0x9a, 0x46, 0x4a, 0x8a, 0xbc, 0xae, 0x29, 0x00, 0xeb, 0x24, 0xd1, 0x5a, 0x3f, - 0x37, 0xf9, 0x09, 0xc6, 0x34, 0x0e, 0xee, 0xf4, 0xd6, 0xfd, 0xa5, 0x27, 0xf7, 0xf5, 0x97, 0xf6, - 0xf8, 0x77, 0x4f, 0x1d, 0xc0, 0xbf, 0xdb, 0x64, 0x19, 0x37, 0x97, 0x17, 0x84, 0x4b, 0xdd, 0x82, - 0x7e, 0xc7, 0x72, 0x7c, 0xf0, 0xc8, 0x53, 0xf6, 0x2f, 0xe6, 0x04, 0xfa, 0x06, 0x54, 0x9f, 0xb9, - 0xe3, 0x80, 0x6a, 0xca, 0x9e, 0x53, 0x38, 0x4b, 0xdd, 0x5a, 0x14, 0xec, 0x39, 0x05, 0x63, 0xbd, - 0x4e, 0xd6, 0x5b, 0x7a, 0xff, 0xa1, 0x79, 0x4b, 0xa7, 0x8f, 0xc0, 0x5b, 0xfa, 0xc0, 0xc0, 0xde, - 0xd2, 0x1b, 0x70, 0xa2, 0x13, 0xd6, 0x17, 0xfd, 0x38, 0xea, 0xb2, 0x5b, 0x75, 0xf3, 0xdd, 0x7a, - 0x83, 0x24, 0xcc, 0xdd, 0x5a, 0x3e, 0xff, 0x4e, 0xbd, 0x93, 0x1d, 0xb6, 0x91, 0xe5, 0x1e, 0xcd, - 0x34, 0x60, 0xa6, 0x13, 0x16, 0x75, 0x9b, 0x53, 0x88, 0xf3, 0x48, 0xe8, 0x7e, 0xda, 0x87, 0x8f, - 0xc6, 0x4f, 0xfb, 0x01, 0x18, 0x8b, 0x9b, 0xdd, 0xa4, 0x1e, 0x5e, 0x0f, 0x98, 0x33, 0xbe, 0x34, - 0xff, 0x0e, 0x65, 0xca, 0x16, 0xf0, 0x5b, 0x7b, 0x33, 0x53, 0xf2, 0x7f, 0xcd, 0x8a, 0x2d, 0x20, - 0xe8, 0xeb, 0x7d, 0xee, 0xef, 0xb8, 0x87, 0x79, 0x7f, 0xe7, 0xcc, 0x81, 0xee, 0xee, 0xe4, 0x39, - 0xa3, 0x1f, 0xf9, 0xa9, 0x73, 0x46, 0x7f, 0xd5, 0x81, 0x89, 0x1d, 0xdd, 0x65, 0x20, 0x1c, 0xe6, - 0x16, 0x02, 0x77, 0x0c, 0x4f, 0xc4, 0xbc, 0x4b, 0xf9, 0x9c, 0x01, 0xba, 0x95, 0x05, 0x60, 0xb3, - 0x27, 0x39, 0x41, 0x45, 0x8f, 0xde, 0xab, 0xa0, 0xa2, 0x37, 0x18, 0x1f, 0x93, 0x4a, 0x2e, 0xf3, - 0xa2, 0xdb, 0x8d, 0x29, 0x96, 0x3c, 0x51, 0x85, 0x14, 0xeb, 0xf4, 0xd0, 0xe7, 0x1c, 0x98, 0x92, - 0x7a, 0x99, 0x70, 0xf9, 0xc5, 0x22, 0x2a, 0xd2, 0xa6, 0x3a, 0xc8, 0xc2, 0xea, 0x37, 0x32, 0x74, - 0x70, 0x0f, 0x65, 0xca, 0xd5, 0x55, 0x10, 0x5a, 0x23, 0x66, 0xc1, 0xbf, 0x42, 0x86, 0x99, 0x4b, - 0xc1, 0x58, 0xaf, 0x83, 0xbe, 0xe1, 0x00, 0x7f, 0x83, 0xbf, 0xf2, 0x04, 0x63, 0xe8, 0x2f, 0x58, - 0x96, 0x4d, 0xd3, 0x57, 0xfd, 0xe7, 0x9f, 0x92, 0xb6, 0x23, 0x06, 0xbb, 0xb5, 0x37, 0x33, 0x69, - 0x3c, 0x4c, 0x14, 0xbf, 0xf9, 0xb6, 0x06, 0x11, 0xb6, 0x4d, 0xd6, 0x35, 0xf4, 0x45, 0x07, 0xa6, - 0xae, 0x67, 0x0c, 0x1a, 0x22, 0x2c, 0x14, 0xdb, 0x37, 0x95, 0xf0, 0xe9, 0xce, 0x42, 0x71, 0x4f, - 0x0f, 0xd0, 0x67, 0x4d, 0x43, 0x27, 0x8f, 0x1f, 0xb5, 0x38, 0x81, 0x19, 0xc3, 0x2a, 0xbf, 0xe6, - 0x96, 0x6f, 0xf1, 0xbc, 0xeb, 0xf8, 0x90, 0x69, 0x3a, 0x98, 0xf4, 0x63, 0xe5, 0x34, 0x25, 0xa6, - 0xbd, 0xc5, 0xc2, 0x66, 0x37, 0x3e, 0xbf, 0x6e, 0x6e, 0xf9, 0xe2, 0x69, 0x98, 0x34, 0x7d, 0x7b, - 0xe8, 0x5d, 0xe6, 0xa3, 0x13, 0x67, 0xb3, 0xf9, 0xfb, 0x27, 0x64, 0x7d, 0x23, 0x87, 0xbf, 0x91, - 0x64, 0xbf, 0x70, 0xa8, 0x49, 0xf6, 0x87, 0x8e, 0x26, 0xc9, 0xfe, 0xd4, 0x61, 0x24, 0xd9, 0x3f, - 0x7e, 0xa0, 0x24, 0xfb, 0xda, 0x23, 0x07, 0xc3, 0xb7, 0x79, 0xe4, 0x60, 0x0e, 0x8e, 0xc9, 0xbb, - 0x3f, 0x44, 0xe4, 0x31, 0xe7, 0x6e, 0xff, 0x33, 0xa2, 0xc9, 0xb1, 0x05, 0xb3, 0x18, 0x67, 0xeb, - 0xd3, 0x4d, 0x56, 0x0c, 0x58, 0xcb, 0x11, 0x5b, 0x2f, 0x20, 0x99, 0x4b, 0x8b, 0xa9, 0xcf, 0x82, - 0x45, 0xc9, 0x68, 0xe7, 0x22, 0x83, 0xdd, 0x92, 0xff, 0x60, 0xde, 0x03, 0xf4, 0x12, 0x54, 0xc2, - 0xad, 0xad, 0x56, 0xe8, 0xd5, 0xd3, 0x97, 0x00, 0x64, 0x5c, 0x02, 0xbf, 0xbb, 0xa9, 0x12, 0xc7, - 0xae, 0xf5, 0xa9, 0x87, 0xfb, 0x62, 0x40, 0x6f, 0x51, 0xc1, 0x24, 0x09, 0x23, 0x52, 0x4f, 0x6d, - 0x35, 0x25, 0x36, 0x66, 0x62, 0x7d, 0xcc, 0x55, 0x93, 0x0e, 0x1f, 0xbd, 0xfa, 0x28, 0x99, 0x52, - 0x9c, 0xed, 0x16, 0x8a, 0xe0, 0x74, 0x27, 0xcf, 0x54, 0x14, 0x8b, 0x1b, 0x4b, 0xfb, 0x19, 0xac, - 0xe4, 0xd6, 0x3d, 0x9d, 0x6b, 0x6c, 0x8a, 0x71, 0x1f, 0xcc, 0x7a, 0xb6, 0xfe, 0xb1, 0xa3, 0xc9, - 0xd6, 0xff, 0x31, 0x00, 0x75, 0x49, 0x5d, 0x1a, 0x1f, 0x56, 0xac, 0x5c, 0xa5, 0xe1, 0x38, 0xb5, - 0x07, 0x52, 0x15, 0x19, 0xac, 0x91, 0x44, 0xff, 0x27, 0xf7, 0x39, 0x0b, 0x6e, 0x61, 0x69, 0x58, - 0x5f, 0x13, 0x3f, 0x75, 0x4f, 0x5a, 0xfc, 0x13, 0x07, 0xa6, 0xf9, 0xca, 0xcb, 0x0a, 0xf7, 0x54, - 0xb4, 0x10, 0x77, 0x7b, 0x6c, 0x87, 0xae, 0xb0, 0x28, 0xbe, 0xaa, 0x41, 0x95, 0x39, 0xba, 0xf7, - 0xe9, 0x09, 0xfa, 0x72, 0x8e, 0x4a, 0x71, 0xcc, 0x96, 0xcd, 0x32, 0xff, 0x51, 0x82, 0x13, 0x37, - 0x07, 0xd1, 0x22, 0xfe, 0x59, 0x5f, 0x93, 0x2a, 0x62, 0xdd, 0xfb, 0xc5, 0x43, 0x32, 0xa9, 0xea, - 0x2f, 0x27, 0x1c, 0xc8, 0xb0, 0xfa, 0x79, 0x07, 0xa6, 0xbc, 0x4c, 0xa8, 0x09, 0xb3, 0x03, 0x59, - 0xb1, 0x49, 0xcd, 0x45, 0x69, 0xfc, 0x0a, 0x13, 0xf2, 0xb2, 0x51, 0x2d, 0xb8, 0x87, 0x38, 0xfa, - 0x81, 0x03, 0x0f, 0x24, 0x5e, 0xbc, 0xcd, 0xf3, 0x12, 0xc7, 0xe9, 0x5d, 0x5d, 0xd1, 0xb9, 0x93, - 0x6c, 0x37, 0xbe, 0x62, 0x7d, 0x37, 0x6e, 0xf4, 0xa7, 0xc9, 0xf7, 0xe5, 0x23, 0x62, 0x5f, 0x3e, - 0xb0, 0x4f, 0x4d, 0xbc, 0x5f, 0xd7, 0xa7, 0x3f, 0xe5, 0xf0, 0xf7, 0xab, 0xfa, 0x8a, 0x7c, 0x9b, - 0xa6, 0xc8, 0x77, 0xd9, 0xe6, 0x0b, 0x3a, 0xba, 0xec, 0xf9, 0xab, 0x0e, 0x9c, 0xcc, 0x3b, 0x91, - 0x72, 0xba, 0xf4, 0x11, 0xb3, 0x4b, 0x16, 0xb5, 0x2c, 0xbd, 0x43, 0x56, 0x1e, 0xf0, 0x98, 0xbe, - 0x02, 0x0f, 0xdf, 0xee, 0x2b, 0xde, 0x0e, 0xdf, 0x98, 0x2e, 0x16, 0xff, 0x69, 0x49, 0xf3, 0x42, - 0x26, 0xa4, 0x63, 0x3d, 0x86, 0x3b, 0x80, 0x11, 0x3f, 0x68, 0xf9, 0x01, 0x11, 0xf7, 0x35, 0x6d, - 0xea, 0xb0, 0xe2, 0x01, 0x1e, 0x8a, 0x1d, 0x0b, 0x2a, 0xf7, 0xd8, 0x29, 0x99, 0x7d, 0xd2, 0x6c, - 0xf8, 0xe8, 0x9f, 0x34, 0xbb, 0x0e, 0xa5, 0xeb, 0x7e, 0xd2, 0x64, 0xc1, 0x14, 0xc2, 0xd7, 0x67, - 0xe1, 0x9e, 0x23, 0x45, 0x97, 0x8e, 0xfd, 0x9a, 0x24, 0x80, 0x53, 0x5a, 0xe8, 0x1c, 0x27, 0xcc, - 0x22, 0xb7, 0xb3, 0x21, 0xb5, 0xd7, 0x64, 0x01, 0x4e, 0xeb, 0xd0, 0xc9, 0x1a, 0xa7, 0xbf, 0x64, - 0x42, 0x24, 0x91, 0xb7, 0xd7, 0x46, 0x3e, 0x46, 0x81, 0x91, 0xdf, 0x26, 0xbe, 0xa6, 0xd1, 0xc0, - 0x06, 0x45, 0x95, 0x3a, 0x79, 0xac, 0x6f, 0xea, 0xe4, 0xd7, 0x99, 0xc0, 0x96, 0xf8, 0x41, 0x97, - 0xac, 0x05, 0x22, 0xde, 0xfb, 0xb2, 0x9d, 0xbb, 0xcf, 0x1c, 0x27, 0x57, 0xc1, 0xd3, 0xdf, 0x58, - 0xa3, 0xa7, 0xb9, 0x5c, 0xca, 0xfb, 0xba, 0x5c, 0x52, 0x93, 0xcb, 0xb8, 0x75, 0x93, 0x4b, 0x42, - 0x3a, 0x56, 0x4c, 0x2e, 0x3f, 0x55, 0xe6, 0x80, 0xbf, 0x70, 0x00, 0x29, 0xb9, 0x4b, 0x31, 0xd4, - 0x23, 0x08, 0xaa, 0xfc, 0xb8, 0x03, 0x10, 0xa8, 0x87, 0x2f, 0xed, 0x9e, 0x82, 0x1c, 0x67, 0xda, - 0x81, 0x14, 0x86, 0x35, 0x9a, 0xee, 0xff, 0x70, 0xd2, 0xd8, 0xe5, 0x74, 0xec, 0x47, 0x10, 0x44, - 0xb6, 0x6b, 0x06, 0x91, 0x6d, 0x58, 0x34, 0xdd, 0xab, 0x61, 0xf4, 0x09, 0x27, 0xfb, 0x71, 0x01, - 0x8e, 0xe9, 0x95, 0xab, 0xe4, 0x28, 0x3e, 0xf6, 0x75, 0x23, 0x82, 0xf6, 0xaa, 0xdd, 0xf1, 0x56, - 0x85, 0x07, 0x28, 0x2f, 0x5a, 0xfb, 0x63, 0x99, 0x68, 0xed, 0x6b, 0xf6, 0x49, 0xef, 0x1f, 0xb2, - 0xfd, 0x5f, 0x1d, 0x38, 0x91, 0x69, 0x71, 0x04, 0x0b, 0x6c, 0xc7, 0x5c, 0x60, 0xcf, 0x59, 0x1f, - 0x75, 0x9f, 0xd5, 0xf5, 0xcd, 0x42, 0xcf, 0x68, 0x99, 0x12, 0xf7, 0x49, 0x07, 0x8a, 0x54, 0x5a, - 0x96, 0xf1, 0x5c, 0x1f, 0x39, 0x94, 0x15, 0xc0, 0xe4, 0x7a, 0xc1, 0x9d, 0x55, 0xff, 0x18, 0x0c, - 0x73, 0xea, 0xd3, 0x9f, 0x70, 0x00, 0xd2, 0x4a, 0xf7, 0x4a, 0x04, 0x76, 0xbf, 0x5d, 0x80, 0x53, - 0xb9, 0xcb, 0x08, 0x7d, 0x5a, 0x59, 0xe4, 0x1c, 0xdb, 0xd1, 0x8a, 0x06, 0x21, 0xdd, 0x30, 0x37, - 0x61, 0x18, 0xe6, 0x84, 0x3d, 0xee, 0x5e, 0x29, 0x30, 0x82, 0x4d, 0x6b, 0x93, 0xf5, 0x23, 0x27, - 0x0d, 0x80, 0x55, 0x79, 0x8d, 0xfe, 0x12, 0x5e, 0xe2, 0x71, 0x7f, 0xac, 0xdd, 0x70, 0x90, 0x03, - 0x3d, 0x02, 0x5e, 0x71, 0xdd, 0xe4, 0x15, 0xd8, 0xbe, 0x1f, 0xb9, 0x0f, 0xb3, 0x78, 0x05, 0xf2, - 0x1c, 0xcb, 0x83, 0x25, 0x45, 0x34, 0xae, 0xc3, 0x16, 0x06, 0xbe, 0x0e, 0x3b, 0x01, 0xe5, 0x17, - 0x7d, 0x95, 0x4d, 0x73, 0x7e, 0xf6, 0x3b, 0x3f, 0x3c, 0x7b, 0xdf, 0x77, 0x7f, 0x78, 0xf6, 0xbe, - 0x1f, 0xfc, 0xf0, 0xec, 0x7d, 0x1f, 0xbf, 0x79, 0xd6, 0xf9, 0xce, 0xcd, 0xb3, 0xce, 0x77, 0x6f, - 0x9e, 0x75, 0x7e, 0x70, 0xf3, 0xac, 0xf3, 0x1f, 0x6e, 0x9e, 0x75, 0xfe, 0xde, 0x7f, 0x3c, 0x7b, - 0xdf, 0x8b, 0x63, 0x72, 0x60, 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x84, 0x02, 0x48, 0xf8, 0xe2, - 0xd6, 0x00, 0x00, + 0x29, 0xe5, 0x54, 0x45, 0xae, 0x28, 0x25, 0xfd, 0xb0, 0xc1, 0xe8, 0x92, 0xa8, 0x52, 0x49, 0x54, + 0x95, 0xa8, 0x62, 0x27, 0xbe, 0x3c, 0x2a, 0xd5, 0xcf, 0xe9, 0x9e, 0x9d, 0xc5, 0x2d, 0xee, 0x1a, + 0x38, 0x95, 0xfd, 0x0b, 0xd8, 0xaf, 0xbb, 0xbf, 0xaf, 0xbb, 0xa7, 0xfb, 0xeb, 0xef, 0xd5, 0x5f, + 0xc3, 0x7a, 0xc3, 0x4f, 0x9a, 0xdd, 0xcd, 0xd9, 0x5a, 0xd8, 0x3e, 0xe7, 0x45, 0x8d, 0xb0, 0x13, + 0x85, 0x2f, 0xb3, 0x7f, 0xde, 0x79, 0x3d, 0x8c, 0xb6, 0xb7, 0x5a, 0xe1, 0xf5, 0xf8, 0xdc, 0xce, + 0xd3, 0xe7, 0x3a, 0xdb, 0x8d, 0x73, 0x5e, 0xc7, 0x8f, 0xcf, 0x49, 0xe8, 0xb9, 0x9d, 0xa7, 0xbc, + 0x56, 0xa7, 0xe9, 0x3d, 0x75, 0xae, 0x41, 0x02, 0x12, 0x79, 0x09, 0xa9, 0xcf, 0x76, 0xa2, 0x30, + 0x09, 0xd1, 0x07, 0x52, 0x8c, 0xb3, 0x12, 0x23, 0xfb, 0xe7, 0xc3, 0x0a, 0xe3, 0xec, 0xce, 0xd3, + 0xb3, 0x9d, 0xed, 0xc6, 0x2c, 0xc5, 0x38, 0x2b, 0xa1, 0xb3, 0x12, 0xe3, 0xf4, 0x3b, 0xb5, 0x3e, + 0x35, 0xc2, 0x46, 0x78, 0x8e, 0x21, 0xde, 0xec, 0x6e, 0xb1, 0x5f, 0xec, 0x07, 0xfb, 0x8f, 0x13, + 0x9c, 0x76, 0xb7, 0x9f, 0x89, 0x67, 0xfd, 0x90, 0xf6, 0xef, 0x5c, 0x2d, 0x8c, 0xc8, 0xb9, 0x9d, + 0x9e, 0x4e, 0x4d, 0xbf, 0x43, 0xab, 0xd3, 0x09, 0x5b, 0x7e, 0x6d, 0x37, 0xaf, 0xd6, 0xbb, 0xd2, + 0x5a, 0x6d, 0xaf, 0xd6, 0xf4, 0x03, 0x12, 0xed, 0xa6, 0x43, 0x6f, 0x93, 0xc4, 0xcb, 0x6b, 0x75, + 0xae, 0x5f, 0xab, 0xa8, 0x1b, 0x24, 0x7e, 0x9b, 0xf4, 0x34, 0xf8, 0xab, 0xb7, 0x6b, 0x10, 0xd7, + 0x9a, 0xa4, 0xed, 0xf5, 0xb4, 0x7b, 0xba, 0x5f, 0xbb, 0x6e, 0xe2, 0xb7, 0xce, 0xf9, 0x41, 0x12, + 0x27, 0x51, 0xb6, 0x91, 0x7b, 0x01, 0x46, 0xe6, 0xda, 0x61, 0x37, 0x48, 0xd0, 0x7b, 0xa1, 0xb8, + 0xe3, 0xb5, 0xba, 0xa4, 0xe2, 0x3c, 0xec, 0x3c, 0x5e, 0x9a, 0x7f, 0xf4, 0x3b, 0x7b, 0x33, 0xf7, + 0xdd, 0xdc, 0x9b, 0x29, 0x3e, 0x4f, 0x81, 0xb7, 0xf6, 0x66, 0x4e, 0x92, 0xa0, 0x16, 0xd6, 0xfd, + 0xa0, 0x71, 0xee, 0xe5, 0x38, 0x0c, 0x66, 0xaf, 0x74, 0xdb, 0x9b, 0x24, 0xc2, 0xbc, 0x8d, 0xfb, + 0x6f, 0x0a, 0x70, 0x6c, 0x2e, 0xaa, 0x35, 0xfd, 0x1d, 0x52, 0x4d, 0x28, 0xfe, 0xc6, 0x2e, 0x6a, + 0xc2, 0x50, 0xe2, 0x45, 0x0c, 0x5d, 0xf9, 0xfc, 0xea, 0xec, 0xdd, 0x7e, 0xf7, 0xd9, 0x0d, 0x2f, + 0x92, 0xb8, 0xe7, 0x47, 0x6f, 0xee, 0xcd, 0x0c, 0x6d, 0x78, 0x11, 0xa6, 0x24, 0x50, 0x0b, 0x86, + 0x83, 0x30, 0x20, 0x95, 0x02, 0x23, 0x75, 0xe5, 0xee, 0x49, 0x5d, 0x09, 0x03, 0x35, 0x8e, 0xf9, + 0xb1, 0x9b, 0x7b, 0x33, 0xc3, 0x14, 0x82, 0x19, 0x15, 0x3a, 0xae, 0x57, 0xfd, 0x4e, 0x65, 0xc8, + 0xd6, 0xb8, 0x5e, 0xf4, 0x3b, 0xe6, 0xb8, 0x5e, 0xf4, 0x3b, 0x98, 0x92, 0x70, 0x3f, 0x5b, 0x80, + 0xd2, 0x5c, 0xd4, 0xe8, 0xb6, 0x49, 0x90, 0xc4, 0xe8, 0x63, 0x00, 0x1d, 0x2f, 0xf2, 0xda, 0x24, + 0x21, 0x51, 0x5c, 0x71, 0x1e, 0x1e, 0x7a, 0xbc, 0x7c, 0x7e, 0xe5, 0xee, 0xc9, 0xaf, 0x4b, 0x9c, + 0xf3, 0x48, 0x7c, 0x72, 0x50, 0xa0, 0x18, 0x6b, 0x24, 0xd1, 0x6b, 0x50, 0xf2, 0xa2, 0xc4, 0xdf, + 0xf2, 0x6a, 0x49, 0x5c, 0x29, 0x30, 0xfa, 0xcf, 0xde, 0x3d, 0xfd, 0x39, 0x81, 0x72, 0xfe, 0xb8, + 0x20, 0x5f, 0x92, 0x90, 0x18, 0xa7, 0xf4, 0xdc, 0xdf, 0x1b, 0x86, 0xf2, 0x5c, 0x94, 0x2c, 0x2f, + 0x54, 0x13, 0x2f, 0xe9, 0xc6, 0xe8, 0x0f, 0x1d, 0x38, 0x11, 0xf3, 0x69, 0xf3, 0x49, 0xbc, 0x1e, + 0x85, 0x35, 0x12, 0xc7, 0xa4, 0x2e, 0xe6, 0x65, 0xcb, 0x4a, 0xbf, 0x24, 0xb1, 0xd9, 0x6a, 0x2f, + 0xa1, 0x0b, 0x41, 0x12, 0xed, 0xce, 0x3f, 0x25, 0xfa, 0x7c, 0x22, 0xa7, 0xc6, 0x9b, 0x6f, 0xcf, + 0x20, 0x39, 0x14, 0x8a, 0x89, 0x7f, 0x62, 0x9c, 0xd7, 0x6b, 0xf4, 0x55, 0x07, 0xc6, 0x3b, 0x61, + 0x3d, 0xc6, 0xa4, 0x16, 0x76, 0x3b, 0xa4, 0x2e, 0xa6, 0xf7, 0xc3, 0x76, 0x87, 0xb1, 0xae, 0x51, + 0xe0, 0xfd, 0x3f, 0x29, 0xfa, 0x3f, 0xae, 0x17, 0x61, 0xa3, 0x2b, 0xe8, 0x19, 0x18, 0x0f, 0xc2, + 0xa4, 0xda, 0x21, 0x35, 0x7f, 0xcb, 0x27, 0x75, 0xb6, 0xf0, 0xc7, 0xd2, 0x96, 0x57, 0xb4, 0x32, + 0x6c, 0xd4, 0x9c, 0x5e, 0x82, 0x4a, 0xbf, 0x99, 0x43, 0x53, 0x30, 0xb4, 0x4d, 0x76, 0x39, 0xb3, + 0xc1, 0xf4, 0x5f, 0x74, 0x52, 0x32, 0x20, 0xba, 0x8d, 0xc7, 0x04, 0x67, 0x79, 0x4f, 0xe1, 0x19, + 0x67, 0xfa, 0xfd, 0x70, 0xbc, 0xa7, 0xeb, 0x07, 0x41, 0xe0, 0x7e, 0x77, 0x04, 0xc6, 0xe4, 0xa7, + 0x40, 0x0f, 0xc3, 0x70, 0xe0, 0xb5, 0x25, 0x9f, 0x1b, 0x17, 0xe3, 0x18, 0xbe, 0xe2, 0xb5, 0xe9, + 0x0e, 0xf7, 0xda, 0x84, 0xd6, 0xe8, 0x78, 0x49, 0x93, 0xe1, 0xd1, 0x6a, 0xac, 0x7b, 0x49, 0x13, + 0xb3, 0x12, 0xf4, 0x20, 0x0c, 0xb7, 0xc3, 0x3a, 0x61, 0x73, 0x51, 0xe4, 0x1c, 0x62, 0x35, 0xac, + 0x13, 0xcc, 0xa0, 0xb4, 0xfd, 0x56, 0x14, 0xb6, 0x2b, 0xc3, 0x66, 0xfb, 0xa5, 0x28, 0x6c, 0x63, + 0x56, 0x82, 0xbe, 0xe2, 0xc0, 0x94, 0x5c, 0xdb, 0x97, 0xc3, 0x9a, 0x97, 0xf8, 0x61, 0x50, 0x29, + 0x32, 0x8e, 0x82, 0xed, 0x6d, 0x29, 0x89, 0x79, 0xbe, 0x22, 0xba, 0x30, 0x95, 0x2d, 0xc1, 0x3d, + 0xbd, 0x40, 0xe7, 0x01, 0x1a, 0xad, 0x70, 0xd3, 0x6b, 0xd1, 0x09, 0xa9, 0x8c, 0xb0, 0x21, 0x28, + 0xce, 0xb0, 0xac, 0x4a, 0xb0, 0x56, 0x0b, 0xdd, 0x80, 0x51, 0x8f, 0x73, 0xff, 0xca, 0x28, 0x1b, + 0xc4, 0x73, 0x36, 0x06, 0x61, 0x1c, 0x27, 0xf3, 0xe5, 0x9b, 0x7b, 0x33, 0xa3, 0x02, 0x88, 0x25, + 0x39, 0xf4, 0x24, 0x8c, 0x85, 0x1d, 0xda, 0x6f, 0xaf, 0x55, 0x19, 0x63, 0x0b, 0x73, 0x4a, 0xf4, + 0x75, 0x6c, 0x4d, 0xc0, 0xb1, 0xaa, 0x81, 0x9e, 0x80, 0xd1, 0xb8, 0xbb, 0x49, 0xbf, 0x63, 0xa5, + 0xc4, 0x06, 0x76, 0x4c, 0x54, 0x1e, 0xad, 0x72, 0x30, 0x96, 0xe5, 0xe8, 0xdd, 0x50, 0x8e, 0x48, + 0xad, 0x1b, 0xc5, 0x84, 0x7e, 0xd8, 0x0a, 0x30, 0xdc, 0x27, 0x44, 0xf5, 0x32, 0x4e, 0x8b, 0xb0, + 0x5e, 0x0f, 0xbd, 0x0f, 0x26, 0xe9, 0x07, 0xbe, 0x70, 0xa3, 0x13, 0x91, 0x38, 0xa6, 0x5f, 0xb5, + 0xcc, 0x08, 0x9d, 0x16, 0x2d, 0x27, 0x97, 0x8c, 0x52, 0x9c, 0xa9, 0x8d, 0x5e, 0x07, 0xf0, 0x14, + 0xcf, 0xa8, 0x8c, 0xb3, 0xc9, 0xbc, 0x6c, 0x6f, 0x45, 0x2c, 0x2f, 0xcc, 0x4f, 0xd2, 0xef, 0x98, + 0xfe, 0xc6, 0x1a, 0x3d, 0x3a, 0x3f, 0x75, 0xd2, 0x22, 0x09, 0xa9, 0x57, 0x26, 0xd8, 0x80, 0xd5, + 0xfc, 0x2c, 0x72, 0x30, 0x96, 0xe5, 0xee, 0xdf, 0x2d, 0x80, 0x86, 0x05, 0xcd, 0xc3, 0x98, 0xe0, + 0x6b, 0x62, 0x4b, 0xce, 0x3f, 0x26, 0xbf, 0x83, 0xfc, 0x82, 0xb7, 0xf6, 0x72, 0xf9, 0xa1, 0x6a, + 0x87, 0xde, 0x80, 0x72, 0x27, 0xac, 0xaf, 0x92, 0xc4, 0xab, 0x7b, 0x89, 0x27, 0x4e, 0x73, 0x0b, + 0x27, 0x8c, 0xc4, 0x38, 0x7f, 0x8c, 0x7e, 0xba, 0xf5, 0x94, 0x04, 0xd6, 0xe9, 0xa1, 0x67, 0x01, + 0xc5, 0x24, 0xda, 0xf1, 0x6b, 0x64, 0xae, 0x56, 0xa3, 0x22, 0x11, 0xdb, 0x00, 0x43, 0x6c, 0x30, + 0xd3, 0x62, 0x30, 0xa8, 0xda, 0x53, 0x03, 0xe7, 0xb4, 0x72, 0xbf, 0x57, 0x80, 0x49, 0x6d, 0xac, + 0x1d, 0x52, 0x43, 0x6f, 0x39, 0x70, 0x4c, 0x1d, 0x67, 0xf3, 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, 0xfa, 0xcb, 0x0e, 0x9c, 0xcc, 0x43, 0x91, 0xc3, 0x73, 0x9b, 0x3a, + 0xcf, 0xb5, 0xca, 0xbc, 0x28, 0x55, 0x3a, 0x18, 0x9d, 0x8f, 0xff, 0xbf, 0x02, 0x4c, 0xe9, 0x4b, + 0x88, 0x49, 0x02, 0xff, 0xdc, 0x81, 0x53, 0x72, 0x04, 0x98, 0xc4, 0xdd, 0x56, 0x66, 0x7a, 0xdb, + 0x56, 0xa7, 0x97, 0x9f, 0xa4, 0x73, 0x79, 0xf4, 0xf8, 0x34, 0x3f, 0x24, 0xa6, 0xf9, 0x54, 0x6e, + 0x1d, 0x9c, 0xdf, 0xd5, 0xe9, 0x6f, 0x3a, 0x30, 0xdd, 0x1f, 0x69, 0xce, 0xc4, 0x77, 0xcc, 0x89, + 0x7f, 0xd1, 0xde, 0x20, 0x39, 0x79, 0x36, 0xfd, 0x6c, 0xb0, 0xfa, 0x07, 0xf8, 0xad, 0x31, 0xe8, + 0x39, 0x43, 0xd0, 0x53, 0x50, 0x16, 0xec, 0xf8, 0x72, 0xd8, 0x88, 0x59, 0x27, 0xc7, 0xf8, 0x5e, + 0x9b, 0x4b, 0xc1, 0x58, 0xaf, 0x83, 0xea, 0x50, 0x88, 0x9f, 0x16, 0x5d, 0xb7, 0xc0, 0xde, 0xaa, + 0x4f, 0x2b, 0x29, 0x72, 0xe4, 0xe6, 0xde, 0x4c, 0xa1, 0xfa, 0x34, 0x2e, 0xc4, 0x4f, 0x53, 0x49, + 0xbd, 0xe1, 0x27, 0xf6, 0x24, 0xf5, 0x65, 0x3f, 0x51, 0x74, 0x98, 0xa4, 0xbe, 0xec, 0x27, 0x98, + 0x92, 0xa0, 0x1a, 0x48, 0x33, 0x49, 0x3a, 0xec, 0xc4, 0xb7, 0xa2, 0x81, 0x5c, 0xdc, 0xd8, 0x58, + 0x57, 0xb4, 0x98, 0x7c, 0x41, 0x21, 0x98, 0x51, 0x41, 0x9f, 0x71, 0xe8, 0x8c, 0xf3, 0xc2, 0x30, + 0xda, 0x15, 0x82, 0xc3, 0x55, 0x7b, 0x4b, 0x20, 0x8c, 0x76, 0x15, 0x71, 0xf1, 0x21, 0x55, 0x01, + 0xd6, 0x49, 0xb3, 0x81, 0xd7, 0xb7, 0x62, 0x26, 0x27, 0xd8, 0x19, 0xf8, 0xe2, 0x52, 0x35, 0x33, + 0xf0, 0xc5, 0xa5, 0x2a, 0x66, 0x54, 0xe8, 0x07, 0x8d, 0xbc, 0xeb, 0x42, 0xc6, 0xb0, 0xf0, 0x41, + 0xb1, 0x77, 0xdd, 0xfc, 0xa0, 0xd8, 0xbb, 0x8e, 0x29, 0x09, 0x4a, 0x29, 0x8c, 0x63, 0x26, 0x52, + 0x58, 0xa1, 0xb4, 0x56, 0xad, 0x9a, 0x94, 0xd6, 0xaa, 0x55, 0x4c, 0x49, 0xb0, 0x45, 0x5a, 0x8b, + 0x99, 0x3c, 0x62, 0x67, 0x91, 0x2e, 0x64, 0x28, 0x2d, 0x2f, 0x54, 0x31, 0x25, 0x41, 0x59, 0x86, + 0xf7, 0x6a, 0x37, 0xe2, 0xc2, 0x4c, 0xf9, 0xfc, 0x9a, 0x85, 0xf5, 0x42, 0xd1, 0x29, 0x6a, 0xa5, + 0x9b, 0x7b, 0x33, 0x45, 0x06, 0xc2, 0x9c, 0x90, 0xfb, 0x07, 0x43, 0x29, 0xbb, 0x90, 0xfc, 0x1c, + 0xfd, 0x1a, 0x3b, 0x08, 0x05, 0x2f, 0x10, 0xa2, 0xaf, 0x73, 0x68, 0xa2, 0xef, 0x09, 0x7e, 0xe2, + 0x19, 0xe4, 0x70, 0x96, 0x3e, 0xfa, 0x82, 0xd3, 0xab, 0xdb, 0x7a, 0xf6, 0xcf, 0xb2, 0xf4, 0x60, + 0xe6, 0x67, 0xc5, 0xbe, 0x2a, 0xef, 0xf4, 0x67, 0x9c, 0x54, 0x88, 0x88, 0xfb, 0x9d, 0x03, 0x1f, + 0x31, 0xcf, 0x01, 0x8b, 0x0a, 0xb9, 0xce, 0xf7, 0x3f, 0xeb, 0xc0, 0x84, 0x84, 0x53, 0xf1, 0x38, + 0x46, 0x37, 0x60, 0x4c, 0xf6, 0x54, 0x7c, 0x3d, 0x9b, 0xb6, 0x00, 0x25, 0xc4, 0xab, 0xce, 0x28, + 0x6a, 0xee, 0x5b, 0x23, 0x80, 0xd2, 0xb3, 0xaa, 0x13, 0xc6, 0x3e, 0xe3, 0x44, 0x77, 0x70, 0x0a, + 0x05, 0xda, 0x29, 0xf4, 0xbc, 0xcd, 0x53, 0x28, 0xed, 0x96, 0x71, 0x1e, 0x7d, 0x21, 0xc3, 0xb7, + 0xf9, 0xc1, 0xf4, 0xe1, 0x43, 0xe1, 0xdb, 0x5a, 0x17, 0xf6, 0xe7, 0xe0, 0x3b, 0x82, 0x83, 0xf3, + 0xa3, 0xeb, 0x17, 0xec, 0x72, 0x70, 0xad, 0x17, 0x59, 0x5e, 0x1e, 0x71, 0x0e, 0xcb, 0xcf, 0xae, + 0x6b, 0x56, 0x39, 0xac, 0x46, 0xd5, 0xe4, 0xb5, 0x11, 0xe7, 0xb5, 0x23, 0xb6, 0x68, 0x6a, 0xbc, + 0x36, 0x4b, 0x53, 0x71, 0xdd, 0x57, 0x25, 0xd7, 0xe5, 0xa7, 0xd6, 0x0b, 0x96, 0xb9, 0xae, 0x46, + 0xb7, 0x97, 0xff, 0xbe, 0x02, 0xa7, 0x7a, 0xeb, 0x61, 0xb2, 0x85, 0xce, 0x41, 0xa9, 0x16, 0x06, + 0x5b, 0x7e, 0x63, 0xd5, 0xeb, 0x08, 0x7d, 0x4d, 0xf1, 0xa2, 0x05, 0x59, 0x80, 0xd3, 0x3a, 0xe8, + 0x21, 0xce, 0x78, 0xb8, 0x45, 0xa4, 0x2c, 0xaa, 0x0e, 0xad, 0x90, 0x5d, 0xc6, 0x85, 0xde, 0x33, + 0xf6, 0x95, 0xaf, 0xcf, 0xdc, 0xf7, 0xf1, 0x3f, 0x7e, 0xf8, 0x3e, 0xf7, 0x8f, 0x86, 0xe0, 0x81, + 0x5c, 0x9a, 0x42, 0x5a, 0xff, 0x2d, 0x43, 0x5a, 0xd7, 0xca, 0x05, 0x17, 0xb9, 0x66, 0x53, 0x90, + 0xd5, 0xd0, 0xe7, 0xc9, 0xe5, 0x5a, 0x31, 0xce, 0xef, 0x14, 0x9d, 0xa8, 0xc0, 0x6b, 0x93, 0xb8, + 0xe3, 0xd5, 0x88, 0x18, 0xbd, 0x9a, 0xa8, 0x2b, 0xb2, 0x00, 0xa7, 0x75, 0xb8, 0x0a, 0xbd, 0xe5, + 0x75, 0x5b, 0x89, 0x30, 0x94, 0x69, 0x2a, 0x34, 0x03, 0x63, 0x59, 0x8e, 0xfe, 0x9e, 0x03, 0xa8, + 0x97, 0xaa, 0xd8, 0x88, 0x1b, 0x87, 0x31, 0x0f, 0xf3, 0xa7, 0x6f, 0x6a, 0x4a, 0xb8, 0x36, 0xd2, + 0x9c, 0x7e, 0x68, 0xdf, 0xf4, 0xa3, 0xe9, 0x39, 0xc4, 0x95, 0x83, 0x01, 0x6c, 0x68, 0xcc, 0xd4, + 0x52, 0xab, 0x91, 0x38, 0xe6, 0xe6, 0x38, 0xdd, 0xd4, 0xc2, 0xc0, 0x58, 0x96, 0xa3, 0x19, 0x28, + 0x92, 0x28, 0x0a, 0x23, 0xa1, 0x6b, 0xb3, 0x65, 0x7c, 0x81, 0x02, 0x30, 0x87, 0xbb, 0x3f, 0x2a, + 0x40, 0xa5, 0x9f, 0x76, 0x82, 0x7e, 0x57, 0xd3, 0xab, 0x85, 0xe6, 0x24, 0x14, 0xbf, 0xf0, 0xf0, + 0x74, 0xa2, 0xac, 0x02, 0xd8, 0x47, 0xc3, 0x16, 0xa5, 0x38, 0xdb, 0xc1, 0xe9, 0x2f, 0x6a, 0x1a, + 0xb6, 0x8e, 0x22, 0xe7, 0x80, 0xdf, 0x32, 0x0f, 0xf8, 0x75, 0xdb, 0x83, 0xd2, 0x8f, 0xf9, 0x3f, + 0x29, 0xc2, 0x09, 0x59, 0x5a, 0x25, 0xf4, 0xa8, 0x7c, 0xae, 0x4b, 0xa2, 0x5d, 0xf4, 0x7d, 0x07, + 0x4e, 0x7a, 0x59, 0xd3, 0x8d, 0x4f, 0x0e, 0x61, 0xa2, 0x35, 0xaa, 0xb3, 0x73, 0x39, 0x14, 0xf9, + 0x44, 0x9f, 0x17, 0x13, 0x7d, 0x32, 0xaf, 0x4a, 0x1f, 0xbb, 0x7b, 0xee, 0x00, 0xd0, 0x33, 0x30, + 0x2e, 0xe1, 0xcc, 0xdc, 0xc3, 0xb7, 0xb8, 0x32, 0x6e, 0xcf, 0x69, 0x65, 0xd8, 0xa8, 0x49, 0x5b, + 0x26, 0xa4, 0xdd, 0x69, 0x79, 0x09, 0xd1, 0x0c, 0x45, 0xaa, 0xe5, 0x86, 0x56, 0x86, 0x8d, 0x9a, + 0xe8, 0x31, 0x18, 0x09, 0xc2, 0x3a, 0xb9, 0x54, 0x17, 0x06, 0xe2, 0x49, 0xd1, 0x66, 0xe4, 0x0a, + 0x83, 0x62, 0x51, 0x8a, 0x1e, 0x4d, 0xad, 0x71, 0x45, 0xb6, 0x85, 0xca, 0x79, 0x96, 0x38, 0xf4, + 0x0f, 0x1c, 0x28, 0xd1, 0x16, 0x1b, 0xbb, 0x1d, 0x42, 0xcf, 0x36, 0xfa, 0x45, 0xea, 0x87, 0xf3, + 0x45, 0xae, 0x48, 0x32, 0xa6, 0xa9, 0xa3, 0xa4, 0xe0, 0x6f, 0xbe, 0x3d, 0x33, 0x26, 0x7f, 0xe0, + 0xb4, 0x57, 0xd3, 0xcb, 0x70, 0x7f, 0xdf, 0xaf, 0x79, 0x20, 0x57, 0xc0, 0xdf, 0x80, 0x49, 0xb3, + 0x13, 0x07, 0xf2, 0x03, 0xfc, 0x53, 0x6d, 0xdb, 0xf1, 0x71, 0x09, 0x7e, 0x76, 0xcf, 0xa4, 0x59, + 0xb5, 0x18, 0x16, 0xc5, 0xd2, 0x33, 0x17, 0xc3, 0xa2, 0x58, 0x0c, 0x8b, 0xee, 0x1f, 0x3a, 0xe9, + 0xd6, 0xd4, 0xc4, 0x3c, 0x7a, 0x30, 0x77, 0xa3, 0x96, 0x60, 0xc4, 0xea, 0x60, 0xbe, 0x8a, 0x2f, + 0x63, 0x0a, 0x47, 0x5f, 0xd4, 0xb8, 0x23, 0x6d, 0xd6, 0x15, 0x6e, 0x0d, 0x4b, 0x26, 0x7a, 0x03, + 0x71, 0x2f, 0xff, 0x13, 0x05, 0x38, 0xdb, 0x05, 0xf7, 0x0b, 0x05, 0x78, 0x68, 0x5f, 0xa1, 0x35, + 0xb7, 0xe3, 0xce, 0x3d, 0xef, 0x38, 0x3d, 0xd6, 0x22, 0xd2, 0x09, 0xaf, 0xe2, 0xcb, 0xe2, 0x7b, + 0xa9, 0x63, 0x0d, 0x73, 0x30, 0x96, 0xe5, 0x54, 0x74, 0xd8, 0x26, 0xbb, 0x4b, 0x61, 0xd4, 0xf6, + 0x12, 0xc1, 0x1d, 0x94, 0xe8, 0xb0, 0x22, 0x0b, 0x70, 0x5a, 0xc7, 0xfd, 0xbe, 0x03, 0xd9, 0x0e, + 0x20, 0x0f, 0x26, 0xbb, 0x31, 0x89, 0xe8, 0x91, 0x5a, 0x25, 0xb5, 0x88, 0xc8, 0xe5, 0xf9, 0xe8, + 0x2c, 0xf7, 0xf6, 0xd3, 0x11, 0xce, 0xd6, 0xc2, 0x88, 0xcc, 0xee, 0x3c, 0x35, 0xcb, 0x6b, 0xac, + 0x90, 0xdd, 0x2a, 0x69, 0x11, 0x8a, 0x63, 0x1e, 0xdd, 0xdc, 0x9b, 0x99, 0xbc, 0x6a, 0x20, 0xc0, + 0x19, 0x84, 0x94, 0x44, 0xc7, 0x8b, 0xe3, 0xeb, 0x61, 0x54, 0x17, 0x24, 0x0a, 0x07, 0x26, 0xb1, + 0x6e, 0x20, 0xc0, 0x19, 0x84, 0xee, 0xf7, 0xa8, 0xfa, 0xa8, 0x4b, 0xad, 0xe8, 0xeb, 0x54, 0xf6, + 0xa1, 0x90, 0xf9, 0x56, 0xb8, 0xb9, 0x10, 0x06, 0x89, 0xe7, 0x07, 0x44, 0x06, 0x0b, 0x6c, 0x58, + 0x92, 0x91, 0x0d, 0xdc, 0xa9, 0x0d, 0xbf, 0xb7, 0x0c, 0xe7, 0xf4, 0x85, 0xca, 0x38, 0x9b, 0xad, + 0x70, 0x33, 0xeb, 0x05, 0xa4, 0x95, 0x30, 0x2b, 0x71, 0x7f, 0xe2, 0xc0, 0x99, 0x3e, 0xc2, 0x38, + 0xfa, 0xb2, 0x03, 0x13, 0x9b, 0x3f, 0x15, 0x63, 0x33, 0xbb, 0x81, 0xde, 0x07, 0x93, 0x14, 0x40, + 0x4f, 0x22, 0xb1, 0x36, 0x0b, 0xa6, 0x87, 0x6a, 0xde, 0x28, 0xc5, 0x99, 0xda, 0xee, 0xaf, 0x17, + 0x20, 0x87, 0x0a, 0x7a, 0x12, 0xc6, 0x48, 0x50, 0xef, 0x84, 0x7e, 0x90, 0x08, 0x66, 0xa4, 0xb8, + 0xde, 0x05, 0x01, 0xc7, 0xaa, 0x86, 0xd0, 0x3f, 0xc4, 0xc4, 0x14, 0x7a, 0xf4, 0x0f, 0xd1, 0xf3, + 0xb4, 0x0e, 0x6a, 0xc0, 0x94, 0xc7, 0xfd, 0x2b, 0x6c, 0xed, 0xb1, 0x65, 0x3a, 0x74, 0x90, 0x65, + 0x7a, 0x92, 0xb9, 0x3f, 0x33, 0x28, 0x70, 0x0f, 0x52, 0xf4, 0x6e, 0x28, 0x77, 0x63, 0x52, 0x5d, + 0x5c, 0x59, 0x88, 0x48, 0x9d, 0x6b, 0xc5, 0x9a, 0xdf, 0xef, 0x6a, 0x5a, 0x84, 0xf5, 0x7a, 0xee, + 0xbf, 0x70, 0x60, 0x74, 0xde, 0xab, 0x6d, 0x87, 0x5b, 0x5b, 0x74, 0x2a, 0xea, 0xdd, 0x28, 0x35, + 0x6c, 0x69, 0x53, 0xb1, 0x28, 0xe0, 0x58, 0xd5, 0x40, 0x1b, 0x30, 0xc2, 0x37, 0xbc, 0xd8, 0x76, + 0x3f, 0xaf, 0x8d, 0x47, 0xc5, 0xf1, 0xb0, 0xe5, 0xd0, 0x4d, 0xfc, 0xd6, 0x2c, 0x8f, 0xe3, 0x99, + 0xbd, 0x14, 0x24, 0x6b, 0x51, 0x35, 0x89, 0xfc, 0xa0, 0x31, 0x0f, 0xf4, 0xb8, 0x58, 0x62, 0x38, + 0xb0, 0xc0, 0x45, 0x87, 0xd1, 0xf6, 0x6e, 0x48, 0x72, 0x82, 0xfd, 0xa8, 0x61, 0xac, 0xa6, 0x45, + 0x58, 0xaf, 0xe7, 0xfe, 0x91, 0x03, 0xa5, 0x79, 0x2f, 0xf6, 0x6b, 0x7f, 0x81, 0x98, 0xcf, 0x87, + 0xa0, 0xb8, 0xe0, 0xd5, 0x9a, 0x04, 0x5d, 0xcd, 0x2a, 0xbd, 0xe5, 0xf3, 0x8f, 0xe7, 0x91, 0x51, + 0x0a, 0xb0, 0x4e, 0x69, 0xa2, 0x9f, 0x6a, 0xec, 0xbe, 0xed, 0xc0, 0xe4, 0x42, 0xcb, 0x27, 0x41, + 0xb2, 0x40, 0xa2, 0x84, 0x4d, 0x5c, 0x03, 0xa6, 0x6a, 0x0a, 0x72, 0x27, 0x53, 0xc7, 0x56, 0xeb, + 0x42, 0x06, 0x05, 0xee, 0x41, 0x8a, 0xea, 0x70, 0x8c, 0xc3, 0xd2, 0x5d, 0x71, 0xa0, 0xf9, 0x63, + 0xd6, 0xd1, 0x05, 0x13, 0x03, 0xce, 0xa2, 0x74, 0x7f, 0xec, 0xc0, 0x99, 0x85, 0x56, 0x37, 0x4e, + 0x48, 0x74, 0x4d, 0x70, 0x23, 0x29, 0xde, 0xa2, 0x8f, 0xc0, 0x58, 0x5b, 0x7a, 0x6c, 0x9d, 0xdb, + 0x2c, 0x60, 0xc6, 0xcf, 0x68, 0x6d, 0xda, 0x99, 0xb5, 0xcd, 0x97, 0x49, 0x2d, 0x59, 0x25, 0x89, + 0x97, 0x86, 0x17, 0xa4, 0x30, 0xac, 0xb0, 0xa2, 0x0e, 0x0c, 0xc7, 0x1d, 0x52, 0xb3, 0x17, 0xdd, + 0x25, 0xc7, 0x50, 0xed, 0x90, 0x5a, 0xca, 0xd7, 0x99, 0xaf, 0x91, 0x51, 0x72, 0xff, 0xb7, 0x03, + 0x0f, 0xf4, 0x19, 0xef, 0x65, 0x3f, 0x4e, 0xd0, 0x4b, 0x3d, 0x63, 0x9e, 0x1d, 0x6c, 0xcc, 0xb4, + 0x35, 0x1b, 0xb1, 0x62, 0x08, 0x12, 0xa2, 0x8d, 0xf7, 0xa3, 0x50, 0xf4, 0x13, 0xd2, 0x96, 0x66, + 0x68, 0x0b, 0x06, 0xa3, 0x3e, 0x63, 0x99, 0x9f, 0x90, 0x31, 0x7e, 0x97, 0x28, 0x3d, 0xcc, 0xc9, + 0xba, 0xdb, 0x30, 0xb2, 0x10, 0xb6, 0xba, 0xed, 0x60, 0xb0, 0x48, 0x99, 0x64, 0xb7, 0x43, 0xb2, + 0x67, 0x24, 0x13, 0xff, 0x59, 0x89, 0x34, 0x1c, 0x0d, 0xe5, 0x1b, 0x8e, 0xdc, 0x7f, 0xe9, 0x00, + 0xdd, 0x55, 0x75, 0x5f, 0x78, 0x12, 0x39, 0x3a, 0x4e, 0xf0, 0x21, 0x1d, 0xdd, 0xad, 0xbd, 0x99, + 0x09, 0x55, 0x51, 0xc3, 0xff, 0x21, 0x18, 0x89, 0x99, 0x4a, 0x2e, 0xfa, 0xb0, 0x24, 0xe5, 0x67, + 0xae, 0xa8, 0xdf, 0xda, 0x9b, 0x19, 0x28, 0x6c, 0x73, 0x56, 0xe1, 0x16, 0x4e, 0x4f, 0x81, 0x95, + 0x0a, 0x7c, 0x6d, 0x12, 0xc7, 0x5e, 0x43, 0x6a, 0x78, 0x4a, 0xe0, 0x5b, 0xe5, 0x60, 0x2c, 0xcb, + 0xdd, 0x2f, 0x39, 0x30, 0xa1, 0x0e, 0x2f, 0x2a, 0xbe, 0xa3, 0x2b, 0xfa, 0x31, 0xc7, 0x57, 0xca, + 0x43, 0x7d, 0x38, 0x8e, 0x38, 0xc8, 0xf7, 0x3f, 0x05, 0xdf, 0x05, 0xe3, 0x75, 0xd2, 0x21, 0x41, + 0x9d, 0x04, 0x35, 0xaa, 0x7e, 0xd3, 0x15, 0x52, 0x9a, 0x9f, 0xa2, 0xfa, 0xe6, 0xa2, 0x06, 0xc7, + 0x46, 0x2d, 0xf7, 0x1b, 0x0e, 0xdc, 0xaf, 0xd0, 0x55, 0x49, 0x82, 0x49, 0x12, 0xed, 0xaa, 0x30, + 0xcd, 0x83, 0x9d, 0x56, 0xd7, 0xa8, 0xfc, 0x9b, 0x44, 0x9c, 0xf8, 0x9d, 0x1d, 0x57, 0x65, 0x2e, + 0x2d, 0x33, 0x24, 0x58, 0x62, 0x73, 0x7f, 0x75, 0x08, 0x4e, 0xea, 0x9d, 0x54, 0x0c, 0xe6, 0x97, + 0x1c, 0x00, 0x35, 0x03, 0xf4, 0x40, 0x1e, 0xb2, 0xe3, 0xbb, 0x32, 0xbe, 0x54, 0xca, 0x82, 0x14, + 0x38, 0xc6, 0x1a, 0x59, 0xf4, 0x02, 0x8c, 0xef, 0xd0, 0x4d, 0x41, 0x56, 0xa9, 0xb8, 0x10, 0x57, + 0x86, 0x58, 0x37, 0x66, 0xf2, 0x3e, 0xe6, 0xf3, 0x69, 0xbd, 0xd4, 0x1c, 0xa0, 0x01, 0x63, 0x6c, + 0xa0, 0xa2, 0x9a, 0xce, 0x44, 0xa4, 0x7f, 0x12, 0x61, 0x13, 0xff, 0xa0, 0xc5, 0x31, 0x66, 0xbf, + 0xfa, 0xfc, 0xf1, 0x9b, 0x7b, 0x33, 0x13, 0x06, 0x08, 0x9b, 0x9d, 0x70, 0x5f, 0x00, 0x36, 0x17, + 0x7e, 0xd0, 0x25, 0x6b, 0x01, 0x7a, 0x44, 0xda, 0xe8, 0xb8, 0x5f, 0x45, 0x71, 0x0e, 0xdd, 0x4e, + 0x47, 0x75, 0xd9, 0x2d, 0xcf, 0x6f, 0xb1, 0xf0, 0x45, 0x5a, 0x4b, 0xe9, 0xb2, 0x4b, 0x0c, 0x8a, + 0x45, 0xa9, 0x3b, 0x0b, 0xa3, 0x0b, 0x74, 0xec, 0x24, 0xa2, 0x78, 0xf5, 0xa8, 0xe3, 0x09, 0x23, + 0xea, 0x58, 0x46, 0x17, 0x6f, 0xc0, 0xa9, 0x85, 0x88, 0x78, 0x09, 0xa9, 0x3e, 0x3d, 0xdf, 0xad, + 0x6d, 0x93, 0x84, 0x87, 0x76, 0xc5, 0xe8, 0xbd, 0x30, 0x11, 0xb2, 0x23, 0xe3, 0x72, 0x58, 0xdb, + 0xf6, 0x83, 0x86, 0x30, 0xb9, 0x9e, 0x12, 0x58, 0x26, 0xd6, 0xf4, 0x42, 0x6c, 0xd6, 0x75, 0xff, + 0x43, 0x01, 0xc6, 0x17, 0xa2, 0x30, 0x90, 0x6c, 0xf1, 0x08, 0x8e, 0xb2, 0xc4, 0x38, 0xca, 0x2c, + 0xb8, 0x3b, 0xf5, 0xfe, 0xf7, 0x3b, 0xce, 0xd0, 0xeb, 0x8a, 0x45, 0x0e, 0xd9, 0x52, 0x41, 0x0c, + 0xba, 0x0c, 0x77, 0xfa, 0xb1, 0x4d, 0x06, 0xea, 0xfe, 0x47, 0x07, 0xa6, 0xf4, 0xea, 0x47, 0x70, + 0x82, 0xc6, 0xe6, 0x09, 0x7a, 0xc5, 0xee, 0x78, 0xfb, 0x1c, 0x9b, 0xff, 0x6c, 0xd4, 0x1c, 0x27, + 0xf3, 0x75, 0x7f, 0xc5, 0x81, 0xf1, 0xeb, 0x1a, 0x40, 0x0c, 0xd6, 0xb6, 0x10, 0xf3, 0x0e, 0xc9, + 0x66, 0x74, 0xe8, 0xad, 0xcc, 0x6f, 0x6c, 0xf4, 0x84, 0xf2, 0xfd, 0xb8, 0xd6, 0x24, 0xf5, 0x6e, + 0x4b, 0x1e, 0xdf, 0x6a, 0x4a, 0xab, 0x02, 0x8e, 0x55, 0x0d, 0xf4, 0x12, 0x1c, 0xaf, 0x85, 0x41, + 0xad, 0x1b, 0x45, 0x24, 0xa8, 0xed, 0xae, 0xb3, 0x3b, 0x12, 0xe2, 0x40, 0x9c, 0x15, 0xcd, 0x8e, + 0x2f, 0x64, 0x2b, 0xdc, 0xca, 0x03, 0xe2, 0x5e, 0x44, 0xdc, 0x59, 0x10, 0xd3, 0x23, 0x4b, 0x28, + 0x5c, 0x9a, 0xb3, 0x80, 0x81, 0xb1, 0x2c, 0x47, 0x57, 0xe1, 0x4c, 0x9c, 0x78, 0x51, 0xe2, 0x07, + 0x8d, 0x45, 0xe2, 0xd5, 0x5b, 0x7e, 0x40, 0x55, 0x89, 0x30, 0xa8, 0x73, 0x57, 0xe2, 0xd0, 0xfc, + 0x03, 0x37, 0xf7, 0x66, 0xce, 0x54, 0xf3, 0xab, 0xe0, 0x7e, 0x6d, 0xd1, 0x87, 0x60, 0x5a, 0xb8, + 0x23, 0xb6, 0xba, 0xad, 0x67, 0xc3, 0xcd, 0xf8, 0xa2, 0x1f, 0x53, 0x3d, 0xfe, 0xb2, 0xdf, 0xf6, + 0x13, 0xe6, 0x30, 0x2c, 0xce, 0x9f, 0xbd, 0xb9, 0x37, 0x33, 0x5d, 0xed, 0x5b, 0x0b, 0xef, 0x83, + 0x01, 0x61, 0x38, 0xcd, 0x99, 0x5f, 0x0f, 0xee, 0x51, 0x86, 0x7b, 0xfa, 0xe6, 0xde, 0xcc, 0xe9, + 0xa5, 0xdc, 0x1a, 0xb8, 0x4f, 0x4b, 0xfa, 0x05, 0x13, 0xbf, 0x4d, 0x5e, 0x0d, 0x03, 0xc2, 0x02, + 0x55, 0xb4, 0x2f, 0xb8, 0x21, 0xe0, 0x58, 0xd5, 0x40, 0x2f, 0xa7, 0x2b, 0x91, 0x6e, 0x17, 0x11, + 0x70, 0x72, 0x70, 0x0e, 0xc7, 0x54, 0x93, 0x6b, 0x1a, 0x26, 0x16, 0x49, 0x69, 0xe0, 0x46, 0x9f, + 0x70, 0x60, 0x3c, 0x4e, 0x42, 0x75, 0xaf, 0x41, 0x44, 0x9c, 0x58, 0x58, 0xf6, 0x55, 0x0d, 0x2b, + 0x17, 0x7c, 0x74, 0x08, 0x36, 0xa8, 0xa2, 0x9f, 0x83, 0x92, 0x5c, 0xc0, 0x71, 0xa5, 0xcc, 0x64, + 0x25, 0xa6, 0xc6, 0xc9, 0xf5, 0x1d, 0xe3, 0xb4, 0xdc, 0xfd, 0xd1, 0x10, 0xa0, 0x5e, 0xb6, 0x86, + 0x56, 0x60, 0xc4, 0xab, 0x25, 0xfe, 0x8e, 0x8c, 0x26, 0x7c, 0x24, 0xef, 0xc8, 0xe7, 0xd3, 0x83, + 0xc9, 0x16, 0xa1, 0xab, 0x9a, 0xa4, 0xbc, 0x70, 0x8e, 0x35, 0xc5, 0x02, 0x05, 0x0a, 0xe1, 0x78, + 0xcb, 0x8b, 0x13, 0x49, 0xbf, 0x4e, 0x3f, 0x93, 0x38, 0x0c, 0x7e, 0x76, 0xb0, 0x0f, 0x41, 0x5b, + 0xcc, 0x9f, 0xa2, 0xbb, 0xed, 0x72, 0x16, 0x11, 0xee, 0xc5, 0x8d, 0x3e, 0xc6, 0x64, 0x27, 0x2e, + 0xd8, 0x4a, 0xa1, 0x65, 0xc5, 0x8a, 0x5c, 0xc1, 0x71, 0x1a, 0x72, 0x93, 0x20, 0x83, 0x35, 0x92, + 0xe8, 0x1c, 0x94, 0xd8, 0xae, 0x20, 0x75, 0xc2, 0xf7, 0xf6, 0x50, 0x2a, 0xe2, 0x56, 0x65, 0x01, + 0x4e, 0xeb, 0x68, 0x32, 0x04, 0xdf, 0xce, 0x7d, 0x64, 0x08, 0xf4, 0x0c, 0x14, 0x3b, 0x4d, 0x2f, + 0x96, 0x11, 0xea, 0xae, 0xe4, 0xc9, 0xeb, 0x14, 0xc8, 0x18, 0x8f, 0xf6, 0x2d, 0x19, 0x10, 0xf3, + 0x06, 0xee, 0xbf, 0x02, 0x18, 0x5d, 0x9c, 0x5b, 0xde, 0xf0, 0xe2, 0xed, 0x01, 0x34, 0x1c, 0xba, + 0xc9, 0x84, 0x28, 0x9a, 0x65, 0x93, 0x52, 0x44, 0xc5, 0xaa, 0x06, 0x0a, 0x60, 0xc4, 0x0f, 0x28, + 0x5f, 0xa9, 0x4c, 0xda, 0xf2, 0x22, 0x28, 0x6d, 0x8d, 0x99, 0x79, 0x2e, 0x31, 0xec, 0x58, 0x50, + 0x41, 0xaf, 0x43, 0xc9, 0x93, 0x17, 0x84, 0xc4, 0xe9, 0xbe, 0x62, 0xc3, 0x3c, 0x2e, 0x50, 0xea, + 0x01, 0x4a, 0x02, 0x84, 0x53, 0x82, 0xe8, 0xe3, 0x0e, 0x94, 0xe5, 0xd0, 0x31, 0xd9, 0x12, 0x9e, + 0xeb, 0x55, 0x7b, 0x63, 0xc6, 0x64, 0x8b, 0x47, 0xaf, 0x68, 0x00, 0xac, 0x93, 0xec, 0xd1, 0x88, + 0x8a, 0x83, 0x68, 0x44, 0xe8, 0x3a, 0x94, 0xae, 0xfb, 0x49, 0x93, 0x9d, 0xdf, 0xc2, 0x63, 0xb6, + 0x74, 0xf7, 0xbd, 0xa6, 0xe8, 0xd2, 0x19, 0xbb, 0x26, 0x09, 0xe0, 0x94, 0x16, 0xdd, 0x0e, 0xf4, + 0x07, 0xbb, 0x60, 0xc5, 0x38, 0x7f, 0xc9, 0x6c, 0xc0, 0x0a, 0x70, 0x5a, 0x87, 0x4e, 0xf1, 0x38, + 0xfd, 0x55, 0x25, 0xaf, 0x74, 0x29, 0x6b, 0x11, 0x11, 0x89, 0x16, 0xd6, 0x95, 0xc4, 0xc8, 0x27, + 0xeb, 0x9a, 0x46, 0x03, 0x1b, 0x14, 0xe9, 0x1e, 0xb9, 0xde, 0x24, 0x81, 0xb8, 0x31, 0xa1, 0xf6, + 0xc8, 0xb5, 0x26, 0x09, 0x30, 0x2b, 0x41, 0xaf, 0x73, 0x0d, 0x8d, 0xab, 0x0a, 0x82, 0xd7, 0x5f, + 0xb6, 0xa3, 0xbd, 0x70, 0x9c, 0xfc, 0xd2, 0x42, 0xfa, 0x1b, 0x6b, 0xf4, 0x28, 0xc7, 0x08, 0x83, + 0x0b, 0x37, 0xfc, 0x44, 0x5c, 0xb5, 0x50, 0x1c, 0x63, 0x8d, 0x41, 0xb1, 0x28, 0xe5, 0x91, 0x19, + 0x74, 0x11, 0xc4, 0xec, 0x5e, 0x45, 0x49, 0x8f, 0xcc, 0x60, 0x60, 0x2c, 0xcb, 0xd1, 0xdf, 0x77, + 0xa0, 0xd8, 0x0c, 0xc3, 0xed, 0xb8, 0x32, 0xc1, 0x16, 0x87, 0x05, 0x89, 0x59, 0x70, 0x9c, 0xd9, + 0x8b, 0x14, 0xad, 0x79, 0x79, 0xac, 0xc8, 0x60, 0xb7, 0xf6, 0x66, 0x26, 0x2f, 0xfb, 0x5b, 0xa4, + 0xb6, 0x5b, 0x6b, 0x11, 0x06, 0x79, 0xf3, 0x6d, 0x0d, 0x72, 0x61, 0x87, 0x04, 0x09, 0xe6, 0xbd, + 0x9a, 0xfe, 0xac, 0x03, 0x90, 0x22, 0xca, 0x71, 0x81, 0x12, 0x33, 0x68, 0xc0, 0x82, 0xba, 0x6c, + 0x74, 0x4d, 0xf7, 0xa9, 0xfe, 0x6b, 0x07, 0xca, 0x74, 0x70, 0x92, 0x05, 0x3e, 0x06, 0x23, 0x89, + 0x17, 0x35, 0x88, 0x74, 0x03, 0xa8, 0xcf, 0xb1, 0xc1, 0xa0, 0x58, 0x94, 0xa2, 0x00, 0x8a, 0x89, + 0x17, 0x6f, 0x4b, 0x21, 0xfd, 0x92, 0xb5, 0x29, 0x4e, 0xe5, 0x73, 0xfa, 0x2b, 0xc6, 0x9c, 0x0c, + 0x7a, 0x1c, 0xc6, 0xe8, 0xd1, 0xb1, 0xe4, 0xc5, 0x32, 0x32, 0x67, 0x9c, 0x32, 0xf1, 0x25, 0x01, + 0xc3, 0xaa, 0xd4, 0xfd, 0xf5, 0x02, 0x0c, 0x2f, 0x72, 0x75, 0x6d, 0x24, 0x0e, 0xbb, 0x51, 0x8d, + 0x08, 0xb1, 0xdd, 0xc2, 0x9a, 0xa6, 0x78, 0xab, 0x0c, 0xa7, 0xa6, 0x30, 0xb1, 0xdf, 0x58, 0xd0, + 0x42, 0x5f, 0x74, 0x60, 0x32, 0x89, 0xbc, 0x20, 0xde, 0x62, 0x0e, 0x17, 0x3f, 0x0c, 0xc4, 0x14, + 0x59, 0x58, 0x85, 0x1b, 0x06, 0xde, 0x6a, 0x42, 0x3a, 0xa9, 0xdf, 0xc7, 0x2c, 0xc3, 0x99, 0x3e, + 0xb8, 0xbf, 0xe1, 0x00, 0xa4, 0xbd, 0x47, 0x9f, 0x71, 0x60, 0xc2, 0xd3, 0x23, 0x42, 0xc5, 0x1c, + 0xad, 0xd9, 0xf3, 0xce, 0x32, 0xb4, 0xdc, 0x52, 0x61, 0x80, 0xb0, 0x49, 0xd8, 0x7d, 0x37, 0x14, + 0xd9, 0xee, 0x60, 0x2a, 0x8d, 0xb0, 0x6c, 0x67, 0x4d, 0x59, 0xd2, 0xe2, 0x8d, 0x55, 0x0d, 0xf7, + 0x25, 0x98, 0xbc, 0x70, 0x83, 0xd4, 0xba, 0x49, 0x18, 0x71, 0xbb, 0x7e, 0x9f, 0x1b, 0x40, 0xce, + 0x1d, 0xdd, 0x00, 0xfa, 0xb6, 0x03, 0x65, 0x2d, 0x3c, 0x90, 0x9e, 0xd4, 0x8d, 0x85, 0x2a, 0x37, + 0x5f, 0x88, 0xa9, 0x5a, 0xb1, 0x12, 0x80, 0xc8, 0x51, 0xa6, 0xc7, 0x88, 0x02, 0xe1, 0x94, 0xe0, + 0x6d, 0xc2, 0xf7, 0xdc, 0x3f, 0x70, 0xe0, 0x54, 0x6e, 0x2c, 0xe3, 0x3d, 0xee, 0xb6, 0xe1, 0x42, + 0x2f, 0x0c, 0xe0, 0x42, 0xff, 0x1d, 0x07, 0x52, 0x4c, 0x94, 0x15, 0x6d, 0xa6, 0x3d, 0xd7, 0x58, + 0x91, 0xa0, 0x24, 0x4a, 0xd1, 0xeb, 0x70, 0xc6, 0xfc, 0x82, 0x77, 0xe8, 0x4d, 0xe1, 0xaa, 0x67, + 0x3e, 0x26, 0xdc, 0x8f, 0x84, 0xfb, 0x55, 0x07, 0x8a, 0xcb, 0x5e, 0xb7, 0x41, 0x06, 0x32, 0x86, + 0x51, 0x3e, 0x16, 0x11, 0xaf, 0x95, 0x48, 0xd5, 0x41, 0xf0, 0x31, 0x2c, 0x60, 0x58, 0x95, 0xa2, + 0x39, 0x28, 0x85, 0x1d, 0x62, 0x78, 0x00, 0x1f, 0x91, 0xb3, 0xb7, 0x26, 0x0b, 0xe8, 0xb1, 0xc3, + 0xa8, 0x2b, 0x08, 0x4e, 0x5b, 0xb9, 0xdf, 0x2f, 0x42, 0x59, 0xbb, 0xf5, 0x42, 0x65, 0x81, 0x88, + 0x74, 0xc2, 0xac, 0xbc, 0x4c, 0x17, 0x0c, 0x66, 0x25, 0x74, 0x0f, 0x46, 0x64, 0xc7, 0x8f, 0x39, + 0xdb, 0x32, 0xf6, 0x20, 0x16, 0x70, 0xac, 0x6a, 0xa0, 0x19, 0x28, 0xd6, 0x49, 0x27, 0x69, 0xb2, + 0xee, 0x0d, 0xf3, 0xd0, 0xbf, 0x45, 0x0a, 0xc0, 0x1c, 0x4e, 0x2b, 0x6c, 0x91, 0xa4, 0xd6, 0x64, + 0x76, 0x5f, 0x11, 0x1b, 0xb8, 0x44, 0x01, 0x98, 0xc3, 0x73, 0x7c, 0x94, 0xc5, 0xc3, 0xf7, 0x51, + 0x8e, 0x58, 0xf6, 0x51, 0xa2, 0x0e, 0x9c, 0x88, 0xe3, 0xe6, 0x7a, 0xe4, 0xef, 0x78, 0x09, 0x49, + 0x57, 0xdf, 0xe8, 0x41, 0xe8, 0x9c, 0x61, 0xf7, 0xd0, 0xab, 0x17, 0xb3, 0x58, 0x70, 0x1e, 0x6a, + 0x54, 0x85, 0x53, 0x7e, 0x10, 0x93, 0x5a, 0x37, 0x22, 0x97, 0x1a, 0x41, 0x18, 0x91, 0x8b, 0x61, + 0x4c, 0xd1, 0x89, 0x5b, 0xb4, 0x2a, 0x5a, 0xf6, 0x52, 0x5e, 0x25, 0x9c, 0xdf, 0x16, 0x2d, 0xc3, + 0xf1, 0xba, 0x1f, 0x7b, 0x9b, 0x2d, 0x52, 0xed, 0x6e, 0xb6, 0x43, 0xae, 0x78, 0x97, 0x18, 0xc2, + 0xfb, 0xa5, 0x95, 0x68, 0x31, 0x5b, 0x01, 0xf7, 0xb6, 0x41, 0xcf, 0xc0, 0x78, 0xec, 0x07, 0x8d, + 0x16, 0x99, 0x8f, 0xbc, 0xa0, 0xd6, 0x14, 0xd7, 0x6f, 0x95, 0x35, 0xbd, 0xaa, 0x95, 0x61, 0xa3, + 0x26, 0xdb, 0xf3, 0xbc, 0x4d, 0x46, 0x1a, 0x14, 0xb5, 0x45, 0xa9, 0xfb, 0x03, 0x07, 0xc6, 0xf5, + 0x48, 0x75, 0x2a, 0x69, 0x43, 0x73, 0x71, 0xa9, 0xca, 0xcf, 0x02, 0x7b, 0x27, 0xfe, 0x45, 0x85, + 0x33, 0x55, 0x96, 0x53, 0x18, 0xd6, 0x68, 0x0e, 0x70, 0xef, 0xfc, 0x11, 0x28, 0x6e, 0x85, 0x54, + 0x20, 0x19, 0x32, 0xcd, 0xf0, 0x4b, 0x14, 0x88, 0x79, 0x99, 0xfb, 0x3f, 0x1c, 0x38, 0x9d, 0x1f, + 0x84, 0xff, 0xd3, 0x30, 0xc8, 0xf3, 0x00, 0x74, 0x28, 0x06, 0x53, 0xd7, 0x32, 0x4f, 0xc8, 0x12, + 0xac, 0xd5, 0x1a, 0x6c, 0xd8, 0x7f, 0x46, 0x85, 0xe2, 0x94, 0xce, 0xe7, 0x1c, 0x98, 0xa0, 0x64, + 0x57, 0xa2, 0x4d, 0x63, 0xb4, 0x6b, 0x76, 0x46, 0xab, 0xd0, 0xa6, 0xde, 0x06, 0x03, 0x8c, 0x4d, + 0xe2, 0xe8, 0xe7, 0xa0, 0xe4, 0xd5, 0xeb, 0x11, 0x89, 0x63, 0xe5, 0xb7, 0x63, 0xb6, 0xa8, 0x39, + 0x09, 0xc4, 0x69, 0x39, 0x65, 0xa2, 0xcd, 0xfa, 0x56, 0x4c, 0xf9, 0x92, 0x60, 0xdc, 0x8a, 0x89, + 0x52, 0x22, 0x14, 0x8e, 0x55, 0x0d, 0xf7, 0x57, 0x86, 0xc1, 0xa4, 0x8d, 0xea, 0x70, 0x6c, 0x3b, + 0xda, 0x5c, 0x60, 0x61, 0x0f, 0x77, 0x12, 0x7e, 0xc0, 0xc2, 0x02, 0x56, 0x4c, 0x0c, 0x38, 0x8b, + 0x52, 0x50, 0x59, 0x21, 0xbb, 0x89, 0xb7, 0x79, 0xc7, 0xc1, 0x07, 0x2b, 0x26, 0x06, 0x9c, 0x45, + 0x89, 0xde, 0x0d, 0xe5, 0xed, 0x68, 0x53, 0xb2, 0xe8, 0x6c, 0x24, 0xcb, 0x4a, 0x5a, 0x84, 0xf5, + 0x7a, 0x74, 0x0a, 0xb7, 0xa3, 0x4d, 0x7a, 0x2a, 0xca, 0x3c, 0x0c, 0x6a, 0x0a, 0x57, 0x04, 0x1c, + 0xab, 0x1a, 0xa8, 0x03, 0x68, 0x5b, 0xce, 0x9e, 0x0a, 0xf2, 0x10, 0x27, 0xc9, 0xe0, 0x31, 0x22, + 0x2c, 0xba, 0x7e, 0xa5, 0x07, 0x0f, 0xce, 0xc1, 0x8d, 0x5e, 0x80, 0x33, 0xdb, 0xd1, 0xa6, 0x10, + 0x16, 0xd6, 0x23, 0x3f, 0xa8, 0xf9, 0x1d, 0x23, 0xe7, 0xc2, 0x8c, 0xe8, 0xee, 0x99, 0x95, 0xfc, + 0x6a, 0xb8, 0x5f, 0x7b, 0xf7, 0x77, 0x87, 0x81, 0xdd, 0x16, 0xa5, 0xbc, 0xb0, 0x4d, 0x92, 0x66, + 0x58, 0xcf, 0xca, 0x3f, 0xab, 0x0c, 0x8a, 0x45, 0xa9, 0x8c, 0x21, 0x2d, 0xf4, 0x89, 0x21, 0xbd, + 0x0e, 0xa3, 0x4d, 0xe2, 0xd5, 0x49, 0x24, 0x2d, 0x88, 0x97, 0xed, 0xdc, 0x6f, 0xbd, 0xc8, 0x90, + 0xa6, 0x6a, 0x38, 0xff, 0x1d, 0x63, 0x49, 0x0d, 0xbd, 0x07, 0x26, 0xa9, 0x20, 0x13, 0x76, 0x13, + 0x69, 0xe2, 0xe7, 0x16, 0x44, 0x76, 0xa2, 0x6e, 0x18, 0x25, 0x38, 0x53, 0x13, 0x2d, 0xc2, 0x94, + 0x30, 0xc7, 0x2b, 0xcb, 0xa4, 0x98, 0x58, 0x95, 0x0c, 0xa3, 0x9a, 0x29, 0xc7, 0x3d, 0x2d, 0x58, + 0x0c, 0x60, 0x58, 0xe7, 0x1e, 0x59, 0x3d, 0x06, 0x30, 0xac, 0xef, 0x62, 0x56, 0x82, 0x5e, 0x85, + 0x31, 0xfa, 0x77, 0x29, 0x0a, 0xdb, 0xc2, 0x36, 0xb3, 0x6e, 0x67, 0x76, 0x28, 0x0d, 0xa1, 0x29, + 0x32, 0x01, 0x6f, 0x5e, 0x50, 0xc1, 0x8a, 0x1e, 0xd5, 0x57, 0xe4, 0x39, 0x5c, 0xdd, 0xf6, 0x3b, + 0xcf, 0x93, 0xc8, 0xdf, 0xda, 0x65, 0x42, 0xc3, 0x58, 0xaa, 0xaf, 0x5c, 0xea, 0xa9, 0x81, 0x73, + 0x5a, 0xb9, 0x9f, 0x2b, 0xc0, 0xb8, 0x7e, 0xe9, 0xf8, 0x76, 0x81, 0xc5, 0x71, 0xba, 0x28, 0xb8, + 0x76, 0x7a, 0xd1, 0xc2, 0xb0, 0x6f, 0xb7, 0x20, 0x9a, 0x30, 0xec, 0x75, 0x85, 0xb4, 0x68, 0xc5, + 0x08, 0xc6, 0x46, 0xdc, 0x4d, 0x9a, 0xfc, 0x76, 0x1a, 0x0b, 0xf9, 0x65, 0x14, 0xdc, 0x4f, 0x0e, + 0xc1, 0x98, 0x2c, 0x44, 0x9f, 0x70, 0x00, 0xd2, 0xd0, 0x2b, 0xc1, 0x4a, 0xd7, 0x6d, 0xc4, 0xe5, + 0xe8, 0x51, 0x63, 0x9a, 0x2d, 0x5d, 0xc1, 0xb1, 0x46, 0x17, 0x25, 0x30, 0x12, 0xd2, 0xce, 0x9d, + 0xb7, 0x77, 0x71, 0x7e, 0x8d, 0x12, 0x3e, 0xcf, 0xa8, 0xa7, 0x66, 0x33, 0x06, 0xc3, 0x82, 0x16, + 0xd5, 0x00, 0x37, 0x65, 0x44, 0xa0, 0x3d, 0x13, 0xb3, 0x0a, 0x32, 0x4c, 0x15, 0x3a, 0x05, 0xc2, + 0x29, 0x41, 0xf7, 0x29, 0x98, 0x34, 0x37, 0x03, 0xd5, 0x08, 0x36, 0x77, 0x13, 0xc2, 0xed, 0x0d, + 0xe3, 0x5c, 0x23, 0x98, 0xa7, 0x00, 0xcc, 0xe1, 0xee, 0xf7, 0xa8, 0x1c, 0xa0, 0xd8, 0xcb, 0x00, + 0x26, 0xfe, 0x47, 0x74, 0x63, 0x59, 0x3f, 0xb5, 0xeb, 0x63, 0x50, 0x62, 0xff, 0xb0, 0x8d, 0x3e, + 0x64, 0xcb, 0x7f, 0x9f, 0xf6, 0x53, 0x6c, 0x75, 0x26, 0x13, 0x3c, 0x2f, 0x09, 0xe1, 0x94, 0xa6, + 0x1b, 0xc2, 0x54, 0xb6, 0x36, 0xfa, 0x20, 0x8c, 0xc7, 0xf2, 0x58, 0x4d, 0xaf, 0xd0, 0x0d, 0x78, + 0xfc, 0x72, 0xef, 0x99, 0xd6, 0x1c, 0x1b, 0xc8, 0xdc, 0x35, 0x18, 0xb1, 0x3a, 0x85, 0xee, 0xb7, + 0x1c, 0x28, 0x31, 0x07, 0x66, 0x23, 0xf2, 0xda, 0x69, 0x93, 0xa1, 0x7d, 0x66, 0x3d, 0x86, 0x51, + 0xae, 0xa3, 0xcb, 0xc0, 0x1f, 0x0b, 0x5c, 0x86, 0xe7, 0xbb, 0x4b, 0xb9, 0x0c, 0x37, 0x06, 0xc4, + 0x58, 0x52, 0x72, 0x3f, 0x55, 0x80, 0x91, 0x4b, 0x41, 0xa7, 0xfb, 0x97, 0x3e, 0xe7, 0xda, 0x2a, + 0x0c, 0x5f, 0x4a, 0x48, 0xdb, 0x4c, 0x0d, 0x38, 0x3e, 0xff, 0xa8, 0x9e, 0x16, 0xb0, 0x62, 0xa6, + 0x05, 0xc4, 0xde, 0x75, 0x19, 0x17, 0x27, 0x6c, 0xc4, 0xe9, 0x35, 0xc2, 0x27, 0xa1, 0x74, 0xd9, + 0xdb, 0x24, 0xad, 0x15, 0xb2, 0xcb, 0x2e, 0xfd, 0xf1, 0x18, 0x0d, 0x27, 0x55, 0xec, 0x8d, 0x78, + 0x8a, 0x45, 0x98, 0x64, 0xb5, 0xd5, 0x66, 0xa0, 0x9a, 0x03, 0x49, 0xf3, 0x2a, 0x39, 0xa6, 0xe6, + 0xa0, 0xe5, 0x54, 0xd2, 0x6a, 0xb9, 0xb3, 0x50, 0x4e, 0xb1, 0x0c, 0x40, 0xf5, 0x27, 0x05, 0x98, + 0x30, 0x4c, 0xdd, 0x86, 0x03, 0xd0, 0xb9, 0xad, 0x03, 0xd0, 0x70, 0xc8, 0x15, 0xee, 0xb5, 0x43, + 0x6e, 0xe8, 0xe8, 0x1d, 0x72, 0xe6, 0x47, 0x1a, 0x1e, 0xe8, 0x23, 0xb5, 0x60, 0xf8, 0xb2, 0x1f, + 0x6c, 0x0f, 0xc6, 0x67, 0xe2, 0x5a, 0xd8, 0xe9, 0xe1, 0x33, 0x55, 0x0a, 0xc4, 0xbc, 0x4c, 0x4a, + 0x2e, 0x43, 0xf9, 0x92, 0x8b, 0xfb, 0x09, 0x07, 0xc6, 0x57, 0xbd, 0xc0, 0xdf, 0x22, 0x71, 0xc2, + 0xd6, 0x55, 0x72, 0xa8, 0x97, 0xbf, 0xc6, 0xfb, 0xa4, 0x31, 0x78, 0xd3, 0x81, 0xe3, 0xab, 0xa4, + 0x1d, 0xfa, 0xaf, 0x7a, 0x69, 0xd8, 0x29, 0xed, 0x7b, 0xd3, 0x4f, 0x44, 0x94, 0x9d, 0xea, 0xfb, + 0x45, 0x3f, 0xc1, 0x14, 0x7e, 0x1b, 0x3b, 0x2e, 0xbb, 0x56, 0x41, 0x15, 0x34, 0xed, 0x42, 0x62, + 0x1a, 0x50, 0x2a, 0x0b, 0x70, 0x5a, 0xc7, 0xfd, 0x3d, 0x07, 0x46, 0x79, 0x27, 0x54, 0xa4, 0xae, + 0xd3, 0x07, 0x77, 0x13, 0x8a, 0xac, 0x9d, 0x58, 0xd5, 0xcb, 0x16, 0xc4, 0x1f, 0x8a, 0x8e, 0xef, + 0x41, 0xf6, 0x2f, 0xe6, 0x04, 0x98, 0xda, 0xe2, 0xdd, 0x98, 0x53, 0x11, 0xb7, 0xa9, 0xda, 0xc2, + 0xa0, 0x58, 0x94, 0xba, 0x5f, 0x1b, 0x82, 0x31, 0x95, 0xbd, 0x8b, 0xe5, 0x56, 0x08, 0x82, 0x30, + 0xf1, 0x78, 0xac, 0x03, 0xe7, 0xd5, 0x1f, 0xb4, 0x97, 0x3d, 0x6c, 0x76, 0x2e, 0xc5, 0xce, 0xfd, + 0x77, 0x4a, 0x09, 0xd5, 0x4a, 0xb0, 0xde, 0x09, 0xf4, 0x51, 0x18, 0x69, 0x51, 0xee, 0x23, 0x59, + 0xf7, 0xf3, 0x16, 0xbb, 0xc3, 0xd8, 0x9a, 0xe8, 0x89, 0x9a, 0x21, 0x0e, 0xc4, 0x82, 0xea, 0xf4, + 0xfb, 0x60, 0x2a, 0xdb, 0xeb, 0xdb, 0xdd, 0x97, 0x2c, 0xe9, 0xb7, 0x2d, 0xff, 0xba, 0xe0, 0x9e, + 0x07, 0x6f, 0xea, 0x3e, 0x07, 0xe5, 0x55, 0x92, 0x44, 0x7e, 0x8d, 0x21, 0xb8, 0xdd, 0xe2, 0x1a, + 0x48, 0x7e, 0xf8, 0x34, 0x5b, 0xac, 0x14, 0x67, 0x8c, 0x5e, 0x07, 0xe8, 0x44, 0x21, 0xd5, 0x5f, + 0x49, 0x57, 0x7e, 0x6c, 0x0b, 0xf2, 0xf0, 0xba, 0xc2, 0xc9, 0x5d, 0xce, 0xe9, 0x6f, 0xac, 0xd1, + 0x73, 0x5f, 0x84, 0xe2, 0x6a, 0x37, 0x21, 0x37, 0x06, 0xe0, 0x58, 0x07, 0x4d, 0x20, 0xe0, 0x7e, + 0x10, 0xc6, 0x19, 0xee, 0x8b, 0x61, 0x8b, 0x1e, 0xab, 0x74, 0x6a, 0xda, 0xf4, 0x77, 0xd6, 0x29, + 0xc0, 0x2a, 0x61, 0x5e, 0x46, 0xb7, 0x4c, 0x33, 0x6c, 0xd5, 0xd5, 0x65, 0x2a, 0xb5, 0x20, 0x2e, + 0x32, 0x28, 0x16, 0xa5, 0xee, 0x2f, 0x15, 0xa0, 0xcc, 0x1a, 0x0a, 0x76, 0xb3, 0x0b, 0xa3, 0x4d, + 0x4e, 0x47, 0xcc, 0xa1, 0x85, 0x10, 0x2d, 0xbd, 0xf7, 0x9a, 0x2e, 0xc7, 0x01, 0x58, 0xd2, 0xa3, + 0xa4, 0xaf, 0x7b, 0x7e, 0x42, 0x49, 0x17, 0x0e, 0x97, 0xf4, 0x35, 0x4e, 0x06, 0x4b, 0x7a, 0xee, + 0x2f, 0x02, 0xbb, 0xa4, 0xbc, 0xd4, 0xf2, 0x1a, 0x7c, 0xe6, 0xc2, 0x6d, 0x52, 0x17, 0x3c, 0x57, + 0x9b, 0x39, 0x0a, 0xc5, 0xa2, 0x94, 0x5f, 0xfc, 0x4c, 0x22, 0x5f, 0x05, 0x37, 0x6b, 0x17, 0x3f, + 0x19, 0x58, 0x86, 0xb2, 0xd7, 0xdd, 0x2f, 0x15, 0x00, 0x58, 0xae, 0x37, 0x7e, 0xb7, 0xf8, 0xe7, + 0x65, 0xa4, 0x92, 0xe9, 0x48, 0x54, 0x91, 0x4a, 0xec, 0xf6, 0xb4, 0x1e, 0xa1, 0xa4, 0xdf, 0x39, + 0x28, 0xec, 0x7f, 0xe7, 0x00, 0x75, 0x60, 0x34, 0xec, 0x26, 0x54, 0x56, 0x15, 0x87, 0xbd, 0x05, + 0x3f, 0xfa, 0x1a, 0x47, 0xc8, 0x03, 0xf5, 0xc5, 0x0f, 0x2c, 0xc9, 0xa0, 0x67, 0x60, 0xac, 0x13, + 0x85, 0x0d, 0x7a, 0x76, 0x8b, 0xe3, 0xfd, 0x41, 0x29, 0x0f, 0xad, 0x0b, 0xf8, 0x2d, 0xed, 0x7f, + 0xac, 0x6a, 0xbb, 0x7f, 0x3c, 0xc5, 0xe7, 0x45, 0xac, 0xbd, 0x69, 0x28, 0xf8, 0xd2, 0x32, 0x05, + 0x02, 0x45, 0xe1, 0xd2, 0x22, 0x2e, 0xf8, 0x75, 0xb5, 0xaf, 0x0a, 0x7d, 0xf7, 0xd5, 0xbb, 0xa1, + 0x5c, 0xf7, 0xe3, 0x4e, 0xcb, 0xdb, 0xbd, 0x92, 0x63, 0x16, 0x5c, 0x4c, 0x8b, 0xb0, 0x5e, 0x0f, + 0x3d, 0x29, 0x6e, 0x98, 0x0c, 0x1b, 0xa6, 0x20, 0x79, 0xc3, 0x24, 0xbd, 0xbb, 0xce, 0x2f, 0x97, + 0x64, 0xef, 0xf8, 0x17, 0x07, 0xbe, 0xe3, 0x9f, 0x95, 0xc4, 0x46, 0x8e, 0x5e, 0x12, 0x7b, 0x2f, + 0x4c, 0xc8, 0x9f, 0x4c, 0x3c, 0xaa, 0x9c, 0x64, 0xbd, 0x57, 0xe6, 0xea, 0x0d, 0xbd, 0x10, 0x9b, + 0x75, 0xd3, 0x45, 0x3b, 0x3a, 0xe8, 0xa2, 0x3d, 0x0f, 0xb0, 0x19, 0x76, 0x83, 0xba, 0x17, 0xed, + 0x5e, 0x5a, 0x14, 0xf1, 0xa8, 0x4a, 0xf0, 0x9b, 0x57, 0x25, 0x58, 0xab, 0xa5, 0x2f, 0xf4, 0xd2, + 0x6d, 0x16, 0xfa, 0x07, 0xa1, 0xc4, 0x62, 0x77, 0x49, 0x7d, 0x2e, 0x11, 0x21, 0x46, 0x07, 0x09, + 0x99, 0x4c, 0x83, 0x0e, 0x25, 0x12, 0x9c, 0xe2, 0x43, 0x1f, 0x02, 0xd8, 0xf2, 0x03, 0x3f, 0x6e, + 0x32, 0xec, 0xe5, 0x03, 0x63, 0x57, 0xe3, 0x5c, 0x52, 0x58, 0xb0, 0x86, 0x11, 0xbd, 0x04, 0xc7, + 0x49, 0x9c, 0xf8, 0x6d, 0x2f, 0x21, 0x75, 0x75, 0x27, 0xb3, 0xc2, 0x6c, 0x99, 0x2a, 0x7a, 0xfa, + 0x42, 0xb6, 0xc2, 0xad, 0x3c, 0x20, 0xee, 0x45, 0x64, 0xec, 0xc8, 0xe9, 0x83, 0xec, 0x48, 0xf4, + 0xbf, 0x1c, 0x38, 0x1e, 0x11, 0x1e, 0x77, 0x12, 0xab, 0x8e, 0x9d, 0x62, 0xec, 0xb8, 0x66, 0x23, + 0x8d, 0xba, 0xca, 0x97, 0x82, 0xb3, 0x54, 0xb8, 0xe0, 0x42, 0xe4, 0xe8, 0x7b, 0xca, 0x6f, 0xe5, + 0x01, 0xdf, 0x7c, 0x7b, 0x66, 0xa6, 0x37, 0x9d, 0xbf, 0x42, 0x4e, 0x77, 0xde, 0xdf, 0x7e, 0x7b, + 0x66, 0x4a, 0xfe, 0x4e, 0x27, 0xad, 0x67, 0x90, 0xf4, 0x58, 0xed, 0x84, 0xf5, 0x4b, 0xeb, 0x22, + 0x16, 0x4c, 0x1d, 0xab, 0xeb, 0x14, 0x88, 0x79, 0x19, 0x7a, 0x1c, 0xc6, 0xea, 0x1e, 0x69, 0x87, + 0x81, 0x4a, 0x88, 0xcb, 0xa4, 0xf9, 0x45, 0x01, 0xc3, 0xaa, 0x94, 0xea, 0x10, 0x81, 0x38, 0x52, + 0x2a, 0x0f, 0xd8, 0xd2, 0x21, 0xe4, 0x21, 0xc5, 0xa9, 0xca, 0x5f, 0x58, 0x51, 0x42, 0x2d, 0x18, + 0xf1, 0x99, 0xa1, 0x42, 0x84, 0x9b, 0x5a, 0xb0, 0x8e, 0x70, 0xc3, 0x87, 0x0c, 0x36, 0x65, 0xac, + 0x5f, 0xd0, 0xd0, 0xcf, 0x9a, 0x63, 0x47, 0x73, 0xd6, 0x3c, 0x0e, 0x63, 0xb5, 0xa6, 0xdf, 0xaa, + 0x47, 0x24, 0xa8, 0x4c, 0x31, 0x8d, 0x9d, 0xcd, 0xc4, 0x82, 0x80, 0x61, 0x55, 0x8a, 0xfe, 0x1a, + 0x4c, 0x84, 0xdd, 0x84, 0xb1, 0x16, 0x3a, 0x4f, 0x71, 0xe5, 0x38, 0xab, 0xce, 0x82, 0x87, 0xd6, + 0xf4, 0x02, 0x6c, 0xd6, 0xa3, 0x2c, 0xbe, 0x19, 0xc6, 0x2c, 0xb5, 0x0f, 0x63, 0xf1, 0xa7, 0x4d, + 0x16, 0x7f, 0x51, 0x2b, 0xc3, 0x46, 0x4d, 0xf4, 0x15, 0x07, 0x8e, 0xb7, 0xb3, 0x0a, 0x5c, 0xe5, + 0x0c, 0x9b, 0x99, 0xaa, 0x0d, 0x41, 0x3f, 0x83, 0x9a, 0x87, 0x7d, 0xf7, 0x80, 0x71, 0x6f, 0x27, + 0x58, 0x92, 0xad, 0x78, 0x37, 0xa8, 0x35, 0xa3, 0x30, 0x30, 0xbb, 0x77, 0xbf, 0xad, 0xab, 0x65, + 0x6c, 0x6f, 0xe7, 0x91, 0x98, 0xbf, 0xff, 0xe6, 0xde, 0xcc, 0xa9, 0xdc, 0x22, 0x9c, 0xdf, 0xa9, + 0xe9, 0x45, 0x38, 0x9d, 0xcf, 0x1f, 0x6e, 0xa7, 0x71, 0x0c, 0xe9, 0x1a, 0xc7, 0x12, 0xdc, 0xdf, + 0xb7, 0x53, 0xf4, 0xa4, 0x91, 0xd2, 0xa6, 0x63, 0x9e, 0x34, 0x3d, 0xd2, 0xe1, 0x24, 0x8c, 0xeb, + 0xef, 0x3f, 0xb8, 0xff, 0x77, 0x08, 0x20, 0xb5, 0x93, 0x23, 0x0f, 0x26, 0xb9, 0x4d, 0xfe, 0xd2, + 0xe2, 0x1d, 0x5f, 0x8a, 0x5f, 0x30, 0x10, 0xe0, 0x0c, 0x42, 0xd4, 0x06, 0xc4, 0x21, 0xfc, 0xf7, + 0x9d, 0xf8, 0x56, 0x99, 0x2b, 0x72, 0xa1, 0x07, 0x09, 0xce, 0x41, 0x4c, 0x47, 0x94, 0x84, 0xdb, + 0x24, 0xb8, 0x8a, 0x2f, 0xdf, 0x49, 0x66, 0x05, 0xee, 0x8d, 0x33, 0x10, 0xe0, 0x0c, 0x42, 0xe4, + 0xc2, 0x08, 0xb3, 0xcd, 0xc8, 0x00, 0x6d, 0xc6, 0x5e, 0x98, 0xa4, 0x11, 0x63, 0x51, 0x82, 0xbe, + 0xe4, 0xc0, 0xa4, 0x4c, 0x10, 0xc1, 0xac, 0xa1, 0x32, 0x34, 0xfb, 0xaa, 0x2d, 0x3f, 0xc7, 0x05, + 0x1d, 0x7b, 0x1a, 0xf8, 0x68, 0x80, 0x63, 0x9c, 0xe9, 0x84, 0xfb, 0x02, 0x9c, 0xc8, 0x69, 0x6e, + 0x45, 0xa3, 0xfd, 0xb6, 0x03, 0x65, 0x2d, 0x6f, 0x21, 0x7a, 0x1d, 0x4a, 0x61, 0xd5, 0x7a, 0xb4, + 0xdd, 0x5a, 0xb5, 0x27, 0xda, 0x4e, 0x81, 0x70, 0x4a, 0x70, 0x90, 0x20, 0xc1, 0xdc, 0x24, 0x8b, + 0xf7, 0xb8, 0xdb, 0x07, 0x0e, 0x12, 0xfc, 0x95, 0x22, 0xa4, 0x98, 0x0e, 0x98, 0xb8, 0x24, 0x0d, + 0x29, 0x2c, 0xec, 0x1b, 0x52, 0x58, 0x87, 0x63, 0x1e, 0xf3, 0x25, 0xdf, 0x61, 0xba, 0x12, 0x9e, + 0xb6, 0xd6, 0xc4, 0x80, 0xb3, 0x28, 0x29, 0x95, 0x38, 0x6d, 0xca, 0xa8, 0x0c, 0x1f, 0x98, 0x4a, + 0xd5, 0xc4, 0x80, 0xb3, 0x28, 0xd1, 0x4b, 0x50, 0xa9, 0xb1, 0xeb, 0xb7, 0x7c, 0x8c, 0x97, 0xb6, + 0xae, 0x84, 0xc9, 0x7a, 0x44, 0x62, 0x12, 0x24, 0x22, 0x31, 0xd9, 0xc3, 0x62, 0x16, 0x2a, 0x0b, + 0x7d, 0xea, 0xe1, 0xbe, 0x18, 0xa8, 0x9a, 0xc2, 0x9c, 0xd1, 0x7e, 0xb2, 0xcb, 0x98, 0x88, 0xf0, + 0xd2, 0x2b, 0x35, 0xa5, 0xaa, 0x17, 0x62, 0xb3, 0x2e, 0xfa, 0x65, 0x07, 0x26, 0x5a, 0xd2, 0x5c, + 0x8f, 0xbb, 0x2d, 0x99, 0x65, 0x13, 0x5b, 0x59, 0x7e, 0x97, 0x75, 0xcc, 0x5c, 0x96, 0x30, 0x40, + 0xd8, 0xa4, 0x9d, 0xcd, 0x1d, 0x33, 0x36, 0x60, 0xee, 0x98, 0xef, 0x39, 0x30, 0x95, 0xa5, 0x86, + 0xb6, 0xe1, 0xa1, 0xb6, 0x17, 0x6d, 0x5f, 0x0a, 0xb6, 0x22, 0x76, 0x11, 0x23, 0xe1, 0x8b, 0x61, + 0x6e, 0x2b, 0x21, 0xd1, 0xa2, 0xb7, 0xcb, 0xdd, 0x9f, 0x45, 0xf5, 0x4c, 0xd3, 0x43, 0xab, 0xfb, + 0x55, 0xc6, 0xfb, 0xe3, 0x42, 0x55, 0x38, 0x45, 0x2b, 0xb0, 0xd4, 0x72, 0x7e, 0x18, 0xa4, 0x44, + 0x0a, 0x8c, 0x88, 0x0a, 0x06, 0x5c, 0xcd, 0xab, 0x84, 0xf3, 0xdb, 0xba, 0x17, 0x60, 0x84, 0xdf, + 0x8b, 0xbb, 0x2b, 0xff, 0x91, 0xfb, 0x6f, 0x0b, 0x20, 0x05, 0xc3, 0xbf, 0xdc, 0xee, 0x38, 0x7a, + 0x88, 0x46, 0xcc, 0xa4, 0x24, 0xac, 0x1d, 0xec, 0x10, 0x15, 0x49, 0x1c, 0x45, 0x09, 0x95, 0x98, + 0xc9, 0x0d, 0x3f, 0x59, 0x08, 0xeb, 0xd2, 0xc6, 0xc1, 0x24, 0xe6, 0x0b, 0x02, 0x86, 0x55, 0xa9, + 0xfb, 0x09, 0x07, 0x26, 0xe8, 0x28, 0x5b, 0x2d, 0xd2, 0xaa, 0x26, 0xa4, 0x13, 0xa3, 0x18, 0x8a, + 0x31, 0xfd, 0xc7, 0x9e, 0x29, 0x30, 0xbd, 0x4b, 0x49, 0x3a, 0x9a, 0xb3, 0x86, 0x12, 0xc1, 0x9c, + 0x96, 0xfb, 0xd6, 0x10, 0x94, 0xd4, 0x64, 0x0f, 0x60, 0x4f, 0x3d, 0x9f, 0xe6, 0x57, 0xe5, 0x1c, + 0xb8, 0xa2, 0xe5, 0x56, 0xbd, 0x45, 0xa7, 0x2e, 0xd8, 0xe5, 0x89, 0x26, 0xd2, 0x44, 0xab, 0x4f, + 0x9a, 0xae, 0xe6, 0xd3, 0xfa, 0xfa, 0xd3, 0xea, 0x0b, 0x9f, 0xf3, 0x0d, 0xdd, 0xd3, 0x3f, 0x6c, + 0xeb, 0x34, 0x53, 0x6e, 0xcc, 0xfe, 0x2e, 0xfe, 0xcc, 0xd3, 0x3b, 0xc5, 0x81, 0x9e, 0xde, 0x79, + 0x02, 0x86, 0x49, 0xd0, 0x6d, 0x33, 0x51, 0xa9, 0xc4, 0x54, 0x84, 0xe1, 0x0b, 0x41, 0xb7, 0x6d, + 0x8e, 0x8c, 0x55, 0x41, 0xef, 0x83, 0x72, 0x9d, 0xc4, 0xb5, 0xc8, 0x67, 0xd9, 0x13, 0x84, 0x65, + 0xe7, 0x41, 0x66, 0x2e, 0x4b, 0xc1, 0x66, 0x43, 0xbd, 0x81, 0xfb, 0x2a, 0x8c, 0xac, 0xb7, 0xba, + 0x0d, 0x3f, 0x40, 0x1d, 0x18, 0xe1, 0xb9, 0x14, 0xc4, 0x69, 0x6f, 0x41, 0xef, 0xe4, 0xac, 0x42, + 0x8b, 0x42, 0xe1, 0x57, 0x6a, 0x05, 0x1d, 0xf7, 0xb7, 0x0b, 0x40, 0x55, 0xf3, 0xe5, 0x05, 0xf4, + 0x37, 0x7b, 0x5e, 0x9a, 0xf9, 0x99, 0x9c, 0x97, 0x66, 0x26, 0x58, 0xe5, 0x9c, 0x47, 0x66, 0x5a, + 0x30, 0xc1, 0x9c, 0x23, 0xf2, 0x0c, 0x14, 0x62, 0xf5, 0xd3, 0x03, 0xa6, 0x1f, 0xd0, 0x9b, 0x8a, + 0x13, 0x41, 0x07, 0x61, 0x13, 0x39, 0xda, 0x85, 0x13, 0x3c, 0x4d, 0xe7, 0x22, 0x69, 0x79, 0xbb, + 0x46, 0x3a, 0xae, 0x81, 0x53, 0x1e, 0xc8, 0x56, 0x3c, 0xc0, 0x7b, 0xb1, 0x17, 0x1d, 0xce, 0xa3, + 0xe1, 0xfe, 0xfe, 0x30, 0x68, 0xee, 0x8b, 0x01, 0x76, 0xd6, 0x2b, 0x19, 0x67, 0xd5, 0xaa, 0x15, + 0x67, 0x95, 0xf4, 0x00, 0x71, 0x6e, 0x65, 0xfa, 0xa7, 0x68, 0xa7, 0x9a, 0xa4, 0xd5, 0x11, 0xfb, + 0x52, 0x75, 0xea, 0x22, 0x69, 0x75, 0x30, 0x2b, 0x51, 0x97, 0x0f, 0x87, 0xfb, 0x5e, 0x3e, 0x6c, + 0x42, 0xb1, 0xe1, 0x75, 0x1b, 0x44, 0x44, 0x6b, 0x5a, 0xf0, 0x4b, 0xb2, 0xeb, 0x10, 0xdc, 0x2f, + 0xc9, 0xfe, 0xc5, 0x9c, 0x00, 0x65, 0x0c, 0x4d, 0x19, 0xbe, 0x22, 0x0c, 0xba, 0x16, 0x18, 0x83, + 0x8a, 0x88, 0xe1, 0x8c, 0x41, 0xfd, 0xc4, 0x29, 0x31, 0xd4, 0x81, 0xd1, 0x1a, 0x4f, 0x98, 0x22, + 0xe4, 0x9b, 0x4b, 0x36, 0x6e, 0x57, 0x32, 0x84, 0xdc, 0xf2, 0x22, 0x7e, 0x60, 0x49, 0xc6, 0x3d, + 0x07, 0x65, 0xed, 0x71, 0x0c, 0xfa, 0x19, 0x54, 0xae, 0x0e, 0xed, 0x33, 0x2c, 0x7a, 0x89, 0x87, + 0x59, 0x89, 0xfb, 0x8d, 0x61, 0x50, 0x76, 0x37, 0xfd, 0x2e, 0xa0, 0x57, 0xd3, 0x32, 0x0b, 0x19, + 0xf7, 0xe2, 0xc3, 0x00, 0x8b, 0x52, 0x2a, 0x03, 0xb6, 0x49, 0xd4, 0x50, 0x3a, 0xb7, 0x60, 0xed, + 0x4a, 0x06, 0x5c, 0xd5, 0x0b, 0xb1, 0x59, 0x97, 0x0a, 0xf0, 0x6d, 0xe1, 0xce, 0xcf, 0x06, 0x4b, + 0x4b, 0x37, 0x3f, 0x56, 0x35, 0x58, 0x6a, 0x82, 0xb6, 0xe6, 0xfd, 0x17, 0x41, 0x9b, 0x36, 0x9c, + 0x4f, 0x1a, 0x56, 0x1e, 0x5c, 0xa5, 0x43, 0xb0, 0x41, 0x15, 0x2d, 0xc3, 0xf1, 0x98, 0x24, 0x6b, + 0xd7, 0x03, 0x12, 0xa9, 0xb4, 0x01, 0x22, 0xf7, 0x85, 0xba, 0x29, 0x51, 0xcd, 0x56, 0xc0, 0xbd, + 0x6d, 0x72, 0xe3, 0x5c, 0x8b, 0x07, 0x8e, 0x73, 0x5d, 0x84, 0xa9, 0x2d, 0xcf, 0x6f, 0x75, 0x23, + 0xd2, 0x37, 0x5a, 0x76, 0x29, 0x53, 0x8e, 0x7b, 0x5a, 0xb0, 0xcb, 0x3a, 0x2d, 0xaf, 0x11, 0x57, + 0x46, 0xb5, 0xcb, 0x3a, 0x14, 0x80, 0x39, 0xdc, 0xfd, 0x4d, 0x07, 0x78, 0xd2, 0xa1, 0xb9, 0xad, + 0x2d, 0x3f, 0xf0, 0x93, 0x5d, 0xf4, 0x55, 0x07, 0xa6, 0x82, 0xb0, 0x4e, 0xe6, 0x82, 0xc4, 0x97, + 0x40, 0x7b, 0x99, 0xe0, 0x19, 0xad, 0x2b, 0x19, 0xf4, 0x3c, 0x83, 0x45, 0x16, 0x8a, 0x7b, 0xba, + 0xe1, 0x9e, 0x81, 0x53, 0xb9, 0x08, 0xdc, 0xef, 0x0d, 0x81, 0x99, 0x3b, 0x09, 0x3d, 0x07, 0xc5, + 0x16, 0xcb, 0xe6, 0xe1, 0xdc, 0x61, 0x52, 0x2c, 0x36, 0x57, 0x3c, 0xdd, 0x07, 0xc7, 0x84, 0x16, + 0xa1, 0xcc, 0x12, 0x32, 0x89, 0x5c, 0x2b, 0x05, 0x23, 0xcd, 0x41, 0x19, 0xa7, 0x45, 0xb7, 0xcc, + 0x9f, 0x58, 0x6f, 0x86, 0x5e, 0x83, 0xd1, 0x4d, 0x9e, 0x96, 0xd2, 0x9e, 0x7f, 0x50, 0xe4, 0xb9, + 0x64, 0x72, 0x94, 0x4c, 0x7a, 0x79, 0x2b, 0xfd, 0x17, 0x4b, 0x8a, 0x68, 0x17, 0xc6, 0x3c, 0xf9, + 0x4d, 0x87, 0x6d, 0x5d, 0xbe, 0x30, 0xd6, 0x8f, 0x88, 0xae, 0x91, 0xdf, 0x50, 0x91, 0xcb, 0x84, + 0x21, 0x15, 0x07, 0x0a, 0x43, 0xfa, 0x96, 0x03, 0x90, 0xbe, 0xe1, 0x81, 0x6e, 0xc0, 0x58, 0xfc, + 0xb4, 0x61, 0xd4, 0xb0, 0x71, 0xeb, 0x5e, 0x60, 0xd4, 0x6e, 0xa6, 0x0a, 0x08, 0x56, 0xd4, 0x6e, + 0x67, 0x88, 0xf9, 0x89, 0x03, 0x27, 0xf3, 0xde, 0x1a, 0xb9, 0x87, 0x3d, 0x3e, 0xa8, 0x0d, 0x46, + 0x34, 0x58, 0x8f, 0xc8, 0x96, 0x7f, 0x23, 0x27, 0x39, 0x32, 0x2f, 0xc0, 0x69, 0x1d, 0xf7, 0xcd, + 0x51, 0x50, 0x84, 0x0f, 0xc9, 0x66, 0xf3, 0x18, 0xd5, 0xaf, 0x1a, 0xe9, 0x65, 0x49, 0x55, 0x0f, + 0x33, 0x28, 0x16, 0xa5, 0x54, 0xc7, 0x92, 0x01, 0xf4, 0x82, 0x65, 0xb3, 0x55, 0x28, 0x03, 0xed, + 0xb1, 0x2a, 0xcd, 0xb3, 0x02, 0x15, 0x8f, 0xc4, 0x0a, 0x34, 0x62, 0xdf, 0x0a, 0xf4, 0x04, 0x8c, + 0x46, 0x61, 0x8b, 0xcc, 0xe1, 0x2b, 0x42, 0x73, 0x48, 0x03, 0x20, 0x38, 0x18, 0xcb, 0xf2, 0x3b, + 0xb4, 0x83, 0xa0, 0xdf, 0x71, 0xf6, 0x31, 0x34, 0x95, 0x6c, 0x9d, 0x09, 0xb9, 0x99, 0xe4, 0x98, + 0x1a, 0x74, 0x27, 0xd6, 0xab, 0xaf, 0x39, 0x70, 0x9c, 0x04, 0xb5, 0x68, 0x97, 0xe1, 0x11, 0xd8, + 0x84, 0x7f, 0xfa, 0xaa, 0x8d, 0xcd, 0x77, 0x21, 0x8b, 0x9c, 0xbb, 0x81, 0x7a, 0xc0, 0xb8, 0xb7, + 0x1b, 0x68, 0x0d, 0xc6, 0x6a, 0x9e, 0x58, 0x11, 0xe5, 0x83, 0xac, 0x08, 0xee, 0x65, 0x9b, 0x13, + 0x4b, 0x41, 0x21, 0x71, 0x7f, 0x54, 0x80, 0x13, 0x39, 0x5d, 0x62, 0x97, 0xad, 0xda, 0x74, 0x45, + 0x5e, 0xaa, 0x67, 0xf7, 0xe3, 0x8a, 0x80, 0x63, 0x55, 0x03, 0xad, 0xc3, 0xc9, 0xed, 0x76, 0x9c, + 0x62, 0x59, 0x08, 0x83, 0x84, 0xdc, 0x90, 0xbb, 0x53, 0xfa, 0xae, 0x4f, 0xae, 0xe4, 0xd4, 0xc1, + 0xb9, 0x2d, 0xa9, 0xf8, 0x42, 0x02, 0x6f, 0xb3, 0x45, 0xd2, 0x22, 0x71, 0x55, 0x50, 0x89, 0x2f, + 0x17, 0x32, 0xe5, 0xb8, 0xa7, 0x05, 0xfa, 0x8c, 0x03, 0x0f, 0xc4, 0x24, 0xda, 0x21, 0x51, 0xd5, + 0xaf, 0x93, 0x85, 0x6e, 0x9c, 0x84, 0x6d, 0x12, 0xdd, 0xa1, 0x69, 0x75, 0xe6, 0xe6, 0xde, 0xcc, + 0x03, 0xd5, 0xfe, 0xd8, 0xf0, 0x7e, 0xa4, 0xdc, 0xcf, 0x38, 0x30, 0x59, 0x65, 0x8a, 0xb7, 0x92, + 0xa5, 0x6d, 0xe7, 0x12, 0x7d, 0x4c, 0x25, 0xb7, 0xc8, 0x70, 0x45, 0x33, 0x1d, 0x85, 0xfb, 0x32, + 0x4c, 0x55, 0x49, 0xdb, 0xeb, 0x34, 0xd9, 0x3d, 0x5f, 0x1e, 0xbb, 0x75, 0x0e, 0x4a, 0xb1, 0x84, + 0x65, 0x9f, 0x0f, 0x52, 0x95, 0x71, 0x5a, 0x07, 0x3d, 0xca, 0xe3, 0xcc, 0xe4, 0x6d, 0xa1, 0x12, + 0xd7, 0x3a, 0x78, 0x70, 0x5a, 0x8c, 0x65, 0x99, 0xfb, 0x96, 0x03, 0xe3, 0x69, 0x7b, 0xb2, 0x85, + 0x1a, 0x70, 0xac, 0xa6, 0xdd, 0xb4, 0x4b, 0xef, 0x38, 0x0c, 0x7e, 0x29, 0x8f, 0xa7, 0x38, 0x36, + 0x91, 0xe0, 0x2c, 0xd6, 0x83, 0x87, 0xe9, 0x7d, 0xbe, 0x00, 0xc7, 0x54, 0x57, 0x85, 0x93, 0xf1, + 0x8d, 0x6c, 0x34, 0x1d, 0xb6, 0x91, 0xa6, 0xc7, 0x9c, 0xfb, 0x7d, 0x22, 0xea, 0xde, 0xc8, 0x46, + 0xd4, 0x1d, 0x2a, 0xf9, 0x1e, 0xbf, 0xe9, 0xb7, 0x0a, 0x30, 0xa6, 0x92, 0x06, 0x3d, 0x07, 0x45, + 0xa6, 0x4a, 0xde, 0x9d, 0x40, 0xcc, 0xd4, 0x52, 0xcc, 0x31, 0x51, 0x94, 0x2c, 0x62, 0xe7, 0x8e, + 0x13, 0xcf, 0x96, 0xb8, 0xf1, 0xd1, 0x8b, 0x12, 0xcc, 0x31, 0xa1, 0x15, 0x18, 0x22, 0x41, 0x5d, + 0x48, 0xc6, 0x07, 0x47, 0xc8, 0x1e, 0xfa, 0xba, 0x10, 0xd4, 0x31, 0xc5, 0xc2, 0x32, 0x97, 0x71, + 0x01, 0x28, 0xf3, 0xac, 0x8b, 0x90, 0x7e, 0x44, 0xa9, 0xfb, 0x7e, 0x30, 0x72, 0xd6, 0x89, 0x5c, + 0xf8, 0x42, 0xe9, 0xea, 0x7d, 0x8b, 0x4b, 0x68, 0x5b, 0x69, 0x1d, 0xf7, 0x97, 0x87, 0x60, 0xa4, + 0xda, 0xdd, 0xa4, 0x4a, 0xc2, 0x37, 0x1d, 0x38, 0x71, 0x3d, 0x93, 0xd6, 0x39, 0xdd, 0x24, 0x57, + 0xed, 0x59, 0x70, 0xf5, 0xb0, 0xb3, 0x07, 0xe4, 0xa3, 0xf7, 0x39, 0x85, 0x38, 0xaf, 0x3b, 0x46, + 0x66, 0xd5, 0xa1, 0x43, 0xc9, 0xac, 0x7a, 0xe3, 0x90, 0xef, 0x5d, 0x4c, 0xf4, 0xbb, 0x73, 0xe1, + 0xfe, 0x7e, 0x11, 0x80, 0x7f, 0x8d, 0xb5, 0x4e, 0x32, 0x88, 0x9d, 0xed, 0x19, 0x18, 0x6f, 0x90, + 0x80, 0x44, 0x32, 0xa8, 0x30, 0xf3, 0xe4, 0xd0, 0xb2, 0x56, 0x86, 0x8d, 0x9a, 0x4c, 0xa9, 0x09, + 0x92, 0x68, 0x97, 0x0b, 0xbe, 0xd9, 0xbb, 0x15, 0xaa, 0x04, 0x6b, 0xb5, 0xd0, 0xac, 0xe1, 0x32, + 0xe1, 0xde, 0xf7, 0xc9, 0x7d, 0x3c, 0x1c, 0xef, 0x83, 0x49, 0x33, 0x51, 0x89, 0x90, 0xf6, 0x94, + 0xb7, 0xdc, 0xcc, 0x6f, 0x82, 0x33, 0xb5, 0xe9, 0x2e, 0xa8, 0x47, 0xbb, 0xb8, 0x1b, 0x08, 0xb1, + 0x4f, 0xed, 0x82, 0x45, 0x06, 0xc5, 0xa2, 0x94, 0x65, 0x78, 0x60, 0x07, 0x20, 0x87, 0x8b, 0x2c, + 0x11, 0x69, 0x86, 0x07, 0xad, 0x0c, 0x1b, 0x35, 0x29, 0x05, 0x61, 0xa7, 0x04, 0x73, 0x9f, 0x65, + 0x8c, 0x8b, 0x1d, 0x98, 0x0c, 0x4d, 0xfb, 0x0a, 0x97, 0x81, 0xde, 0x35, 0xe0, 0xd2, 0x33, 0xda, + 0xf2, 0x28, 0x87, 0x8c, 0x39, 0x26, 0x83, 0x9f, 0xca, 0xbd, 0xfa, 0x15, 0x84, 0x71, 0x33, 0x26, + 0xb5, 0xef, 0x2d, 0x81, 0x75, 0x38, 0xd9, 0x09, 0xeb, 0xeb, 0x91, 0x1f, 0x46, 0x7e, 0xb2, 0xbb, + 0xd0, 0xf2, 0xe2, 0x98, 0x2d, 0x8c, 0x09, 0x53, 0x1e, 0x5a, 0xcf, 0xa9, 0x83, 0x73, 0x5b, 0x52, + 0x0d, 0xa5, 0x23, 0x80, 0x2c, 0x32, 0xac, 0xc8, 0x25, 0x3a, 0x59, 0x11, 0xab, 0x52, 0xf7, 0x04, + 0x1c, 0xaf, 0x76, 0x3b, 0x9d, 0x96, 0x4f, 0xea, 0xca, 0x25, 0xe1, 0xbe, 0x1f, 0x8e, 0x89, 0xbc, + 0xab, 0x4a, 0xfa, 0x38, 0x50, 0x96, 0x70, 0xf7, 0x3f, 0x0d, 0xc1, 0xb1, 0x4c, 0x1c, 0x0e, 0x7a, + 0x2d, 0x2b, 0x33, 0xd8, 0xc9, 0x07, 0xaa, 0x49, 0x0b, 0x22, 0xb9, 0x67, 0x9e, 0xfc, 0xd1, 0x94, + 0x41, 0xf4, 0xd6, 0x2e, 0xaf, 0xb0, 0x50, 0x73, 0x7e, 0xa4, 0x18, 0x91, 0xf8, 0x1f, 0x05, 0x50, + 0x64, 0xe5, 0x7d, 0x79, 0xdb, 0xe3, 0x64, 0xfb, 0x57, 0x41, 0x62, 0xac, 0x51, 0x44, 0x01, 0x8c, + 0xb2, 0x8e, 0x10, 0x79, 0x63, 0xd2, 0xda, 0x58, 0x99, 0xc8, 0xb6, 0xca, 0x71, 0x63, 0x49, 0xc4, + 0xfd, 0x74, 0x01, 0xf2, 0x83, 0xbd, 0xd0, 0x47, 0x7b, 0x3f, 0xf8, 0x73, 0x16, 0x27, 0x42, 0x44, + 0x9b, 0xf5, 0xff, 0xe6, 0x81, 0xf9, 0xcd, 0x57, 0x2d, 0xcd, 0x83, 0xa0, 0xdb, 0xf3, 0xe5, 0xdd, + 0xff, 0xe9, 0x40, 0x79, 0x63, 0xe3, 0xb2, 0x3a, 0xd7, 0x31, 0x9c, 0x8e, 0x79, 0x32, 0x02, 0xe6, + 0x13, 0x5f, 0x08, 0xdb, 0x1d, 0xee, 0x22, 0x17, 0xae, 0x7b, 0x96, 0xf2, 0xb7, 0x9a, 0x5b, 0x03, + 0xf7, 0x69, 0x89, 0x2e, 0xc1, 0x09, 0xbd, 0xa4, 0xaa, 0xbd, 0xb0, 0x58, 0x14, 0x09, 0x80, 0x7a, + 0x8b, 0x71, 0x5e, 0x9b, 0x2c, 0x2a, 0x61, 0xde, 0x65, 0xc7, 0x73, 0x0e, 0x2a, 0x51, 0x8c, 0xf3, + 0xda, 0xb8, 0x6b, 0x50, 0xde, 0xf0, 0x22, 0x35, 0xf0, 0x0f, 0xc0, 0x54, 0x2d, 0x6c, 0x4b, 0xb3, + 0xda, 0x65, 0xb2, 0x43, 0x5a, 0x62, 0xc8, 0xfc, 0x59, 0x93, 0x4c, 0x19, 0xee, 0xa9, 0xed, 0xfe, + 0xb7, 0xb3, 0xa0, 0x2e, 0x57, 0x0e, 0x70, 0xa2, 0x76, 0x54, 0x18, 0x6c, 0xd1, 0x72, 0x18, 0xac, + 0x3a, 0x5b, 0x32, 0xa1, 0xb0, 0x49, 0x1a, 0x0a, 0x3b, 0x62, 0x3b, 0x14, 0x56, 0x49, 0xd8, 0x3d, + 0xe1, 0xb0, 0x5f, 0x76, 0x60, 0x3c, 0x08, 0xeb, 0x44, 0xf9, 0x2e, 0x47, 0xd9, 0x0e, 0x7f, 0xc9, + 0xde, 0xad, 0x02, 0x1e, 0xd6, 0x29, 0xd0, 0xf3, 0x10, 0x6d, 0x75, 0x24, 0xeb, 0x45, 0xd8, 0xe8, + 0x07, 0x5a, 0xd2, 0x0c, 0xbd, 0xdc, 0x9f, 0xf2, 0x60, 0x9e, 0x7e, 0x76, 0x5b, 0xab, 0xed, 0x0d, + 0x4d, 0x4e, 0x2c, 0xd9, 0x32, 0x60, 0xca, 0x1b, 0x73, 0x9a, 0x5b, 0x48, 0x66, 0xad, 0x4e, 0xe5, + 0x47, 0x17, 0x46, 0x78, 0x2c, 0xb7, 0x48, 0x35, 0xc5, 0xbc, 0x95, 0x3c, 0xce, 0x1b, 0x8b, 0x12, + 0x94, 0xc8, 0xf8, 0x88, 0xb2, 0xad, 0x37, 0x28, 0x8c, 0xf8, 0x8b, 0xfc, 0x00, 0x09, 0xf4, 0xac, + 0xae, 0xf7, 0x8f, 0x0f, 0xa2, 0xf7, 0x4f, 0xf4, 0xd5, 0xf9, 0x3f, 0xe7, 0xc0, 0x78, 0x4d, 0x7b, + 0x13, 0xa2, 0xf2, 0xb8, 0xad, 0xb7, 0xaf, 0xf3, 0x9e, 0xee, 0xe0, 0x4e, 0x30, 0xe3, 0x0d, 0x0a, + 0x83, 0x3a, 0xcb, 0xaf, 0xc9, 0x8c, 0x1c, 0x4c, 0xd4, 0xb1, 0x92, 0x52, 0xc3, 0x34, 0x9a, 0xc8, + 0x38, 0x53, 0x0a, 0xc3, 0x82, 0x16, 0x7a, 0x1d, 0xc6, 0xe4, 0x75, 0x00, 0x11, 0x36, 0x8f, 0x6d, + 0x78, 0x25, 0x4c, 0xd7, 0xa7, 0x4c, 0xca, 0xc7, 0xa1, 0x58, 0x51, 0x44, 0x4d, 0x18, 0xaa, 0x7b, + 0x0d, 0x11, 0x40, 0xbf, 0x6a, 0x27, 0xe9, 0xa9, 0xa4, 0xc9, 0xf4, 0xd1, 0xc5, 0xb9, 0x65, 0x4c, + 0x49, 0xa0, 0x1b, 0x69, 0x52, 0xfd, 0x29, 0x6b, 0xa7, 0xaf, 0x29, 0x16, 0x72, 0x99, 0xa0, 0x27, + 0x47, 0x7f, 0x5d, 0x78, 0x8b, 0xff, 0x0a, 0x23, 0xbb, 0x64, 0x27, 0x6b, 0x2a, 0x4f, 0xd1, 0x92, + 0x7a, 0x9c, 0x29, 0x95, 0x66, 0x92, 0x74, 0x2a, 0x3f, 0x6b, 0x8b, 0x0a, 0x4b, 0x34, 0xc2, 0x9f, + 0x29, 0xdf, 0xd8, 0x58, 0xc7, 0x0c, 0x3b, 0x6a, 0xc1, 0x48, 0x87, 0x05, 0xbd, 0x54, 0x7e, 0xce, + 0xd6, 0xd9, 0xc2, 0x83, 0x68, 0xf8, 0xda, 0xe4, 0xff, 0x63, 0x41, 0x03, 0x5d, 0x80, 0x51, 0xfe, + 0x36, 0x0c, 0xbf, 0xc0, 0x50, 0x3e, 0x3f, 0xdd, 0xff, 0x85, 0x99, 0xf4, 0xa0, 0xe0, 0xbf, 0x63, + 0x2c, 0xdb, 0xa2, 0xcf, 0x3b, 0x30, 0x49, 0x39, 0x6a, 0xfa, 0x98, 0x4d, 0x05, 0xd9, 0xe2, 0x59, + 0x57, 0x63, 0x2a, 0x91, 0x48, 0x5e, 0xa3, 0xd4, 0xc2, 0x4b, 0x06, 0x39, 0x9c, 0x21, 0x8f, 0xde, + 0x80, 0xb1, 0xd8, 0xaf, 0x93, 0x9a, 0x17, 0xc5, 0x95, 0x13, 0x87, 0xd3, 0x95, 0xd4, 0x3f, 0x25, + 0x08, 0x61, 0x45, 0x12, 0xfd, 0x1a, 0x7b, 0x4d, 0x54, 0xbc, 0xfc, 0x5f, 0xe3, 0x6a, 0xcc, 0x49, + 0x5b, 0x7b, 0x5f, 0x7a, 0xe2, 0x24, 0x66, 0xe1, 0xb6, 0x31, 0xc9, 0xe1, 0x2c, 0x7d, 0xf4, 0xb7, + 0x1c, 0x38, 0xc5, 0xdf, 0x05, 0xc8, 0x3e, 0x64, 0x71, 0xea, 0x0e, 0xed, 0x51, 0xec, 0xe6, 0xc5, + 0x5c, 0x1e, 0x4a, 0x9c, 0x4f, 0x89, 0x65, 0xf1, 0x35, 0xdf, 0x1e, 0x3a, 0x6d, 0xd5, 0x4f, 0x3b, + 0xf8, 0x7b, 0x43, 0xe8, 0x29, 0x28, 0x77, 0xc4, 0x71, 0xe8, 0xc7, 0x6d, 0x76, 0x8f, 0x66, 0x88, + 0xdf, 0x70, 0x5c, 0x4f, 0xc1, 0x58, 0xaf, 0x63, 0xa4, 0x74, 0x7e, 0x62, 0xbf, 0x94, 0xce, 0xe8, + 0x2a, 0x94, 0x93, 0xb0, 0x25, 0xb2, 0x9a, 0xc6, 0x95, 0x0a, 0x5b, 0x81, 0x67, 0xf3, 0xf6, 0xd6, + 0x86, 0xaa, 0x96, 0x6a, 0xee, 0x29, 0x2c, 0xc6, 0x3a, 0x1e, 0x16, 0xbb, 0x2c, 0xde, 0x5b, 0x88, + 0x98, 0xca, 0x7e, 0x7f, 0x26, 0x76, 0x59, 0x2f, 0xc4, 0x66, 0x5d, 0xb4, 0x0c, 0xc7, 0x3b, 0x3d, + 0x3a, 0x3f, 0xbf, 0xbf, 0xa7, 0x42, 0x40, 0x7a, 0x15, 0xfe, 0xde, 0x36, 0x86, 0xb6, 0xff, 0xc0, + 0x7e, 0xda, 0x7e, 0x9f, 0x04, 0xc7, 0x0f, 0xde, 0x49, 0x82, 0x63, 0x54, 0x87, 0x07, 0xbd, 0x6e, + 0x12, 0xb2, 0x64, 0x3a, 0x66, 0x13, 0x1e, 0xc6, 0xfd, 0x30, 0x8f, 0x0c, 0xbf, 0xb9, 0x37, 0xf3, + 0xe0, 0xdc, 0x3e, 0xf5, 0xf0, 0xbe, 0x58, 0xd0, 0xab, 0x30, 0x46, 0x44, 0x92, 0xe6, 0xca, 0xcf, + 0xd8, 0x12, 0x12, 0xcc, 0xb4, 0xcf, 0x32, 0x42, 0x96, 0xc3, 0xb0, 0xa2, 0x87, 0x36, 0xa0, 0xdc, + 0x0c, 0xe3, 0x64, 0xae, 0xe5, 0x7b, 0x31, 0x89, 0x2b, 0x0f, 0xb1, 0x45, 0x93, 0x2b, 0x7b, 0x5d, + 0x94, 0xd5, 0xd2, 0x35, 0x73, 0x31, 0x6d, 0x89, 0x75, 0x34, 0x88, 0x30, 0x6f, 0x2d, 0x8b, 0x61, + 0x97, 0x8e, 0xaf, 0xb3, 0x6c, 0x60, 0x8f, 0xe5, 0x61, 0x5e, 0x0f, 0xeb, 0x55, 0xb3, 0xb6, 0x72, + 0xd7, 0xea, 0x40, 0x9c, 0xc5, 0x89, 0x9e, 0x81, 0xf1, 0x4e, 0x58, 0xaf, 0x76, 0x48, 0x6d, 0xdd, + 0x4b, 0x6a, 0xcd, 0xca, 0x8c, 0x69, 0x65, 0x5c, 0xd7, 0xca, 0xb0, 0x51, 0x13, 0x75, 0x60, 0xb4, + 0xcd, 0xb3, 0x2c, 0x54, 0x1e, 0xb1, 0xa5, 0xdb, 0x88, 0xb4, 0x0d, 0xc2, 0x86, 0xc0, 0x7f, 0x60, + 0x49, 0x06, 0xfd, 0x43, 0x07, 0x8e, 0x65, 0x6e, 0x86, 0x55, 0xde, 0x61, 0x4d, 0x64, 0x31, 0x11, + 0xcf, 0x3f, 0xc6, 0xa6, 0xcf, 0x04, 0xde, 0xea, 0x05, 0xe1, 0x6c, 0x8f, 0xf8, 0xbc, 0xb0, 0x54, + 0x29, 0x95, 0x47, 0xed, 0xcd, 0x0b, 0x43, 0x28, 0xe7, 0x85, 0xfd, 0xc0, 0x92, 0x0c, 0x7a, 0x02, + 0x46, 0x45, 0x56, 0xc3, 0xca, 0x63, 0xa6, 0xcb, 0x5d, 0x24, 0x3f, 0xc4, 0xb2, 0x7c, 0xfa, 0xfd, + 0x70, 0xbc, 0x47, 0x75, 0x3b, 0x50, 0xbe, 0x8e, 0xdf, 0x70, 0x40, 0xbf, 0x4a, 0x6e, 0xfd, 0x65, + 0x94, 0x67, 0x60, 0xbc, 0xc6, 0x9f, 0xa1, 0xe4, 0x97, 0xd1, 0x87, 0x4d, 0x7b, 0xef, 0x82, 0x56, + 0x86, 0x8d, 0x9a, 0xee, 0x45, 0x40, 0xbd, 0x69, 0xeb, 0xef, 0x28, 0x19, 0xd4, 0x3f, 0x76, 0x60, + 0xc2, 0x90, 0x19, 0xac, 0x3b, 0x55, 0x97, 0x00, 0xb5, 0xfd, 0x28, 0x0a, 0x23, 0xfd, 0xbd, 0x3f, + 0x91, 0x30, 0x82, 0x5d, 0xc9, 0x5b, 0xed, 0x29, 0xc5, 0x39, 0x2d, 0xdc, 0xdf, 0x1e, 0x86, 0x34, + 0x44, 0x5c, 0xe5, 0x05, 0x76, 0xfa, 0xe6, 0x05, 0x7e, 0x12, 0xc6, 0x5e, 0x8e, 0xc3, 0x60, 0x3d, + 0xcd, 0x1e, 0xac, 0xbe, 0xc5, 0xb3, 0xd5, 0xb5, 0x2b, 0xac, 0xa6, 0xaa, 0xc1, 0x6a, 0xbf, 0xb2, + 0xe4, 0xb7, 0x92, 0xde, 0xf4, 0xb2, 0xcf, 0x3e, 0xc7, 0xe1, 0x58, 0xd5, 0x60, 0x4f, 0xff, 0xed, + 0x10, 0xe5, 0x08, 0x48, 0x9f, 0xfe, 0xe3, 0x2f, 0x52, 0xb0, 0x32, 0x74, 0x0e, 0x4a, 0xca, 0x89, + 0x20, 0x3c, 0x13, 0x6a, 0xa6, 0x94, 0xa7, 0x01, 0xa7, 0x75, 0x98, 0x40, 0x28, 0x0c, 0xcf, 0xc2, + 0x84, 0x52, 0xb5, 0xa1, 0x9e, 0x64, 0x4c, 0xd9, 0x9c, 0xb7, 0x4b, 0x30, 0x56, 0x24, 0xf3, 0x1c, + 0xcb, 0xa5, 0x43, 0x71, 0x2c, 0x6b, 0xf7, 0x15, 0x8a, 0x83, 0xde, 0x57, 0x30, 0xd7, 0xf6, 0xd8, + 0x40, 0x6b, 0xfb, 0x93, 0x43, 0x30, 0xfa, 0x3c, 0x89, 0x58, 0x56, 0xf5, 0x27, 0x60, 0x74, 0x87, + 0xff, 0x9b, 0xbd, 0xec, 0x2a, 0x6a, 0x60, 0x59, 0x4e, 0xbf, 0xdb, 0x66, 0xd7, 0x6f, 0xd5, 0x17, + 0xd3, 0x5d, 0x9c, 0x26, 0x64, 0x94, 0x05, 0x38, 0xad, 0x43, 0x1b, 0x34, 0xa8, 0x64, 0xdf, 0x6e, + 0xfb, 0x3d, 0xaf, 0xda, 0x2f, 0xcb, 0x02, 0x9c, 0xd6, 0x41, 0x8f, 0xc1, 0x48, 0xc3, 0x4f, 0x36, + 0xbc, 0x46, 0xd6, 0x2d, 0xba, 0xcc, 0xa0, 0x58, 0x94, 0x32, 0xb7, 0x98, 0x9f, 0x6c, 0x44, 0x84, + 0x59, 0x76, 0x7b, 0x72, 0x6d, 0x2c, 0x6b, 0x65, 0xd8, 0xa8, 0xc9, 0xba, 0x14, 0x8a, 0x91, 0x89, + 0xa8, 0xd5, 0xb4, 0x4b, 0xb2, 0x00, 0xa7, 0x75, 0xe8, 0xfa, 0xaf, 0x85, 0xed, 0x8e, 0xdf, 0x12, + 0xf1, 0xd4, 0xda, 0xfa, 0x5f, 0x10, 0x70, 0xac, 0x6a, 0xd0, 0xda, 0x94, 0x85, 0x51, 0xf6, 0x93, + 0x7d, 0x66, 0x6d, 0x5d, 0xc0, 0xb1, 0xaa, 0xe1, 0x3e, 0x0f, 0x13, 0x7c, 0x27, 0x2f, 0xb4, 0x3c, + 0xbf, 0xbd, 0xbc, 0x80, 0x2e, 0xf4, 0xdc, 0x57, 0x78, 0x22, 0xe7, 0xbe, 0xc2, 0x29, 0xa3, 0x51, + 0xef, 0xbd, 0x05, 0xf7, 0x07, 0x05, 0x18, 0x3b, 0xc2, 0x97, 0x2a, 0x8f, 0xfc, 0xd1, 0x65, 0x74, + 0x23, 0xf3, 0x4a, 0xe5, 0xba, 0xcd, 0xeb, 0x47, 0xfb, 0xbe, 0x50, 0xf9, 0x9f, 0x0b, 0x70, 0x5a, + 0x56, 0x95, 0xba, 0xdc, 0xf2, 0x02, 0x7b, 0x1f, 0xec, 0xf0, 0x27, 0x3a, 0x32, 0x26, 0x7a, 0xdd, + 0x9e, 0x36, 0xba, 0xbc, 0xd0, 0x77, 0xaa, 0x5f, 0xcd, 0x4c, 0x35, 0xb6, 0x4a, 0x75, 0xff, 0xc9, + 0xfe, 0x73, 0x07, 0xa6, 0xf3, 0x27, 0xfb, 0x08, 0x1e, 0x06, 0x7d, 0xc3, 0x7c, 0x18, 0xf4, 0x17, + 0xec, 0x2d, 0x31, 0x73, 0x28, 0x7d, 0x9e, 0x08, 0xfd, 0x33, 0x07, 0x4e, 0xca, 0x06, 0xec, 0xf4, + 0x9c, 0xf7, 0x03, 0x16, 0xb9, 0x73, 0xf8, 0xcb, 0xec, 0x75, 0x63, 0x99, 0xbd, 0x68, 0x6f, 0xe0, + 0xfa, 0x38, 0xfa, 0x3e, 0xa8, 0xfe, 0xa7, 0x0e, 0x54, 0xf2, 0x1a, 0x1c, 0xc1, 0x27, 0x7f, 0xcd, + 0xfc, 0xe4, 0xcf, 0x1f, 0xce, 0xc8, 0xfb, 0x7f, 0xf0, 0x4a, 0xbf, 0x89, 0x42, 0x2d, 0x29, 0x57, + 0x39, 0xb6, 0x7c, 0xd2, 0x9c, 0x44, 0xbe, 0x80, 0xd6, 0x82, 0x91, 0x98, 0x45, 0xa9, 0x88, 0x25, + 0x70, 0xd1, 0x86, 0xb4, 0x45, 0xf1, 0x09, 0x1b, 0x3b, 0xfb, 0x1f, 0x0b, 0x1a, 0xee, 0x6f, 0x16, + 0xe0, 0x8c, 0x7a, 0xf0, 0x97, 0xec, 0x90, 0x56, 0xba, 0x3f, 0xd8, 0x1b, 0x14, 0x9e, 0xfa, 0x69, + 0xef, 0x0d, 0x8a, 0x94, 0x44, 0xba, 0x17, 0x52, 0x18, 0xd6, 0x68, 0xa2, 0x2a, 0x9c, 0x62, 0x6f, + 0x46, 0x2c, 0xf9, 0x81, 0xd7, 0xf2, 0x5f, 0x25, 0x11, 0x26, 0xed, 0x70, 0xc7, 0x6b, 0x09, 0x49, + 0x5d, 0xdd, 0x77, 0x5e, 0xca, 0xab, 0x84, 0xf3, 0xdb, 0xf6, 0x68, 0xdc, 0x43, 0x83, 0x6a, 0xdc, + 0xee, 0x9f, 0x38, 0x30, 0x7e, 0x84, 0xcf, 0x23, 0x87, 0xe6, 0x96, 0x78, 0xd6, 0xde, 0x96, 0xe8, + 0xb3, 0x0d, 0xf6, 0x8a, 0xd0, 0xf3, 0x62, 0x2c, 0xfa, 0x94, 0xa3, 0xe2, 0x78, 0x78, 0xb0, 0xe4, + 0x87, 0xec, 0xf5, 0xe3, 0x20, 0x49, 0x32, 0xd1, 0xd7, 0x32, 0x99, 0x43, 0x0b, 0xb6, 0xd2, 0x5f, + 0xf5, 0xf4, 0xe6, 0x0e, 0x32, 0x88, 0x7e, 0xd9, 0x01, 0xe0, 0xfd, 0x14, 0x89, 0xc7, 0x69, 0xdf, + 0x36, 0x0f, 0x6d, 0xa6, 0x28, 0x11, 0xde, 0x35, 0xb5, 0x85, 0xd2, 0x02, 0xac, 0xf5, 0xe4, 0x2e, + 0x52, 0x83, 0xde, 0x75, 0x56, 0xd2, 0xcf, 0x3b, 0x70, 0x2c, 0xd3, 0xdd, 0x9c, 0xf6, 0x5b, 0xe6, + 0x13, 0x88, 0x16, 0x24, 0x2b, 0x33, 0x1d, 0xb5, 0x6e, 0x3c, 0xf9, 0xaf, 0x2e, 0x18, 0x4f, 0x6d, + 0xa3, 0xd7, 0xa0, 0x24, 0x2d, 0x1f, 0x72, 0x79, 0xdb, 0x7c, 0x0a, 0x56, 0xa9, 0x37, 0x12, 0x12, + 0xe3, 0x94, 0x5e, 0x26, 0x4c, 0xb0, 0x30, 0x50, 0x98, 0xe0, 0xbd, 0x7d, 0x48, 0x36, 0xdf, 0x2e, + 0x3d, 0x7c, 0x28, 0x76, 0xe9, 0x07, 0xad, 0xdb, 0xa5, 0x1f, 0x3a, 0x62, 0xbb, 0xb4, 0xe6, 0x24, + 0x2c, 0xde, 0x85, 0x93, 0xf0, 0x35, 0x38, 0xb9, 0x93, 0x2a, 0x9d, 0x6a, 0x25, 0x89, 0xa4, 0x4b, + 0x4f, 0xe4, 0x5a, 0xa3, 0xa9, 0x02, 0x1d, 0x27, 0x24, 0x48, 0x34, 0x75, 0x35, 0x8d, 0x50, 0x7c, + 0x3e, 0x07, 0x1d, 0xce, 0x25, 0x92, 0xf5, 0xf6, 0x8c, 0x0e, 0xe0, 0xed, 0x79, 0xcb, 0x81, 0x53, + 0x5e, 0xcf, 0xa5, 0x37, 0x4c, 0xb6, 0x44, 0xc8, 0xc9, 0x35, 0x7b, 0x22, 0x84, 0x81, 0x5e, 0xb8, + 0xd5, 0xf2, 0x8a, 0x70, 0x7e, 0x87, 0xd0, 0xa3, 0xa9, 0xeb, 0x9d, 0xc7, 0xb5, 0xe6, 0xfb, 0xc9, + 0xbf, 0x96, 0x8d, 0xe7, 0x01, 0x36, 0xf5, 0x1f, 0xb1, 0xab, 0x6d, 0x5b, 0x88, 0xe9, 0x29, 0xdf, + 0x45, 0x4c, 0x4f, 0xc6, 0xf5, 0x36, 0x6e, 0xc9, 0xf5, 0x16, 0xc0, 0x94, 0xdf, 0xf6, 0x1a, 0x64, + 0xbd, 0xdb, 0x6a, 0xf1, 0x4b, 0x33, 0xf2, 0xb1, 0xde, 0x5c, 0x0b, 0xde, 0xe5, 0xb0, 0xe6, 0xb5, + 0xb2, 0xcf, 0xb4, 0xab, 0xcb, 0x41, 0x97, 0x32, 0x98, 0x70, 0x0f, 0x6e, 0xba, 0x60, 0x59, 0xf6, + 0x3f, 0x92, 0xd0, 0xd9, 0x66, 0x81, 0x23, 0x63, 0x7c, 0xc1, 0x5e, 0x4c, 0xc1, 0x58, 0xaf, 0x83, + 0x56, 0xa0, 0x54, 0x0f, 0x62, 0x71, 0x7f, 0xf7, 0x18, 0x63, 0x66, 0xef, 0xa4, 0x2c, 0x70, 0xf1, + 0x4a, 0x55, 0xdd, 0xdc, 0x7d, 0x30, 0x27, 0x9d, 0xa5, 0x2a, 0xc7, 0x69, 0x7b, 0xb4, 0xca, 0x90, + 0x89, 0x97, 0xcc, 0x78, 0x3c, 0xc7, 0xc3, 0x7d, 0x1c, 0x46, 0x8b, 0x57, 0xe4, 0x5b, 0x6c, 0x13, + 0x82, 0x9c, 0x78, 0x92, 0x2c, 0xc5, 0xa0, 0x3d, 0x9a, 0x7c, 0x7c, 0xdf, 0x47, 0x93, 0x59, 0x1e, + 0xdb, 0xa4, 0xa5, 0xdc, 0xc3, 0x67, 0xad, 0xe5, 0xb1, 0x4d, 0x23, 0x25, 0x45, 0x1e, 0xdb, 0x14, + 0x80, 0x75, 0x92, 0x68, 0xad, 0x9f, 0x9b, 0xfc, 0x04, 0x63, 0x1a, 0x07, 0x77, 0x7a, 0xeb, 0xfe, + 0xd2, 0x93, 0xfb, 0xfa, 0x4b, 0x7b, 0xfc, 0xbb, 0xa7, 0x0e, 0xe0, 0xdf, 0x6d, 0xb2, 0x0c, 0xa3, + 0xcb, 0x0b, 0xc2, 0xa5, 0x6e, 0x41, 0xbf, 0x63, 0x39, 0x4d, 0x78, 0xe4, 0x29, 0xfb, 0x17, 0x73, + 0x02, 0x7d, 0x03, 0xc8, 0xcf, 0xdc, 0x71, 0x00, 0x39, 0x65, 0xcf, 0x29, 0x9c, 0xa5, 0xaa, 0x2d, + 0x0a, 0xf6, 0x9c, 0x82, 0xb1, 0x5e, 0x27, 0xeb, 0x2d, 0xbd, 0xff, 0xd0, 0xbc, 0xa5, 0xd3, 0x47, + 0xe0, 0x2d, 0x7d, 0x60, 0x60, 0x6f, 0xe9, 0x0d, 0x38, 0xd1, 0x09, 0xeb, 0x8b, 0x7e, 0x1c, 0x75, + 0xd9, 0x2d, 0xc2, 0xf9, 0x6e, 0xbd, 0x41, 0x12, 0xe6, 0x6e, 0x2d, 0x9f, 0x7f, 0xa7, 0xde, 0xc9, + 0x0e, 0xdb, 0xc8, 0x72, 0x8f, 0x66, 0x1a, 0x30, 0xd3, 0x09, 0x8b, 0xba, 0xcd, 0x29, 0xc4, 0x79, + 0x24, 0x74, 0x3f, 0xed, 0xc3, 0x47, 0xe3, 0xa7, 0xfd, 0x00, 0x8c, 0xc5, 0xcd, 0x6e, 0x52, 0x0f, + 0xaf, 0x07, 0xcc, 0x19, 0x5f, 0x9a, 0x7f, 0x87, 0x32, 0x65, 0x0b, 0xf8, 0xad, 0xbd, 0x99, 0x29, + 0xf9, 0xbf, 0x66, 0xc5, 0x16, 0x10, 0xf4, 0xf5, 0x3e, 0xf7, 0x95, 0xdc, 0xc3, 0xbc, 0xaf, 0x74, + 0xe6, 0x40, 0x77, 0x95, 0xf2, 0x9c, 0xd1, 0x8f, 0xfc, 0xd4, 0x39, 0xa3, 0xbf, 0xea, 0xc0, 0xc4, + 0x8e, 0xee, 0x32, 0x10, 0x0e, 0x73, 0x0b, 0x81, 0x3b, 0x86, 0x27, 0x62, 0xde, 0xa5, 0x7c, 0xce, + 0x00, 0xdd, 0xca, 0x02, 0xb0, 0xd9, 0x93, 0x9c, 0xa0, 0xa2, 0x47, 0xef, 0x55, 0x50, 0xd1, 0x1b, + 0x8c, 0x8f, 0x49, 0x25, 0x97, 0x79, 0xd1, 0xed, 0xc6, 0x14, 0x4b, 0x9e, 0xa8, 0x42, 0x8a, 0x75, + 0x7a, 0xe8, 0x73, 0x0e, 0x4c, 0x49, 0xbd, 0x4c, 0xb8, 0xfc, 0x62, 0x11, 0x15, 0x69, 0x53, 0x1d, + 0x64, 0x61, 0xf5, 0x1b, 0x19, 0x3a, 0xb8, 0x87, 0x32, 0xe5, 0xea, 0x2a, 0x08, 0xad, 0x11, 0xb3, + 0xe0, 0x5f, 0x21, 0xc3, 0xcc, 0xa5, 0x60, 0xac, 0xd7, 0x41, 0xdf, 0x70, 0xa0, 0xd8, 0x0c, 0xc3, + 0xed, 0xb8, 0xf2, 0x04, 0x63, 0xe8, 0x2f, 0x58, 0x96, 0x4d, 0x2f, 0x52, 0xdc, 0x5c, 0x28, 0x7d, + 0x4a, 0xda, 0x8e, 0x18, 0xec, 0xd6, 0xde, 0xcc, 0xa4, 0xf1, 0x10, 0x53, 0xfc, 0xe6, 0xdb, 0x1a, + 0x44, 0xd8, 0x36, 0x59, 0xd7, 0xd0, 0x17, 0x1d, 0x98, 0xba, 0x9e, 0x31, 0x68, 0x88, 0xb0, 0x50, + 0x6c, 0xdf, 0x54, 0xc2, 0xa7, 0x3b, 0x0b, 0xc5, 0x3d, 0x3d, 0x40, 0x9f, 0x35, 0x0d, 0x9d, 0x3c, + 0x7e, 0xd4, 0xe2, 0x04, 0x66, 0x0c, 0xab, 0xfc, 0x5a, 0x50, 0xbe, 0xc5, 0xf3, 0xae, 0xe3, 0x43, + 0xa6, 0xe9, 0x60, 0xd2, 0x8f, 0x95, 0xd3, 0x94, 0x98, 0xf6, 0x16, 0x0b, 0x9b, 0xdd, 0xf8, 0xfc, + 0xba, 0xb9, 0xe5, 0x8b, 0xa7, 0x61, 0xd2, 0xf4, 0xed, 0xa1, 0x77, 0x99, 0x8f, 0x6c, 0x9c, 0xcd, + 0xbe, 0x57, 0x30, 0x21, 0xeb, 0x1b, 0x6f, 0x16, 0x18, 0x8f, 0x0a, 0x14, 0x0e, 0xf5, 0x51, 0x81, + 0xa1, 0xa3, 0x79, 0x54, 0x60, 0xea, 0x30, 0x1e, 0x15, 0x38, 0x7e, 0xa0, 0x47, 0x05, 0xb4, 0x47, + 0x1d, 0x86, 0x6f, 0xf3, 0xa8, 0xc3, 0x1c, 0x1c, 0x93, 0x77, 0x7f, 0x88, 0xc8, 0xdb, 0xce, 0xdd, + 0xfe, 0x67, 0x44, 0x93, 0x63, 0x0b, 0x66, 0x31, 0xce, 0xd6, 0xa7, 0x9b, 0xac, 0x18, 0xb0, 0x96, + 0x23, 0xb6, 0x5e, 0x7c, 0x32, 0x97, 0x16, 0x53, 0x9f, 0x05, 0x8b, 0x92, 0xd1, 0xce, 0x45, 0x06, + 0xbb, 0x25, 0xff, 0xc1, 0xbc, 0x07, 0xe8, 0x25, 0xa8, 0x84, 0x5b, 0x5b, 0xad, 0xd0, 0xab, 0xa7, + 0x2f, 0x1f, 0xc8, 0xb8, 0x04, 0x7e, 0x57, 0x55, 0x25, 0xca, 0x5d, 0xeb, 0x53, 0x0f, 0xf7, 0xc5, + 0x80, 0xde, 0xa2, 0x82, 0x49, 0x12, 0x46, 0xa4, 0x9e, 0xda, 0x6a, 0x4a, 0x6c, 0xcc, 0xc4, 0xfa, + 0x98, 0xab, 0x26, 0x1d, 0x3e, 0x7a, 0xf5, 0x51, 0x32, 0xa5, 0x38, 0xdb, 0x2d, 0x14, 0xc1, 0xe9, + 0x4e, 0x9e, 0xa9, 0x28, 0x16, 0x37, 0x96, 0xf6, 0x33, 0x58, 0xc9, 0xad, 0x7b, 0x3a, 0xd7, 0xd8, + 0x14, 0xe3, 0x3e, 0x98, 0xf5, 0xd7, 0x09, 0xc6, 0x8e, 0xe6, 0x75, 0x82, 0x8f, 0x01, 0xa8, 0x4b, + 0xf9, 0xd2, 0xf8, 0xb0, 0x62, 0xe5, 0x2a, 0x0d, 0xc7, 0xa9, 0x3d, 0x08, 0xab, 0xc8, 0x60, 0x8d, + 0x24, 0xfa, 0x3f, 0xb9, 0xcf, 0x77, 0x70, 0x0b, 0x4b, 0xc3, 0xfa, 0x9a, 0xf8, 0xa9, 0x7b, 0xc2, + 0xe3, 0x1f, 0x39, 0x30, 0xcd, 0x57, 0x5e, 0x56, 0xb8, 0xa7, 0xa2, 0x85, 0xb8, 0xdb, 0x63, 0x3b, + 0x74, 0x85, 0x45, 0xf1, 0x55, 0x0d, 0xaa, 0xcc, 0xd1, 0xbd, 0x4f, 0x4f, 0xd0, 0x97, 0x73, 0x54, + 0x8a, 0x63, 0xb6, 0x6c, 0x96, 0xf9, 0x8f, 0x30, 0x9c, 0xb8, 0x39, 0x88, 0x16, 0xf1, 0x4f, 0xfa, + 0x9a, 0x54, 0x11, 0xeb, 0xde, 0x2f, 0x1e, 0x92, 0x49, 0x55, 0x7f, 0x29, 0xe2, 0x40, 0x86, 0xd5, + 0xcf, 0x3b, 0x30, 0xe5, 0x65, 0x42, 0x4d, 0x98, 0x1d, 0xc8, 0x8a, 0x4d, 0x6a, 0x2e, 0x4a, 0xe3, + 0x57, 0x98, 0x90, 0x97, 0x8d, 0x6a, 0xc1, 0x3d, 0xc4, 0xd1, 0x0f, 0x1c, 0x78, 0x20, 0xf1, 0xe2, + 0x6d, 0x9e, 0x87, 0x39, 0x4e, 0xef, 0xea, 0x8a, 0xce, 0x9d, 0x64, 0xbb, 0xf1, 0x15, 0xeb, 0xbb, + 0x71, 0xa3, 0x3f, 0x4d, 0xbe, 0x2f, 0x1f, 0x11, 0xfb, 0xf2, 0x81, 0x7d, 0x6a, 0xe2, 0xfd, 0xba, + 0x3e, 0xfd, 0x29, 0x87, 0xbf, 0xd7, 0xd5, 0x57, 0xe4, 0xdb, 0x34, 0x45, 0xbe, 0xcb, 0x36, 0x5f, + 0x0c, 0xd2, 0x65, 0xcf, 0x5f, 0x75, 0xe0, 0x64, 0xde, 0x89, 0x94, 0xd3, 0xa5, 0x8f, 0x98, 0x5d, + 0xb2, 0xa8, 0x65, 0xe9, 0x1d, 0xb2, 0xf2, 0x60, 0xc9, 0xf4, 0x15, 0x78, 0xf8, 0x76, 0x5f, 0xf1, + 0x76, 0xf8, 0xc6, 0x74, 0xb1, 0xf8, 0x4f, 0x4b, 0x9a, 0x17, 0x32, 0x21, 0x1d, 0xeb, 0x31, 0xdc, + 0x01, 0x8c, 0xf8, 0x41, 0xcb, 0x0f, 0x88, 0xb8, 0xaf, 0x69, 0x53, 0x87, 0x15, 0x0f, 0x0e, 0x51, + 0xec, 0x58, 0x50, 0xb9, 0xc7, 0x4e, 0xc9, 0xec, 0x13, 0x6e, 0xc3, 0x47, 0xff, 0x84, 0xdb, 0x75, + 0x28, 0x5d, 0xf7, 0x93, 0x26, 0x0b, 0xa6, 0x10, 0xbe, 0x3e, 0x0b, 0xf7, 0x1c, 0x29, 0xba, 0x74, + 0xec, 0xd7, 0x24, 0x01, 0x9c, 0xd2, 0x42, 0xe7, 0x38, 0x61, 0x16, 0xb9, 0x9d, 0x0d, 0xa9, 0xbd, + 0x26, 0x0b, 0x70, 0x5a, 0x87, 0x4e, 0xd6, 0x38, 0xfd, 0x25, 0x13, 0x40, 0x89, 0x3c, 0xc5, 0x36, + 0xf2, 0x4f, 0x0a, 0x8c, 0xfc, 0x36, 0xf1, 0x35, 0x8d, 0x06, 0x36, 0x28, 0xaa, 0x54, 0xd1, 0x63, + 0x7d, 0x53, 0x45, 0xbf, 0xce, 0x04, 0xb6, 0xc4, 0x0f, 0xba, 0x64, 0x2d, 0x10, 0xf1, 0xde, 0x97, + 0xed, 0xdc, 0x7d, 0xe6, 0x38, 0xb9, 0x0a, 0x9e, 0xfe, 0xc6, 0x1a, 0x3d, 0xcd, 0xe5, 0x52, 0xde, + 0xd7, 0xe5, 0x92, 0x9a, 0x5c, 0xc6, 0xad, 0x9b, 0x5c, 0x12, 0xd2, 0xb1, 0x62, 0x72, 0xf9, 0xa9, + 0x32, 0x07, 0xfc, 0xb9, 0x03, 0x48, 0xc9, 0x5d, 0x8a, 0xa1, 0x1e, 0x41, 0x50, 0xe5, 0xc7, 0x1d, + 0x80, 0x40, 0x3d, 0xf4, 0x69, 0xf7, 0x14, 0xe4, 0x38, 0xd3, 0x0e, 0xa4, 0x30, 0xac, 0xd1, 0x74, + 0xff, 0xbb, 0x93, 0xc6, 0x2e, 0xa7, 0x63, 0x3f, 0x82, 0x20, 0xb2, 0x5d, 0x33, 0x88, 0x6c, 0xc3, + 0xa2, 0xe9, 0x5e, 0x0d, 0xa3, 0x4f, 0x38, 0xd9, 0x8f, 0x0b, 0x70, 0x4c, 0xaf, 0x5c, 0x25, 0x47, + 0xf1, 0xb1, 0xaf, 0x1b, 0x11, 0xb4, 0x57, 0xed, 0x8e, 0xb7, 0x2a, 0x3c, 0x40, 0x79, 0xd1, 0xda, + 0x1f, 0xcb, 0x44, 0x6b, 0x5f, 0xb3, 0x4f, 0x7a, 0xff, 0x90, 0xed, 0xff, 0xe2, 0xc0, 0x89, 0x4c, + 0x8b, 0x23, 0x58, 0x60, 0x3b, 0xe6, 0x02, 0x7b, 0xce, 0xfa, 0xa8, 0xfb, 0xac, 0xae, 0x6f, 0x16, + 0x7a, 0x46, 0xcb, 0x94, 0xb8, 0x4f, 0x3a, 0x50, 0xa4, 0xd2, 0xb2, 0x8c, 0xe7, 0xfa, 0xc8, 0xa1, + 0xac, 0x00, 0x26, 0xd7, 0x0b, 0xee, 0xac, 0xfa, 0xc7, 0x60, 0x98, 0x53, 0x9f, 0xfe, 0x84, 0x03, + 0x90, 0x56, 0xba, 0x57, 0x22, 0xb0, 0xfb, 0xed, 0x02, 0x9c, 0xca, 0x5d, 0x46, 0xe8, 0xd3, 0xca, + 0x22, 0xe7, 0xd8, 0x8e, 0x56, 0x34, 0x08, 0xe9, 0x86, 0xb9, 0x09, 0xc3, 0x30, 0x27, 0xec, 0x71, + 0xf7, 0x4a, 0x81, 0x11, 0x6c, 0x5a, 0x9b, 0xac, 0x1f, 0x39, 0x69, 0x00, 0xac, 0xca, 0x6b, 0xf4, + 0x17, 0xf0, 0x12, 0x8f, 0xfb, 0x63, 0xed, 0x86, 0x83, 0x1c, 0xe8, 0x11, 0xf0, 0x8a, 0xeb, 0x26, + 0xaf, 0xc0, 0xf6, 0xfd, 0xc8, 0x7d, 0x98, 0xc5, 0x2b, 0x90, 0xe7, 0x58, 0x1e, 0x2c, 0x09, 0xa4, + 0x71, 0x1d, 0xb6, 0x30, 0xf0, 0x75, 0xd8, 0x09, 0x28, 0xbf, 0xe8, 0xab, 0xec, 0xa1, 0xf3, 0xb3, + 0xdf, 0xf9, 0xe1, 0xd9, 0xfb, 0xbe, 0xfb, 0xc3, 0xb3, 0xf7, 0xfd, 0xe0, 0x87, 0x67, 0xef, 0xfb, + 0xf8, 0xcd, 0xb3, 0xce, 0x77, 0x6e, 0x9e, 0x75, 0xbe, 0x7b, 0xf3, 0xac, 0xf3, 0x83, 0x9b, 0x67, + 0x9d, 0x7f, 0x77, 0xf3, 0xac, 0xf3, 0x77, 0xfe, 0xfd, 0xd9, 0xfb, 0x5e, 0x1c, 0x93, 0x03, 0xfb, + 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x3b, 0x1f, 0x04, 0xde, 0xd2, 0xd7, 0x00, 0x00, } func (m *Amount) Marshal() (dAtA []byte, err error) { @@ -11323,6 +11325,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]) @@ -16404,6 +16434,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 } @@ -19013,9 +19055,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 @@ -38997,6 +39051,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 75daf99022cb..67cf02491ae7 100644 --- a/pkg/apis/workflow/v1alpha1/generated.proto +++ b/pkg/apis/workflow/v1alpha1/generated.proto @@ -1551,11 +1551,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 56d15884603e..830664678343 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -6019,16 +6019,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 c7ac0c2e4f27..94bd3685d98a 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -1628,10 +1628,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 { @@ -1641,23 +1645,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 @@ -3880,6 +3867,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 f71aca040c98..fea752614a6f 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 a503bffe916b..dbb877f5fc99 100644 --- a/pkg/plugins/executor/swagger.yml +++ b/pkg/plugins/executor/swagger.yml @@ -3933,8 +3933,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 5f2d50121d95..9899b6feb953 100644 --- a/sdks/python/client/docs/ClusterWorkflowTemplateServiceApi.md +++ b/sdks/python/client/docs/ClusterWorkflowTemplateServiceApi.md @@ -1059,6 +1059,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", @@ -1067,6 +1073,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", @@ -5243,6 +5259,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", @@ -5251,6 +5273,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=[ @@ -9810,6 +9842,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", @@ -9818,6 +9856,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=[ @@ -11993,6 +12041,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", @@ -12001,6 +12055,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", @@ -16177,6 +16241,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", @@ -16185,6 +16255,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=[ @@ -20744,6 +20824,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", @@ -20752,6 +20838,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=[ @@ -22831,6 +22927,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", @@ -22839,6 +22941,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", @@ -27015,6 +27127,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", @@ -27023,6 +27141,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=[ @@ -31582,6 +31710,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", @@ -31590,6 +31724,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 455b2749c5cd..66c1fda4f708 100644 --- a/sdks/python/client/docs/CronWorkflowServiceApi.md +++ b/sdks/python/client/docs/CronWorkflowServiceApi.md @@ -1119,6 +1119,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", @@ -1127,6 +1133,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", @@ -5303,6 +5319,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", @@ -5311,6 +5333,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=[ @@ -9870,6 +9902,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", @@ -9878,6 +9916,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=[ @@ -12135,6 +12183,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", @@ -12143,6 +12197,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", @@ -16319,6 +16383,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", @@ -16327,6 +16397,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=[ @@ -20886,6 +20966,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", @@ -20894,6 +20980,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=[ @@ -23236,6 +23332,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", @@ -23244,6 +23346,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", @@ -27420,6 +27532,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", @@ -27428,6 +27546,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=[ @@ -31987,6 +32115,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", @@ -31995,6 +32129,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 4296e4211333..e146a7826221 100644 --- a/sdks/python/client/docs/WorkflowServiceApi.md +++ b/sdks/python/client/docs/WorkflowServiceApi.md @@ -1074,6 +1074,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", @@ -1082,6 +1088,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", @@ -5258,6 +5274,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", @@ -5266,6 +5288,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=[ @@ -9825,6 +9857,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", @@ -9833,6 +9871,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=[ @@ -16305,6 +16353,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", @@ -16313,6 +16367,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=[ @@ -17652,6 +17716,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", @@ -17660,6 +17730,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", @@ -21836,6 +21916,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", @@ -21844,6 +21930,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=[ @@ -26403,6 +26499,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", @@ -26411,6 +26513,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=[ @@ -28628,6 +28740,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", @@ -28636,6 +28754,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", @@ -32812,6 +32940,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", @@ -32820,6 +32954,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=[ @@ -37379,6 +37523,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", @@ -37387,6 +37537,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=[ @@ -43859,6 +44019,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", @@ -43867,6 +44033,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=[ @@ -45206,6 +45382,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", @@ -45214,6 +45396,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", @@ -49390,6 +49582,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", @@ -49398,6 +49596,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=[ @@ -53957,6 +54165,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", @@ -53965,6 +54179,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 8f9032d97d57..9db55c5dfdc2 100644 --- a/sdks/python/client/docs/WorkflowTemplateServiceApi.md +++ b/sdks/python/client/docs/WorkflowTemplateServiceApi.md @@ -1061,6 +1061,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", @@ -1069,6 +1075,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", @@ -5245,6 +5261,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", @@ -5253,6 +5275,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=[ @@ -9812,6 +9844,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", @@ -9820,6 +9858,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=[ @@ -12002,6 +12050,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", @@ -12010,6 +12064,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", @@ -16186,6 +16250,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", @@ -16194,6 +16264,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=[ @@ -20753,6 +20833,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", @@ -20761,6 +20847,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=[ @@ -22854,6 +22950,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", @@ -22862,6 +22964,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", @@ -27038,6 +27150,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", @@ -27046,6 +27164,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=[ @@ -31605,6 +31733,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", @@ -31613,6 +31747,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 db5e49419b00..47eb29265ada 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 670a31936582..d2d4d3125a3e 100644 --- a/test/e2e/semaphore_test.go +++ b/test/e2e/semaphore_test.go @@ -82,6 +82,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 df300d9959b8..aca294f71562 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -60,7 +60,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" @@ -252,9 +251,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 } @@ -1965,7 +1964,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 } @@ -1973,14 +1972,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 3cbc7b1990ce..740a1e3a3c70 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -8564,7 +8564,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"}}) assert.NoError(t, err) woc := newWorkflowOperationCtx(wf, controller) @@ -8573,7 +8573,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 @@ -8643,7 +8643,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 330ad4ae71fa..e4053235009a 100644 --- a/workflow/sync/mutex_test.go +++ b/workflow/sync/mutex_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/fake" "k8s.io/utils/pointer" @@ -72,8 +73,7 @@ spec: mutex: name: test templates: - - - container: + - container: args: - hello world command: @@ -113,122 +113,132 @@ 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) ctx := context.Background() wfList, err := wfclientset.ArgoprojV1alpha1().Workflows("default").List(ctx, metav1.ListOptions{}) - assert.NoError(t, err) - concurrenyMgr.Initialize(wfList.Items) - assert.Equal(t, 1, len(concurrenyMgr.syncLockMap)) + require.NoError(t, err) + syncManager.Initialize(wfList.Items) + assert.Equal(t, 1, len(syncManager.syncLockMap)) }) 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) - assert.NoError(t, err) + 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, wf.Name, wf.Status.Synchronization.Mutex.Holding[0].Holder) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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 = pointer.Int32(5) holderKey2 := getHolderKey(wf2, "") - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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.Equal(t, 0, len(wf.Status.Synchronization.Mutex.Holding)) // Low priority workflow try to acquire the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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, wf2.Name, 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) { + concurrencyManager := 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) - assert.NoError(t, err) + status, wfUpdate, msg, failedLockName, err := concurrencyManager.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, wf.Name, wf.Status.Synchronization.Mutex.Holding[0].Holder) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) - assert.NoError(t, err) + status, wfUpdate, msg, failedLockName, err = concurrencyManager.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) - assert.NoError(t, err) + status, wfUpdate, msg, failedLockName, err = concurrencyManager.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) @@ -236,42 +246,46 @@ func TestMutexLock(t *testing.T) { wf2.Namespace = "three" wf2.Spec.Priority = pointer.Int32(5) holderKey2 := getHolderKey(wf2, "") - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) - assert.NoError(t, err) + status, wfUpdate, msg, failedLockName, err = concurrencyManager.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) - assert.NoError(t, err) + status, wfUpdate, msg, failedLockName, err = concurrencyManager.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) + concurrencyManager.Release(wf, "", wf.Spec.Synchronization) assert.Equal(t, holderKey2, nextWorkflow) - assert.NotNil(t, wf.Status.Synchronization) + require.NotNil(t, wf.Status.Synchronization) assert.Equal(t, 0, len(wf.Status.Synchronization.Mutex.Holding)) // Low priority workflow try to acquire the lock - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) - assert.NoError(t, err) + status, wfUpdate, msg, failedLockName, err = concurrencyManager.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) - assert.NoError(t, err) + status, wfUpdate, msg, failedLockName, err = concurrencyManager.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, wf2.Name, wf2.Status.Synchronization.Mutex.Holding[0].Holder) - concurrenyMgr.ReleaseAll(wf2) + concurrencyManager.ReleaseAll(wf2) assert.Nil(t, wf2.Status.Synchronization) }) } @@ -381,53 +395,57 @@ 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) - assert.NoError(t, err) + 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) assert.Equal(t, "synchronization-tmpl-level-mutex-vjcdk-3941195474", 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) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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) assert.Equal(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.Empty(t, wf.Status.Synchronization.Mutex.Holding) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "synchronization-tmpl-level-mutex-vjcdk-2216915482", tmpl.Synchronization) - assert.NoError(t, err) + 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) assert.Equal(t, "synchronization-tmpl-level-mutex-vjcdk-2216915482", 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 6f4c92b87aac..6a1f94cd5ca8 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) } @@ -66,7 +66,7 @@ func (cm *Manager) CheckWorkflowExistence() { } } -func (cm *Manager) Initialize(wfs []wfv1.Workflow) { +func (sm *Manager) Initialize(wfs []wfv1.Workflow) { for _, wf := range wfs { if wf.Status.Synchronization == nil { continue @@ -74,15 +74,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 { @@ -96,15 +95,14 @@ 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 != "" { resourceKey := getResourceKey(wf.Namespace, wf.Name, holding.Holder) mutex.acquire(resourceKey) } - cm.syncLockMap[holding.Mutex] = mutex + sm.syncLockMap[holding.Mutex] = mutex } } } @@ -113,94 +111,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) } - cm.syncLockMap[lockKey] = lock + 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 + } - 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 @@ -208,7 +250,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 } @@ -223,7 +265,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 } @@ -235,7 +277,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 } @@ -248,7 +290,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 } @@ -260,7 +302,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)) } @@ -304,35 +346,35 @@ func getResourceKey(namespace, wfName, resourceName string) string { return resourceKey } -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 69194467c65c..91975b9089f1 100644 --- a/workflow/sync/sync_manager_test.go +++ b/workflow/sync/sync_manager_test.go @@ -9,6 +9,7 @@ import ( "time" "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" @@ -304,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") @@ -323,7 +324,6 @@ func GetSyncLimitFunc(kube *fake.Clientset) func(string) (int, error) { } return strconv.Atoi(value) } - return syncLimitConfig } func TestSemaphoreWfLevel(t *testing.T) { @@ -333,113 +333,120 @@ func TestSemaphoreWfLevel(t *testing.T) { ctx := context.Background() _, err := kube.CoreV1().ConfigMaps("default").Create(ctx, &cm, metav1.CreateOptions{}) - assert.NoError(t, err) + require.NoError(t, err) 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{}) - assert.NoError(t, err) - concurrenyMgr.Initialize(wfList.Items) - assert.Equal(t, 1, len(concurrenyMgr.syncLockMap)) + require.NoError(t, err) + syncManager.Initialize(wfList.Items) + assert.Equal(t, 1, len(syncManager.syncLockMap)) }) 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"}}} wf.Status.Synchronization.Semaphore.Holding = invalidSync wfclientset := fakewfclientset.NewSimpleClientset(wf) wfList, err := wfclientset.ArgoprojV1alpha1().Workflows("default").List(ctx, metav1.ListOptions{}) - assert.NoError(t, err) - concurrenyMgr.Initialize(wfList.Items) - assert.Equal(t, 0, len(concurrenyMgr.syncLockMap)) + require.NoError(t, err) + syncManager.Initialize(wfList.Items) + assert.Equal(t, 0, len(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) - assert.NoError(t, err) + 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) assert.Equal(t, wf.Name, wf.Status.Synchronization.Semaphore.Holding[0].Holders[0]) // Try to acquire again - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf, "", wf.Spec.Synchronization) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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 = pointer.Int32(5) holderKey2 := getHolderKey(wf2, "") - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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.Equal(t, 0, len(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) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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) assert.Equal(t, wf2.Name, 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.Len(t, sema.pending.items, 0) }) } @@ -451,62 +458,67 @@ func TestResizeSemaphoreSize(t *testing.T) { ctx := context.Background() _, err := kube.CoreV1().ConfigMaps("default").Create(ctx, &cm, metav1.CreateOptions{}) - assert.NoError(t, err) + require.NoError(t, err) 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) - assert.NoError(t, err) + 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) assert.Equal(t, wf.Name, wf.Status.Synchronization.Semaphore.Holding[0].Holders[0]) wf1.Name = "two" - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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) // Increase the semaphore Size cm, err := kube.CoreV1().ConfigMaps("default").Get(ctx, "my-config", metav1.GetOptions{}) - assert.NoError(t, err) + require.NoError(t, err) cm.Data["workflow"] = "3" _, err = kube.CoreV1().ConfigMaps("default").Update(ctx, cm, metav1.UpdateOptions{}) - assert.NoError(t, err) + require.NoError(t, err) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf1, "", wf1.Spec.Synchronization) - assert.NoError(t, err) + 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) assert.Equal(t, wf1.Name, wf1.Status.Synchronization.Semaphore.Holding[0].Holders[0]) - status, wfUpdate, msg, err = concurrenyMgr.TryAcquire(wf2, "", wf2.Spec.Synchronization) - assert.NoError(t, err) + 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) assert.Equal(t, wf2.Name, wf2.Status.Synchronization.Semaphore.Holding[0].Holders[0]) }) } @@ -518,51 +530,55 @@ func TestSemaphoreTmplLevel(t *testing.T) { ctx := context.Background() _, err := kube.CoreV1().ConfigMaps("default").Create(ctx, &cm, metav1.CreateOptions{}) - assert.NoError(t, err) + require.NoError(t, err) 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) - assert.NoError(t, err) + 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) assert.Equal(t, "semaphore-tmpl-level-xjvln-3448864205", 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) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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) assert.Equal(t, "semaphore-tmpl-level-xjvln-1607747183", wf.Status.Synchronization.Semaphore.Holding[0].Holders[0]) }) } @@ -576,21 +592,22 @@ func TestTriggerWFWithAvailableLock(t *testing.T) { ctx := context.Background() _, err := kube.CoreV1().ConfigMaps("default").Create(ctx, &cm, metav1.CreateOptions{}) - assert.NoError(err) + require.NoError(t, err) 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) - assert.NoError(err) + 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) @@ -599,15 +616,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) - assert.NoError(err) + 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) }) } @@ -617,42 +635,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) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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) - assert.NoError(t, err) + 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.Len(t, mutex.pending.items, 0) }) } @@ -666,11 +687,11 @@ func TestCheckWorkflowExistence(t *testing.T) { ctx := context.Background() _, err := kube.CoreV1().ConfigMaps("default").Create(ctx, &cm, metav1.CreateOptions{}) - assert.NoError(err) + require.NoError(t, err) 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") @@ -681,18 +702,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.Len(mutex.getCurrentHolders(), 0) assert.Len(mutex.getCurrentPending(), 1) assert.Len(semaphore.getCurrentHolders(), 0) @@ -709,7 +730,7 @@ func TestTriggerWFWithSemaphoreAndMutex(t *testing.T) { ctx := context.Background() _, err := kube.CoreV1().ConfigMaps("default").Create(ctx, &cm, metav1.CreateOptions{}) - assert.NoError(err) + require.NoError(t, err) wf := wfv1.MustUnmarshalWorkflow(`apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: @@ -839,27 +860,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) - assert.NoError(err) + 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) - assert.NoError(err) + 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) }) 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) + }) + } +}