From 84944797e0185fd0a8836d21ac272ab7b1dd7eb9 Mon Sep 17 00:00:00 2001 From: Niklas Hansson Date: Mon, 16 Dec 2019 15:00:58 +0100 Subject: [PATCH 01/20] Set different ttl depending on failed or succeded --- workflow/ttlcontroller/ttlcontroller.go | 1 + 1 file changed, 1 insertion(+) diff --git a/workflow/ttlcontroller/ttlcontroller.go b/workflow/ttlcontroller/ttlcontroller.go index 0e3249f31772..f64a6e8a48f4 100644 --- a/workflow/ttlcontroller/ttlcontroller.go +++ b/workflow/ttlcontroller/ttlcontroller.go @@ -185,6 +185,7 @@ func (c *Controller) deleteWorkflow(key string) error { log.Warnf("Failed to unmarshal key '%s' to workflow object: %v", key, err) return nil } + # Need to start to add things here if c.ttlExpired(wf) { log.Infof("Deleting TTL expired workflow %s/%s", wf.Namespace, wf.Name) policy := metav1.DeletePropagationForeground From 4f35c92043991766990d703c6b7af9ba9d7475fc Mon Sep 17 00:00:00 2001 From: NikeNano Date: Mon, 16 Dec 2019 17:17:11 +0100 Subject: [PATCH 02/20] initial mash of work --- pkg/apis/workflow/v1alpha1/workflow_types.go | 27 +++++++++++++++++--- workflow/ttlcontroller/ttlcontroller.go | 15 +++++++++-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 2ed139001c88..c62332c6477c 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "hash/fnv" + apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -106,6 +107,13 @@ type WorkflowList struct { var _ TemplateGetter = &Workflow{} var _ TemplateStorage = &Workflow{} +// TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed +type TTLStrategy struct { + SecondsAfterSuccess *int32 `json:"SecondsAfterSuccess,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterSuccess"` + SecondsAfterFailed *int32 `json:"SecondsAfterFailed,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterFailed"` + SecondsAfterError *int32 `json:"SecondsAfterError,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterError"` +} + // WorkflowSpec is the specification of a Workflow. type WorkflowSpec struct { // Templates is a list of workflow templates used in a workflow @@ -201,6 +209,12 @@ type WorkflowSpec struct { // ttlSecondsAfterFinished expires immediately after the Workflow finishes. TTLSecondsAfterFinished *int32 `json:"ttlSecondsAfterFinished,omitempty" protobuf:"bytes,18,opt,name=ttlSecondsAfterFinished"` + // TTLStrategy limits the lifetime of a Workflow that has finished execution depending on if it + // Succeeded or Failed. If this struct is set, once the Workflow finishes, it will be + // deleted after the time to live expires. If this field is unset, + // the controller config map will hold the default values + TTLStrategy *TTLStrategy + // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to // terminate a Running workflow @@ -845,7 +859,7 @@ func isCompletedPhase(phase NodePhase) bool { phase == NodeSkipped } -// Remove returns whether or not the workflow has completed execution +// Completed returns whether or not the workflow has completed execution func (ws *WorkflowStatus) Completed() bool { return isCompletedPhase(ws.Phase) } @@ -855,9 +869,14 @@ func (ws *WorkflowStatus) Successful() bool { return ws.Phase == NodeSucceeded } -// Remove returns whether or not the node has completed execution -func (n NodeStatus) Completed() bool { - return isCompletedPhase(n.Phase) || n.IsDaemoned() && n.Phase != NodePending +// Error return whether or not the workflow is in a error state +func (ws *WorkflowStatus) Error() bool { + return ws.Phase == NodeError +} + +// Failed return where or not the workflow has failed +func (ws *WorkflowStatus) Failed() bool { + return ws.Phase == NodeFailed } // IsDaemoned returns whether or not the node is deamoned diff --git a/workflow/ttlcontroller/ttlcontroller.go b/workflow/ttlcontroller/ttlcontroller.go index f64a6e8a48f4..6158442b1e0d 100644 --- a/workflow/ttlcontroller/ttlcontroller.go +++ b/workflow/ttlcontroller/ttlcontroller.go @@ -202,10 +202,21 @@ func (c *Controller) ttlExpired(wf *wfv1.Workflow) bool { // We don't care about the Workflows that are going to be deleted, or the ones that don't need clean up. if wf.DeletionTimestamp != nil || wf.Spec.TTLSecondsAfterFinished == nil || wf.Status.FinishedAt.IsZero() { return false + // HERE + // Check that the workflow is finished } now := c.clock.Now() - expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLSecondsAfterFinished)) - return now.After(expiry) + // Check if workflow failed + if wf.Status.Failed() + expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterSuccess)) + return now.After(expiry) + else if wf.Status.Successful() + expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterFailed)) + return now.After(expiry) + else if wf.Status.Error() + expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterError)) + return now.After(expiry) + return false } func timeLeft(wf *wfv1.Workflow, since *time.Time) (*time.Duration, *time.Time) { From 79bacf0079333ea10d1d98074411fc2bb03e8b4b Mon Sep 17 00:00:00 2001 From: NikeNano Date: Thu, 19 Dec 2019 16:52:19 +0100 Subject: [PATCH 03/20] First mash of work on ttlstrategy --- workflow/ttlcontroller/ttlcontroller.go | 46 +++-- workflow/ttlcontroller/ttlcontroller_test.go | 205 +++++++++++++++++++ 2 files changed, 235 insertions(+), 16 deletions(-) diff --git a/workflow/ttlcontroller/ttlcontroller.go b/workflow/ttlcontroller/ttlcontroller.go index 6158442b1e0d..8e727eea4936 100644 --- a/workflow/ttlcontroller/ttlcontroller.go +++ b/workflow/ttlcontroller/ttlcontroller.go @@ -129,18 +129,24 @@ func (c *Controller) processNextWorkItem() bool { } // enqueueWF conditionally queues a workflow to the ttl queue if it is within the deletion period +// what is deletion period? +// need to update here as well it seams like ..... + func (c *Controller) enqueueWF(obj interface{}) { + log.Infof("1") un, ok := obj.(*unstructured.Unstructured) if !ok { log.Warnf("'%v' is not an unstructured", obj) return } + log.Infof("2") wf, err := util.FromUnstructured(un) if err != nil { log.Warnf("Failed to unmarshal workflow %v object: %v", obj, err) return } now := c.clock.Now() + log.Infof("3") remaining, expiration := timeLeft(wf, &now) if remaining == nil || *remaining > c.resyncPeriod { return @@ -185,7 +191,6 @@ func (c *Controller) deleteWorkflow(key string) error { log.Warnf("Failed to unmarshal key '%s' to workflow object: %v", key, err) return nil } - # Need to start to add things here if c.ttlExpired(wf) { log.Infof("Deleting TTL expired workflow %s/%s", wf.Namespace, wf.Name) policy := metav1.DeletePropagationForeground @@ -200,27 +205,26 @@ func (c *Controller) deleteWorkflow(key string) error { func (c *Controller) ttlExpired(wf *wfv1.Workflow) bool { // We don't care about the Workflows that are going to be deleted, or the ones that don't need clean up. - if wf.DeletionTimestamp != nil || wf.Spec.TTLSecondsAfterFinished == nil || wf.Status.FinishedAt.IsZero() { + if wf.DeletionTimestamp != nil || ((wf.Spec.TTLSecondsAfterFinished == nil) && (wf.Spec.TTLStrategy.SecondsAfterFailed == nil) && (wf.Spec.TTLStrategy.SecondsAfterSuccess == nil)) || wf.Status.FinishedAt.IsZero() { + log.Infof("HERE HERE HERE") return false - // HERE - // Check that the workflow is finished } now := c.clock.Now() - // Check if workflow failed - if wf.Status.Failed() - expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterSuccess)) - return now.After(expiry) - else if wf.Status.Successful() + if wf.Status.Failed() && wf.Spec.TTLStrategy.SecondsAfterFailed != nil { expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterFailed)) return now.After(expiry) - else if wf.Status.Error() - expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterError)) + } else if wf.Status.Successful() && wf.Spec.TTLStrategy.SecondsAfterSuccess != nil { + expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterSuccess)) return now.After(expiry) - return false + } else { + expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLSecondsAfterFinished)) + return now.After(expiry) + } } +// This is used to put thing on the que func timeLeft(wf *wfv1.Workflow, since *time.Time) (*time.Duration, *time.Time) { - if wf.DeletionTimestamp != nil || wf.Spec.TTLSecondsAfterFinished == nil || wf.Status.FinishedAt.IsZero() { + if wf.DeletionTimestamp != nil || (wf.Spec.TTLSecondsAfterFinished == nil && wf.Spec.TTLStrategy.SecondsAfterFailed == nil && wf.Spec.TTLStrategy.SecondsAfterSuccess == nil) || wf.Status.FinishedAt.IsZero() { return nil, nil } sinceUTC := since.UTC() @@ -228,7 +232,17 @@ func timeLeft(wf *wfv1.Workflow, since *time.Time) (*time.Duration, *time.Time) if finishAtUTC.After(sinceUTC) { log.Infof("Warning: Found Workflow %s/%s finished in the future. This is likely due to time skew in the cluster. Workflow cleanup will be deferred.", wf.Namespace, wf.Name) } - expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLSecondsAfterFinished) * time.Second) - remaining := expireAtUTC.Sub(sinceUTC) - return &remaining, &expireAtUTC + if wf.Status.Failed() && wf.Spec.TTLStrategy.SecondsAfterFailed != nil { + expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLStrategy.SecondsAfterFailed) * time.Second) + remaining := expireAtUTC.Sub(sinceUTC) + return &remaining, &expireAtUTC + } else if wf.Status.Successful() && wf.Spec.TTLStrategy.SecondsAfterSuccess != nil { + expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLStrategy.SecondsAfterSuccess) * time.Second) + remaining := expireAtUTC.Sub(sinceUTC) + return &remaining, &expireAtUTC + } else { + expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLSecondsAfterFinished) * time.Second) + remaining := expireAtUTC.Sub(sinceUTC) + return &remaining, &expireAtUTC + } } diff --git a/workflow/ttlcontroller/ttlcontroller_test.go b/workflow/ttlcontroller/ttlcontroller_test.go index 03d13ed3b2c2..700ef14bc6ef 100644 --- a/workflow/ttlcontroller/ttlcontroller_test.go +++ b/workflow/ttlcontroller/ttlcontroller_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + wfv1 "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1" fakewfclientset "github.com/argoproj/argo/pkg/client/clientset/versioned/fake" "github.com/argoproj/argo/test" "github.com/argoproj/argo/workflow/util" @@ -45,6 +46,68 @@ status: startedAt: 2018-08-27T20:41:38Z ` +var succeededWf = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + clusterName: "" + creationTimestamp: 2018-08-27T20:41:38Z + generateName: hello-world- + generation: 1 + labels: + workflows.argoproj.io/completed: "true" + workflows.argoproj.io/phase: Succeeded + name: hello-world-nrgbf + namespace: default + resourceVersion: "1063703" + selfLink: /apis/argoproj.io/v1alpha1/namespaces/default/workflows/hello-world-nrgbf + uid: 9866f345-aa39-11e8-b103-025000000001 +spec: + entrypoint: whalesay + templates: + - container: + args: + - hello world + command: + - cowsay + image: docker/whalesay:latest + name: whalesay +status: + phase: Succeeded + startedAt: 2018-08-27T20:41:38Z +` + +var failedWf = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + clusterName: "" + creationTimestamp: 2018-08-27T20:41:38Z + generateName: hello-world- + generation: 1 + labels: + workflows.argoproj.io/completed: "true" + workflows.argoproj.io/phase: Succeeded + name: hello-world-nrgbf + namespace: default + resourceVersion: "1063703" + selfLink: /apis/argoproj.io/v1alpha1/namespaces/default/workflows/hello-world-nrgbf + uid: 9866f345-aa39-11e8-b103-025000000001 +spec: + entrypoint: whalesay + templates: + - container: + args: + - hello world + command: + - cowsay + image: docker/whalesay:latest + name: whalesay +status: + phase: Failed + startedAt: 2018-08-27T20:41:38Z +` + func newTTLController() *Controller { clock := clock.NewFakeClock(time.Now()) return &Controller{ @@ -86,3 +149,145 @@ func TestEnqueueWF(t *testing.T) { controller.enqueueWF(un) assert.Equal(t, 1, controller.workqueue.Len()) } + +func TestTTLStrategySucceded(t *testing.T) { + var err error + var un *unstructured.Unstructured + var ten int32 = 10 + + controller := newTTLController() + + // Veirfy we do not enqueue if not completed + wf := test.LoadWorkflowFromBytes([]byte(succeededWf)) + wf.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} + un, err = util.ToUnstructured(wf) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 0, controller.workqueue.Len()) + + wf1 := test.LoadWorkflowFromBytes([]byte(succeededWf)) + wf1.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + un, err = util.ToUnstructured(wf1) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 1, controller.workqueue.Len()) + +} + +func TestTTLStrategyFailed(t *testing.T) { + var err error + var un *unstructured.Unstructured + var ten int32 = 10 + + controller := newTTLController() + + // Veirfy we do not enqueue if not completed + wf := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} + un, err = util.ToUnstructured(wf) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 0, controller.workqueue.Len()) + + wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf1.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + un, err = util.ToUnstructured(wf1) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 1, controller.workqueue.Len()) + +} + +func TestNoTTLStrategyFailed(t *testing.T) { + var err error + var un *unstructured.Unstructured + controller := newTTLController() + // Veirfy we do not enqueue if not completed + wf := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} + un, err = util.ToUnstructured(wf) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 0, controller.workqueue.Len()) + + wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + un, err = util.ToUnstructured(wf1) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 0, controller.workqueue.Len()) + +} + +func TestNoTTLStrategyFailedButTTLSecondsAfterFinished(t *testing.T) { + var err error + var un *unstructured.Unstructured + var ten int32 = 10 + + controller := newTTLController() + + // Veirfy we do not enqueue if not completed + wf := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf.Spec.TTLSecondsAfterFinished = &ten + wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} + un, err = util.ToUnstructured(wf) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 0, controller.workqueue.Len()) + + wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf1.Spec.TTLSecondsAfterFinished = &ten + wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + un, err = util.ToUnstructured(wf1) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 1, controller.workqueue.Len()) +} + +func TestTTLlExpired(t *testing.T) { + controller := newTTLController() + var ten int32 = 10 + + wf := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + assert.Equal(t, true, wf.Status.Failed()) + now := controller.clock.Now() + assert.Equal(t, true, now.After(wf.Status.FinishedAt.Add(time.Second*time.Duration(*wf.Spec.TTLStrategy.SecondsAfterFailed)))) + assert.Equal(t, true, wf.Status.Failed() && wf.Spec.TTLStrategy.SecondsAfterFailed != nil) + assert.Equal(t, true, controller.ttlExpired(wf)) + + wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf1.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} + assert.Equal(t, false, controller.ttlExpired(wf1)) + + wf2 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf2.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf2.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + assert.Equal(t, true, controller.ttlExpired(wf2)) + + wf3 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf3.Spec.TTLSecondsAfterFinished = &ten + wf3.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} + assert.Equal(t, false, controller.ttlExpired(wf3)) + + wf4 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf4.Spec.TTLSecondsAfterFinished = &ten + wf4.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + assert.Equal(t, true, controller.ttlExpired(wf4)) + + wf5 := test.LoadWorkflowFromBytes([]byte(succeededWf)) + wf5.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf5.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} + assert.Equal(t, false, controller.ttlExpired(wf5)) + + wf6 := test.LoadWorkflowFromBytes([]byte(succeededWf)) + wf6.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf6.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} + assert.Equal(t, true, controller.ttlExpired(wf6)) +} From 2f9f616c8aa3d60941cbdebd05d335c146042b63 Mon Sep 17 00:00:00 2001 From: NikeNano Date: Fri, 20 Dec 2019 14:59:24 +0100 Subject: [PATCH 04/20] Updated the workflow --- pkg/apis/workflow/v1alpha1/workflow_types.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index c62332c6477c..01facc12e7bf 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -109,9 +109,8 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { - SecondsAfterSuccess *int32 `json:"SecondsAfterSuccess,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterSuccess"` + SecondsAfterSuccess *int32 `json:"SecondsAfterSuccess:,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterSuccess:"` SecondsAfterFailed *int32 `json:"SecondsAfterFailed,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterFailed"` - SecondsAfterError *int32 `json:"SecondsAfterError,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterError"` } // WorkflowSpec is the specification of a Workflow. @@ -213,7 +212,8 @@ type WorkflowSpec struct { // Succeeded or Failed. If this struct is set, once the Workflow finishes, it will be // deleted after the time to live expires. If this field is unset, // the controller config map will hold the default values - TTLStrategy *TTLStrategy + // Update + TTLStrategy TTLStrategy `json:"TTLStrategy,omitempty" protobuf:"bytes,18,opt,name=TTLStrategy"` // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to @@ -879,6 +879,11 @@ func (ws *WorkflowStatus) Failed() bool { return ws.Phase == NodeFailed } +// Remove returns whether or not the node has completed execution +func (n NodeStatus) Completed() bool { + return isCompletedPhase(n.Phase) || n.IsDaemoned() && n.Phase != NodePending +} + // IsDaemoned returns whether or not the node is deamoned func (n NodeStatus) IsDaemoned() bool { if n.Daemoned == nil || !*n.Daemoned { From 264c4bcb99d0b121451806a20deb631a06368c45 Mon Sep 17 00:00:00 2001 From: NikeNano Date: Fri, 20 Dec 2019 15:01:54 +0100 Subject: [PATCH 05/20] clean up --- pkg/apis/workflow/v1alpha1/workflow_types.go | 5 ----- workflow/ttlcontroller/ttlcontroller.go | 4 ---- 2 files changed, 9 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 01facc12e7bf..4ec0dec0ea06 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -869,11 +869,6 @@ func (ws *WorkflowStatus) Successful() bool { return ws.Phase == NodeSucceeded } -// Error return whether or not the workflow is in a error state -func (ws *WorkflowStatus) Error() bool { - return ws.Phase == NodeError -} - // Failed return where or not the workflow has failed func (ws *WorkflowStatus) Failed() bool { return ws.Phase == NodeFailed diff --git a/workflow/ttlcontroller/ttlcontroller.go b/workflow/ttlcontroller/ttlcontroller.go index 8e727eea4936..798a3f72c9e0 100644 --- a/workflow/ttlcontroller/ttlcontroller.go +++ b/workflow/ttlcontroller/ttlcontroller.go @@ -133,20 +133,17 @@ func (c *Controller) processNextWorkItem() bool { // need to update here as well it seams like ..... func (c *Controller) enqueueWF(obj interface{}) { - log.Infof("1") un, ok := obj.(*unstructured.Unstructured) if !ok { log.Warnf("'%v' is not an unstructured", obj) return } - log.Infof("2") wf, err := util.FromUnstructured(un) if err != nil { log.Warnf("Failed to unmarshal workflow %v object: %v", obj, err) return } now := c.clock.Now() - log.Infof("3") remaining, expiration := timeLeft(wf, &now) if remaining == nil || *remaining > c.resyncPeriod { return @@ -206,7 +203,6 @@ func (c *Controller) deleteWorkflow(key string) error { func (c *Controller) ttlExpired(wf *wfv1.Workflow) bool { // We don't care about the Workflows that are going to be deleted, or the ones that don't need clean up. if wf.DeletionTimestamp != nil || ((wf.Spec.TTLSecondsAfterFinished == nil) && (wf.Spec.TTLStrategy.SecondsAfterFailed == nil) && (wf.Spec.TTLStrategy.SecondsAfterSuccess == nil)) || wf.Status.FinishedAt.IsZero() { - log.Infof("HERE HERE HERE") return false } now := c.clock.Now() From 7be2d7928137e4271ef5eef0002bca0ea42a867f Mon Sep 17 00:00:00 2001 From: Niklas Hansson Date: Mon, 23 Dec 2019 07:53:40 +0100 Subject: [PATCH 06/20] Apply suggestions from code review Applied the suggestions from review. Co-Authored-By: Simon Behar --- pkg/apis/workflow/v1alpha1/workflow_types.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 4ec0dec0ea06..14ea88abf800 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -109,8 +109,8 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { - SecondsAfterSuccess *int32 `json:"SecondsAfterSuccess:,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterSuccess:"` - SecondsAfterFailed *int32 `json:"SecondsAfterFailed,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterFailed"` + SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterSuccess:"` + SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,2,opt,name=SecondsAfterFailed"` } // WorkflowSpec is the specification of a Workflow. @@ -213,7 +213,7 @@ type WorkflowSpec struct { // deleted after the time to live expires. If this field is unset, // the controller config map will hold the default values // Update - TTLStrategy TTLStrategy `json:"TTLStrategy,omitempty" protobuf:"bytes,18,opt,name=TTLStrategy"` + TTLStrategy TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,28,opt,name=ttlStrategy"` // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to @@ -869,7 +869,7 @@ func (ws *WorkflowStatus) Successful() bool { return ws.Phase == NodeSucceeded } -// Failed return where or not the workflow has failed +// Failed return whether or not the workflow has failed func (ws *WorkflowStatus) Failed() bool { return ws.Phase == NodeFailed } From e7b58cfac02ad09ff257649e2491cfe5a16f531e Mon Sep 17 00:00:00 2001 From: NikeNano Date: Mon, 23 Dec 2019 08:25:47 +0100 Subject: [PATCH 07/20] comments that should have been deleted --- workflow/ttlcontroller/ttlcontroller.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/workflow/ttlcontroller/ttlcontroller.go b/workflow/ttlcontroller/ttlcontroller.go index 798a3f72c9e0..a8e8d78b43ad 100644 --- a/workflow/ttlcontroller/ttlcontroller.go +++ b/workflow/ttlcontroller/ttlcontroller.go @@ -129,9 +129,6 @@ func (c *Controller) processNextWorkItem() bool { } // enqueueWF conditionally queues a workflow to the ttl queue if it is within the deletion period -// what is deletion period? -// need to update here as well it seams like ..... - func (c *Controller) enqueueWF(obj interface{}) { un, ok := obj.(*unstructured.Unstructured) if !ok { @@ -218,7 +215,6 @@ func (c *Controller) ttlExpired(wf *wfv1.Workflow) bool { } } -// This is used to put thing on the que func timeLeft(wf *wfv1.Workflow, since *time.Time) (*time.Duration, *time.Time) { if wf.DeletionTimestamp != nil || (wf.Spec.TTLSecondsAfterFinished == nil && wf.Spec.TTLStrategy.SecondsAfterFailed == nil && wf.Spec.TTLStrategy.SecondsAfterSuccess == nil) || wf.Status.FinishedAt.IsZero() { return nil, nil From 1819279bb9a02ff2dc30744212e36a837f4337bc Mon Sep 17 00:00:00 2001 From: NikeNano Date: Sat, 28 Dec 2019 17:06:47 +0100 Subject: [PATCH 08/20] updated to use pointers instead for ttlstrategy --- pkg/apis/workflow/v1alpha1/workflow_types.go | 7 ++++--- workflow/config/config.go | 9 ++++++++ workflow/ttlcontroller/ttlcontroller.go | 12 +++++------ workflow/ttlcontroller/ttlcontroller_test.go | 22 ++++++++++---------- workflow/util/util.go | 5 +++++ 5 files changed, 35 insertions(+), 20 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 14ea88abf800..d7eeb3e0b1be 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -109,8 +109,9 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { - SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterSuccess:"` - SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,2,opt,name=SecondsAfterFailed"` + SecondsAfterCompleted *int32 `json:"SecondsAfterCompleted:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterCompleted:"` + SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterSuccess:"` + SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,2,opt,name=SecondsAfterFailed"` } // WorkflowSpec is the specification of a Workflow. @@ -213,7 +214,7 @@ type WorkflowSpec struct { // deleted after the time to live expires. If this field is unset, // the controller config map will hold the default values // Update - TTLStrategy TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,28,opt,name=ttlStrategy"` + TTLStrategy *TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,28,opt,name=ttlStrategy"` // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to diff --git a/workflow/config/config.go b/workflow/config/config.go index 309fd3be87ee..60b9bd192507 100644 --- a/workflow/config/config.go +++ b/workflow/config/config.go @@ -6,6 +6,12 @@ import ( apiv1 "k8s.io/api/core/v1" ) +// TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed +type TTLStrategy struct { + SecondsAfterSuccess *int32 `json:"SecondsAfterSuccess:,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterSuccess:"` + SecondsAfterFailed *int32 `json:"SecondsAfterFailed,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterFailed"` +} + // WorkflowControllerConfig contain the configuration settings for the workflow controller type WorkflowControllerConfig struct { // ExecutorImage is the image name of the executor to use when running pods @@ -62,6 +68,9 @@ type WorkflowControllerConfig struct { // Config customized Docker Sock path DockerSockPath string `json:"dockerSockPath,omitempty"` + + // Config for the TTLStrategy + TTLStrategy *TTLStrategy `json:"TTLStrategy,omitempty"` } // KubeConfig is used for wait & init sidecar containers to communicate with a k8s apiserver by a outofcluster method, diff --git a/workflow/ttlcontroller/ttlcontroller.go b/workflow/ttlcontroller/ttlcontroller.go index a8e8d78b43ad..b4d7cf487063 100644 --- a/workflow/ttlcontroller/ttlcontroller.go +++ b/workflow/ttlcontroller/ttlcontroller.go @@ -199,24 +199,24 @@ func (c *Controller) deleteWorkflow(key string) error { func (c *Controller) ttlExpired(wf *wfv1.Workflow) bool { // We don't care about the Workflows that are going to be deleted, or the ones that don't need clean up. - if wf.DeletionTimestamp != nil || ((wf.Spec.TTLSecondsAfterFinished == nil) && (wf.Spec.TTLStrategy.SecondsAfterFailed == nil) && (wf.Spec.TTLStrategy.SecondsAfterSuccess == nil)) || wf.Status.FinishedAt.IsZero() { + if wf.DeletionTimestamp != nil || wf.Spec.TTLStrategy == nil || wf.Status.FinishedAt.IsZero() { return false } now := c.clock.Now() - if wf.Status.Failed() && wf.Spec.TTLStrategy.SecondsAfterFailed != nil { + if wf.Status.Failed() && wf.Spec.TTLStrategy != nil && wf.Spec.TTLStrategy.SecondsAfterFailed != nil { expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterFailed)) return now.After(expiry) - } else if wf.Status.Successful() && wf.Spec.TTLStrategy.SecondsAfterSuccess != nil { + } else if wf.Status.Successful() { expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterSuccess)) return now.After(expiry) } else { - expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLSecondsAfterFinished)) + expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterCompleted)) return now.After(expiry) } } func timeLeft(wf *wfv1.Workflow, since *time.Time) (*time.Duration, *time.Time) { - if wf.DeletionTimestamp != nil || (wf.Spec.TTLSecondsAfterFinished == nil && wf.Spec.TTLStrategy.SecondsAfterFailed == nil && wf.Spec.TTLStrategy.SecondsAfterSuccess == nil) || wf.Status.FinishedAt.IsZero() { + if wf.DeletionTimestamp != nil || wf.Spec.TTLStrategy == nil || wf.Status.FinishedAt.IsZero() { return nil, nil } sinceUTC := since.UTC() @@ -233,7 +233,7 @@ func timeLeft(wf *wfv1.Workflow, since *time.Time) (*time.Duration, *time.Time) remaining := expireAtUTC.Sub(sinceUTC) return &remaining, &expireAtUTC } else { - expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLSecondsAfterFinished) * time.Second) + expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLStrategy.SecondsAfterCompleted) * time.Second) remaining := expireAtUTC.Sub(sinceUTC) return &remaining, &expireAtUTC } diff --git a/workflow/ttlcontroller/ttlcontroller_test.go b/workflow/ttlcontroller/ttlcontroller_test.go index 700ef14bc6ef..2aa157d770ae 100644 --- a/workflow/ttlcontroller/ttlcontroller_test.go +++ b/workflow/ttlcontroller/ttlcontroller_test.go @@ -159,7 +159,7 @@ func TestTTLStrategySucceded(t *testing.T) { // Veirfy we do not enqueue if not completed wf := test.LoadWorkflowFromBytes([]byte(succeededWf)) - wf.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterSuccess: &ten} wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} un, err = util.ToUnstructured(wf) assert.NoError(t, err) @@ -167,7 +167,7 @@ func TestTTLStrategySucceded(t *testing.T) { assert.Equal(t, 0, controller.workqueue.Len()) wf1 := test.LoadWorkflowFromBytes([]byte(succeededWf)) - wf1.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf1.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterSuccess: &ten} wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} un, err = util.ToUnstructured(wf1) assert.NoError(t, err) @@ -185,7 +185,7 @@ func TestTTLStrategyFailed(t *testing.T) { // Veirfy we do not enqueue if not completed wf := test.LoadWorkflowFromBytes([]byte(failedWf)) - wf.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterFailed: &ten} wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} un, err = util.ToUnstructured(wf) assert.NoError(t, err) @@ -193,7 +193,7 @@ func TestTTLStrategyFailed(t *testing.T) { assert.Equal(t, 0, controller.workqueue.Len()) wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) - wf1.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf1.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterFailed: &ten} wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} un, err = util.ToUnstructured(wf1) assert.NoError(t, err) @@ -253,7 +253,7 @@ func TestTTLlExpired(t *testing.T) { var ten int32 = 10 wf := test.LoadWorkflowFromBytes([]byte(failedWf)) - wf.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterFailed: &ten} wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} assert.Equal(t, true, wf.Status.Failed()) now := controller.clock.Now() @@ -262,32 +262,32 @@ func TestTTLlExpired(t *testing.T) { assert.Equal(t, true, controller.ttlExpired(wf)) wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) - wf1.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf1.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterFailed: &ten} wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} assert.Equal(t, false, controller.ttlExpired(wf1)) wf2 := test.LoadWorkflowFromBytes([]byte(failedWf)) - wf2.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf2.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterFailed: &ten} wf2.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} assert.Equal(t, true, controller.ttlExpired(wf2)) wf3 := test.LoadWorkflowFromBytes([]byte(failedWf)) - wf3.Spec.TTLSecondsAfterFinished = &ten + wf3.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterCompleted: &ten} wf3.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} assert.Equal(t, false, controller.ttlExpired(wf3)) wf4 := test.LoadWorkflowFromBytes([]byte(failedWf)) - wf4.Spec.TTLSecondsAfterFinished = &ten + wf4.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterCompleted: &ten} wf4.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} assert.Equal(t, true, controller.ttlExpired(wf4)) wf5 := test.LoadWorkflowFromBytes([]byte(succeededWf)) - wf5.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf5.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterSuccess: &ten} wf5.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-5 * time.Second)} assert.Equal(t, false, controller.ttlExpired(wf5)) wf6 := test.LoadWorkflowFromBytes([]byte(succeededWf)) - wf6.Spec.TTLStrategy = wfv1.TTLStrategy{SecondsAfterSuccess: &ten} + wf6.Spec.TTLStrategy = &wfv1.TTLStrategy{SecondsAfterSuccess: &ten} wf6.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} assert.Equal(t, true, controller.ttlExpired(wf6)) } diff --git a/workflow/util/util.go b/workflow/util/util.go index 6d3cb4df581e..11a8799a9d4d 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -122,6 +122,11 @@ func NewWorkflowLister(informer cache.SharedIndexInformer) WorkflowLister { func FromUnstructured(un *unstructured.Unstructured) (*wfv1.Workflow, error) { var wf wfv1.Workflow err := runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &wf) + if wf.Spec.TTLSecondsAfterFinished != nil { + ttlstrategy := wfv1.TTLStrategy{ + SecondsAfterCompleted: wf.Spec.TTLSecondsAfterFinished} + wf.Spec.TTLStrategy = &ttlstrategy + } return &wf, err } From 33120ffd4db197dced19ea09e6e14da31b91365f Mon Sep 17 00:00:00 2001 From: NikeNano Date: Sat, 28 Dec 2019 19:14:57 +0100 Subject: [PATCH 09/20] removed things that was added by misstake and handled when ttlstrategy is added --- workflow/config/config.go | 9 --------- workflow/util/util.go | 9 ++++++--- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/workflow/config/config.go b/workflow/config/config.go index 60b9bd192507..309fd3be87ee 100644 --- a/workflow/config/config.go +++ b/workflow/config/config.go @@ -6,12 +6,6 @@ import ( apiv1 "k8s.io/api/core/v1" ) -// TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed -type TTLStrategy struct { - SecondsAfterSuccess *int32 `json:"SecondsAfterSuccess:,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterSuccess:"` - SecondsAfterFailed *int32 `json:"SecondsAfterFailed,omitempty" protobuf:"bytes,18,opt,name=SecondsAfterFailed"` -} - // WorkflowControllerConfig contain the configuration settings for the workflow controller type WorkflowControllerConfig struct { // ExecutorImage is the image name of the executor to use when running pods @@ -68,9 +62,6 @@ type WorkflowControllerConfig struct { // Config customized Docker Sock path DockerSockPath string `json:"dockerSockPath,omitempty"` - - // Config for the TTLStrategy - TTLStrategy *TTLStrategy `json:"TTLStrategy,omitempty"` } // KubeConfig is used for wait & init sidecar containers to communicate with a k8s apiserver by a outofcluster method, diff --git a/workflow/util/util.go b/workflow/util/util.go index 11a8799a9d4d..2af44232df8e 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -123,9 +123,12 @@ func FromUnstructured(un *unstructured.Unstructured) (*wfv1.Workflow, error) { var wf wfv1.Workflow err := runtime.DefaultUnstructuredConverter.FromUnstructured(un.Object, &wf) if wf.Spec.TTLSecondsAfterFinished != nil { - ttlstrategy := wfv1.TTLStrategy{ - SecondsAfterCompleted: wf.Spec.TTLSecondsAfterFinished} - wf.Spec.TTLStrategy = &ttlstrategy + if wf.Spec.TTLStrategy == nil { + ttlstrategy := wfv1.TTLStrategy{SecondsAfterCompleted: wf.Spec.TTLSecondsAfterFinished} + wf.Spec.TTLStrategy = &ttlstrategy + } else { + wf.Spec.TTLStrategy.SecondsAfterCompleted = wf.Spec.TTLSecondsAfterFinished + } } return &wf, err } From 2b9f50e287c3e6a49573c02b3247b675d866fc49 Mon Sep 17 00:00:00 2001 From: NikeNano Date: Sat, 28 Dec 2019 21:14:06 +0100 Subject: [PATCH 10/20] Updated test and now handle cases where both ttlstratetyComplete and ttlSecondsFinsihed are set --- workflow/ttlcontroller/ttlcontroller.go | 6 ++- workflow/ttlcontroller/ttlcontroller_test.go | 52 ++++++++++++++++++++ workflow/util/util.go | 2 +- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/workflow/ttlcontroller/ttlcontroller.go b/workflow/ttlcontroller/ttlcontroller.go index b4d7cf487063..6c4c6a21463a 100644 --- a/workflow/ttlcontroller/ttlcontroller.go +++ b/workflow/ttlcontroller/ttlcontroller.go @@ -206,7 +206,7 @@ func (c *Controller) ttlExpired(wf *wfv1.Workflow) bool { if wf.Status.Failed() && wf.Spec.TTLStrategy != nil && wf.Spec.TTLStrategy.SecondsAfterFailed != nil { expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterFailed)) return now.After(expiry) - } else if wf.Status.Successful() { + } else if wf.Status.Successful() && wf.Spec.TTLStrategy != nil && wf.Spec.TTLStrategy.SecondsAfterSuccess != nil { expiry := wf.Status.FinishedAt.Add(time.Second * time.Duration(*wf.Spec.TTLStrategy.SecondsAfterSuccess)) return now.After(expiry) } else { @@ -232,9 +232,11 @@ func timeLeft(wf *wfv1.Workflow, since *time.Time) (*time.Duration, *time.Time) expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLStrategy.SecondsAfterSuccess) * time.Second) remaining := expireAtUTC.Sub(sinceUTC) return &remaining, &expireAtUTC - } else { + } else if wf.Spec.TTLStrategy.SecondsAfterCompleted != nil { expireAtUTC := finishAtUTC.Add(time.Duration(*wf.Spec.TTLStrategy.SecondsAfterCompleted) * time.Second) remaining := expireAtUTC.Sub(sinceUTC) return &remaining, &expireAtUTC + } else { + return nil, nil } } diff --git a/workflow/ttlcontroller/ttlcontroller_test.go b/workflow/ttlcontroller/ttlcontroller_test.go index 2aa157d770ae..74927c6735b9 100644 --- a/workflow/ttlcontroller/ttlcontroller_test.go +++ b/workflow/ttlcontroller/ttlcontroller_test.go @@ -241,6 +241,8 @@ func TestNoTTLStrategyFailedButTTLSecondsAfterFinished(t *testing.T) { wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) wf1.Spec.TTLSecondsAfterFinished = &ten + ttlstrategy := wfv1.TTLStrategy{SecondsAfterFailed: &ten} + wf1.Spec.TTLStrategy = &ttlstrategy wf1.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-11 * time.Second)} un, err = util.ToUnstructured(wf1) assert.NoError(t, err) @@ -248,6 +250,56 @@ func TestNoTTLStrategyFailedButTTLSecondsAfterFinished(t *testing.T) { assert.Equal(t, 1, controller.workqueue.Len()) } +func TestTTLStrategyFromUnstructured(t *testing.T) { + var err error + var un *unstructured.Unstructured + var ten int32 = 10 + var five int32 = 5 + controller := newTTLController() + wf := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf.Spec.TTLSecondsAfterFinished = &ten + ttlstrategy := wfv1.TTLStrategy{SecondsAfterFailed: &five} + wf.Spec.TTLStrategy = &ttlstrategy + wf.Status.FinishedAt = metav1.Time{Time: controller.clock.Now().Add(-6 * time.Second)} + un, err = util.ToUnstructured(wf) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 1, controller.workqueue.Len()) + + controller1 := newTTLController() + wf1 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf1.Spec.TTLSecondsAfterFinished = &ten + ttlstrategy1 := wfv1.TTLStrategy{SecondsAfterCompleted: &five} + wf1.Spec.TTLStrategy = &ttlstrategy1 + wf1.Status.FinishedAt = metav1.Time{Time: controller1.clock.Now().Add(-6 * time.Second)} + un, err = util.ToUnstructured(wf1) + assert.NoError(t, err) + controller1.enqueueWF(un) + assert.Equal(t, 1, controller1.workqueue.Len()) + + controller2 := newTTLController() + wf2 := test.LoadWorkflowFromBytes([]byte(failedWf)) + wf2.Spec.TTLSecondsAfterFinished = &ten + ttlstrategy2 := wfv1.TTLStrategy{SecondsAfterFailed: &five} + wf2.Spec.TTLStrategy = &ttlstrategy2 + wf2.Status.FinishedAt = metav1.Time{Time: controller2.clock.Now().Add(-6 * time.Second)} + un, err = util.ToUnstructured(wf2) + assert.NoError(t, err) + controller2.enqueueWF(un) + assert.Equal(t, 1, controller2.workqueue.Len()) + + controller3 := newTTLController() + wf3 := test.LoadWorkflowFromBytes([]byte(failedWf)) + ttlstrategy3 := wfv1.TTLStrategy{SecondsAfterSuccess: &five} + wf3.Spec.TTLStrategy = &ttlstrategy3 + wf3.Status.FinishedAt = metav1.Time{Time: controller3.clock.Now().Add(-6 * time.Second)} + un, err = util.ToUnstructured(wf3) + t.Log(wf3.Spec.TTLStrategy) + assert.NoError(t, err) + controller.enqueueWF(un) + assert.Equal(t, 0, controller3.workqueue.Len()) +} + func TestTTLlExpired(t *testing.T) { controller := newTTLController() var ten int32 = 10 diff --git a/workflow/util/util.go b/workflow/util/util.go index 2af44232df8e..e6bc78c0f385 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -126,7 +126,7 @@ func FromUnstructured(un *unstructured.Unstructured) (*wfv1.Workflow, error) { if wf.Spec.TTLStrategy == nil { ttlstrategy := wfv1.TTLStrategy{SecondsAfterCompleted: wf.Spec.TTLSecondsAfterFinished} wf.Spec.TTLStrategy = &ttlstrategy - } else { + } else if wf.Spec.TTLStrategy.SecondsAfterCompleted == nil { wf.Spec.TTLStrategy.SecondsAfterCompleted = wf.Spec.TTLSecondsAfterFinished } } From 00af5a4992039829a93e1d12439f89f73ed7ee5e Mon Sep 17 00:00:00 2001 From: NikeNano Date: Thu, 2 Jan 2020 21:21:20 +0100 Subject: [PATCH 11/20] updated codegen --- .../v1alpha1/zz_generated.deepcopy.go | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go index 6e99a07880a6..b0d68a9204f2 100644 --- a/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/workflow/v1alpha1/zz_generated.deepcopy.go @@ -893,6 +893,37 @@ func (in *SuspendTemplate) DeepCopy() *SuspendTemplate { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TTLStrategy) DeepCopyInto(out *TTLStrategy) { + *out = *in + if in.SecondsAfterCompleted != nil { + in, out := &in.SecondsAfterCompleted, &out.SecondsAfterCompleted + *out = new(int32) + **out = **in + } + if in.SecondsAfterSuccess != nil { + in, out := &in.SecondsAfterSuccess, &out.SecondsAfterSuccess + *out = new(int32) + **out = **in + } + if in.SecondsAfterFailed != nil { + in, out := &in.SecondsAfterFailed, &out.SecondsAfterFailed + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TTLStrategy. +func (in *TTLStrategy) DeepCopy() *TTLStrategy { + if in == nil { + return nil + } + out := new(TTLStrategy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TarStrategy) DeepCopyInto(out *TarStrategy) { *out = *in @@ -1267,6 +1298,11 @@ func (in *WorkflowSpec) DeepCopyInto(out *WorkflowSpec) { *out = new(int32) **out = **in } + if in.TTLStrategy != nil { + in, out := &in.TTLStrategy, &out.TTLStrategy + *out = new(TTLStrategy) + (*in).DeepCopyInto(*out) + } if in.ActiveDeadlineSeconds != nil { in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds *out = new(int64) From fc92e65c5c281d2e68bed3b70aa38d8085fc51e6 Mon Sep 17 00:00:00 2001 From: NikeNano Date: Thu, 2 Jan 2020 22:19:27 +0100 Subject: [PATCH 12/20] changed uppercase to lowercase on string --- pkg/apis/workflow/v1alpha1/workflow_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 8f53b4cc0134..1075dd04ce9c 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -109,7 +109,7 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { - SecondsAfterCompleted *int32 `json:"SecondsAfterCompleted:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterCompleted:"` + SecondsAfterCompleted *int32 `json:"secondsAfterCompleted:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterCompleted:"` SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterSuccess:"` SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,2,opt,name=SecondsAfterFailed"` } From ca55edec2e5f3710b43716f4c1579fde80d14f51 Mon Sep 17 00:00:00 2001 From: NikeNano Date: Thu, 2 Jan 2020 22:29:20 +0100 Subject: [PATCH 13/20] updated to lower case, to follow standard --- pkg/apis/workflow/v1alpha1/workflow_types.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 1075dd04ce9c..e39c77508435 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -109,9 +109,9 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { - SecondsAfterCompleted *int32 `json:"secondsAfterCompleted:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterCompleted:"` - SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,1,opt,name=SecondsAfterSuccess:"` - SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,2,opt,name=SecondsAfterFailed"` + SecondsAfterCompleted *int32 `json:"secondsAfterCompleted:,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompleted:"` + SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,1,opt,name=secondsAfterSuccess:"` + SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,2,opt,name=secondsAfterFailed"` } // WorkflowSpec is the specification of a Workflow. From fb76e4ece4afd6089789b4e38385512e277776e9 Mon Sep 17 00:00:00 2001 From: NikeNano Date: Sat, 4 Jan 2020 14:51:00 +0100 Subject: [PATCH 14/20] added the Deprecated tag --- pkg/apis/workflow/v1alpha1/workflow_types.go | 25 ++++++++++---------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index e39c77508435..b15bfe109a13 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -110,8 +110,8 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { SecondsAfterCompleted *int32 `json:"secondsAfterCompleted:,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompleted:"` - SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,1,opt,name=secondsAfterSuccess:"` - SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,2,opt,name=secondsAfterFailed"` + SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,2,opt,name=secondsAfterSuccess:"` + SecondsAfterFailed *int32 `json:"secondsAfterFailed:,omitempty" protobuf:"bytes,3,opt,name=secondsAfterFailed"` } // WorkflowSpec is the specification of a Workflow. @@ -207,6 +207,7 @@ type WorkflowSpec struct { // deleted after ttlSecondsAfterFinished expires. If this field is unset, // ttlSecondsAfterFinished will not expire. If this field is set to zero, // ttlSecondsAfterFinished expires immediately after the Workflow finishes. + // DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead. TTLSecondsAfterFinished *int32 `json:"ttlSecondsAfterFinished,omitempty" protobuf:"bytes,18,opt,name=ttlSecondsAfterFinished"` // TTLStrategy limits the lifetime of a Workflow that has finished execution depending on if it @@ -214,42 +215,42 @@ type WorkflowSpec struct { // deleted after the time to live expires. If this field is unset, // the controller config map will hold the default values // Update - TTLStrategy *TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,28,opt,name=ttlStrategy"` + TTLStrategy *TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,19,opt,name=ttlStrategy"` // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to // terminate a Running workflow - ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"bytes,19,opt,name=activeDeadlineSeconds"` + ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"bytes,20,opt,name=activeDeadlineSeconds"` // Priority is used if controller is configured to process limited number of workflows in parallel. Workflows with higher priority are processed first. - Priority *int32 `json:"priority,omitempty" protobuf:"bytes,20,opt,name=priority"` + Priority *int32 `json:"priority,omitempty" protobuf:"bytes,21,opt,name=priority"` // Set scheduler name for all pods. // Will be overridden if container/script template's scheduler name is set. // Default scheduler will be used if neither specified. // +optional - SchedulerName string `json:"schedulerName,omitempty" protobuf:"bytes,21,opt,name=schedulerName"` + SchedulerName string `json:"schedulerName,omitempty" protobuf:"bytes,22,opt,name=schedulerName"` // PodGC describes the strategy to use when to deleting completed pods - PodGC *PodGC `json:"podGC,omitempty" protobuf:"bytes,22,opt,name=podGC"` + PodGC *PodGC `json:"podGC,omitempty" protobuf:"bytes,23,opt,name=podGC"` // PriorityClassName to apply to workflow pods. - PodPriorityClassName string `json:"podPriorityClassName,omitempty" protobuf:"bytes,23,opt,name=podPriorityClassName"` + PodPriorityClassName string `json:"podPriorityClassName,omitempty" protobuf:"bytes,24,opt,name=podPriorityClassName"` // Priority to apply to workflow pods. - PodPriority *int32 `json:"podPriority,omitempty" protobuf:"bytes,24,opt,name=podPriority"` + PodPriority *int32 `json:"podPriority,omitempty" protobuf:"bytes,25,opt,name=podPriority"` // +patchStrategy=merge // +patchMergeKey=ip - HostAliases []apiv1.HostAlias `json:"hostAliases,omitempty" patchStrategy:"merge" patchMergeKey:"ip" protobuf:"bytes,25,opt,name=hostAliases"` + HostAliases []apiv1.HostAlias `json:"hostAliases,omitempty" patchStrategy:"merge" patchMergeKey:"ip" protobuf:"bytes,26,opt,name=hostAliases"` // SecurityContext holds pod-level security attributes and common container settings. // Optional: Defaults to empty. See type description for default values of each field. // +optiona - SecurityContext *apiv1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,26,opt,name=securityContext"` + SecurityContext *apiv1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,27,opt,name=securityContext"` // PodSpecPatch holds strategic merge patch to apply against the pod spec. Allows parameterization of // container fields which are not strings (e.g. resource limits). - PodSpecPatch string `json:"podSpecPatch,omitempty" protobuf:"bytes,27,opt,name=podSpecPatch"` + PodSpecPatch string `json:"podSpecPatch,omitempty" protobuf:"bytes,28,opt,name=podSpecPatch"` } type ParallelSteps struct { From 50df4fd946ae4c61e62629da4ef62f6ea7b27c3e Mon Sep 17 00:00:00 2001 From: NikeNano Date: Tue, 7 Jan 2020 08:54:25 +0100 Subject: [PATCH 15/20] reverted the protobuff nbr after feedback --- pkg/apis/workflow/v1alpha1/workflow_types.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index b15bfe109a13..4c24951d6714 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -215,42 +215,42 @@ type WorkflowSpec struct { // deleted after the time to live expires. If this field is unset, // the controller config map will hold the default values // Update - TTLStrategy *TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,19,opt,name=ttlStrategy"` + TTLStrategy *TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,28,opt,name=ttlStrategy"` // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to // terminate a Running workflow - ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"bytes,20,opt,name=activeDeadlineSeconds"` + ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"bytes,19,opt,name=activeDeadlineSeconds"` // Priority is used if controller is configured to process limited number of workflows in parallel. Workflows with higher priority are processed first. - Priority *int32 `json:"priority,omitempty" protobuf:"bytes,21,opt,name=priority"` + Priority *int32 `json:"priority,omitempty" protobuf:"bytes,20,opt,name=priority"` // Set scheduler name for all pods. // Will be overridden if container/script template's scheduler name is set. // Default scheduler will be used if neither specified. // +optional - SchedulerName string `json:"schedulerName,omitempty" protobuf:"bytes,22,opt,name=schedulerName"` + SchedulerName string `json:"schedulerName,omitempty" protobuf:"bytes,21,opt,name=schedulerName"` // PodGC describes the strategy to use when to deleting completed pods - PodGC *PodGC `json:"podGC,omitempty" protobuf:"bytes,23,opt,name=podGC"` + PodGC *PodGC `json:"podGC,omitempty" protobuf:"bytes,22,opt,name=podGC"` // PriorityClassName to apply to workflow pods. - PodPriorityClassName string `json:"podPriorityClassName,omitempty" protobuf:"bytes,24,opt,name=podPriorityClassName"` + PodPriorityClassName string `json:"podPriorityClassName,omitempty" protobuf:"bytes,23,opt,name=podPriorityClassName"` // Priority to apply to workflow pods. - PodPriority *int32 `json:"podPriority,omitempty" protobuf:"bytes,25,opt,name=podPriority"` + PodPriority *int32 `json:"podPriority,omitempty" protobuf:"bytes,24,opt,name=podPriority"` // +patchStrategy=merge // +patchMergeKey=ip - HostAliases []apiv1.HostAlias `json:"hostAliases,omitempty" patchStrategy:"merge" patchMergeKey:"ip" protobuf:"bytes,26,opt,name=hostAliases"` + HostAliases []apiv1.HostAlias `json:"hostAliases,omitempty" patchStrategy:"merge" patchMergeKey:"ip" protobuf:"bytes,25,opt,name=hostAliases"` // SecurityContext holds pod-level security attributes and common container settings. // Optional: Defaults to empty. See type description for default values of each field. // +optiona - SecurityContext *apiv1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,27,opt,name=securityContext"` + SecurityContext *apiv1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,26,opt,name=securityContext"` // PodSpecPatch holds strategic merge patch to apply against the pod spec. Allows parameterization of // container fields which are not strings (e.g. resource limits). - PodSpecPatch string `json:"podSpecPatch,omitempty" protobuf:"bytes,28,opt,name=podSpecPatch"` + PodSpecPatch string `json:"podSpecPatch,omitempty" protobuf:"bytes,27,opt,name=podSpecPatch"` } type ParallelSteps struct { From 7b219745d76a01d57da8dc7ae369eb0359a3198f Mon Sep 17 00:00:00 2001 From: Niklas Hansson Date: Tue, 7 Jan 2020 09:01:49 +0100 Subject: [PATCH 16/20] Update pkg/apis/workflow/v1alpha1/workflow_types.go Co-Authored-By: Simon Behar --- pkg/apis/workflow/v1alpha1/workflow_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 4c24951d6714..58ca8931f61e 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -109,7 +109,7 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { - SecondsAfterCompleted *int32 `json:"secondsAfterCompleted:,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompleted:"` + SecondsAfterCompleted *int32 `json:"secondsAfterCompleted,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompleted"` SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,2,opt,name=secondsAfterSuccess:"` SecondsAfterFailed *int32 `json:"secondsAfterFailed:,omitempty" protobuf:"bytes,3,opt,name=secondsAfterFailed"` } From de463d994f483509533de1e387fe69bf84e3e1a5 Mon Sep 17 00:00:00 2001 From: Niklas Hansson Date: Tue, 7 Jan 2020 09:02:00 +0100 Subject: [PATCH 17/20] Update pkg/apis/workflow/v1alpha1/workflow_types.go Co-Authored-By: Simon Behar --- pkg/apis/workflow/v1alpha1/workflow_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 58ca8931f61e..f4859f2bcd32 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -110,7 +110,7 @@ var _ TemplateStorage = &Workflow{} // TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed type TTLStrategy struct { SecondsAfterCompleted *int32 `json:"secondsAfterCompleted,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompleted"` - SecondsAfterSuccess *int32 `json:"secondsAfterSuccess:,omitempty" protobuf:"bytes,2,opt,name=secondsAfterSuccess:"` + SecondsAfterSuccess *int32 `json:"secondsAfterSuccess,omitempty" protobuf:"bytes,2,opt,name=secondsAfterSuccess"` SecondsAfterFailed *int32 `json:"secondsAfterFailed:,omitempty" protobuf:"bytes,3,opt,name=secondsAfterFailed"` } From 9f8821eb3eda410dc15ab155d8a2af2ef50909d9 Mon Sep 17 00:00:00 2001 From: Niklas Hansson Date: Tue, 7 Jan 2020 09:02:12 +0100 Subject: [PATCH 18/20] Update pkg/apis/workflow/v1alpha1/workflow_types.go Co-Authored-By: Simon Behar --- pkg/apis/workflow/v1alpha1/workflow_types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index f4859f2bcd32..4db23257c4cd 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -111,7 +111,7 @@ var _ TemplateStorage = &Workflow{} type TTLStrategy struct { SecondsAfterCompleted *int32 `json:"secondsAfterCompleted,omitempty" protobuf:"bytes,1,opt,name=secondsAfterCompleted"` SecondsAfterSuccess *int32 `json:"secondsAfterSuccess,omitempty" protobuf:"bytes,2,opt,name=secondsAfterSuccess"` - SecondsAfterFailed *int32 `json:"secondsAfterFailed:,omitempty" protobuf:"bytes,3,opt,name=secondsAfterFailed"` + SecondsAfterFailed *int32 `json:"secondsAfterFailed,omitempty" protobuf:"bytes,3,opt,name=secondsAfterFailed"` } // WorkflowSpec is the specification of a Workflow. From e98aa2d4c035f5c1c085f4ff321ba06c410f4d69 Mon Sep 17 00:00:00 2001 From: NikeNano Date: Tue, 7 Jan 2020 15:19:04 +0100 Subject: [PATCH 19/20] updated in accordance with the code updates --- examples/gc-ttl.yaml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/examples/gc-ttl.yaml b/examples/gc-ttl.yaml index ff54d4a7a038..5679520266c3 100644 --- a/examples/gc-ttl.yaml +++ b/examples/gc-ttl.yaml @@ -1,12 +1,21 @@ # This example shows the ability to automatically delete workflows after a specified time period # after the workflow completes. The ttlSecondsAfterFinished indicates the duration in seconds, after # a workflow finishes, in which the workflow (and its pods) will be deleted. +# This example shows the ability to automatically delete workflows after a specified time period +# after the workflow completes. The ttlSecondsAfterFinished indicates the duration in seconds, after +# a workflow finishes, in which the workflow (and its pods) will be deleted. +# The TTLStrategy sets the strategy for how long workflows that are successful or completed should live. +# The former ttlSecondsAfterFinished will be despatched and will be replaced with SecondsAfterCompleted. +# However the user now also have the possibility to set a seperataion between workflows that were succesfull or failed apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: gc-ttl- spec: - ttlSecondsAfterFinished: 10 + TTLStrategy: + secondsAfterCompleted: 10 # Used to replace ttlSecondsAfterFinished which will be Despatched + secondsAfterSuccess: 5 # The time to live after success + secondsAfterFailed: 5 # The time to live after failure entrypoint: whalesay templates: - name: whalesay @@ -14,3 +23,4 @@ spec: image: docker/whalesay:latest command: [cowsay] args: ["hello world"] + From e78dc2658f49a13376704572ce1b9b22e4ba847c Mon Sep 17 00:00:00 2001 From: Simon Behar Date: Tue, 7 Jan 2020 06:52:42 -0800 Subject: [PATCH 20/20] Codegen and minor edit --- api/openapi-spec/swagger.json | 24 +- examples/gc-ttl.yaml | 17 +- pkg/apis/workflow/v1alpha1/generated.pb.go | 955 +++++++++++------- pkg/apis/workflow/v1alpha1/generated.proto | 17 + .../workflow/v1alpha1/openapi_generated.go | 42 +- pkg/apis/workflow/v1alpha1/workflow_types.go | 2 +- 6 files changed, 687 insertions(+), 370 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 5745a38d1f3a..50c5701fbd79 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -1079,6 +1079,24 @@ } } }, + "io.argoproj.workflow.v1alpha1.TTLStrategy": { + "description": "TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed", + "type": "object", + "properties": { + "secondsAfterCompleted": { + "type": "integer", + "format": "int32" + }, + "secondsAfterFailed": { + "type": "integer", + "format": "int32" + }, + "secondsAfterSuccess": { + "type": "integer", + "format": "int32" + } + } + }, "io.argoproj.workflow.v1alpha1.TarStrategy": { "description": "TarStrategy will tar and gzip the file or directory when saving", "type": "object" @@ -1626,10 +1644,14 @@ "x-kubernetes-patch-strategy": "merge" }, "ttlSecondsAfterFinished": { - "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes.", + "description": "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes. DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead.", "type": "integer", "format": "int32" }, + "ttlStrategy": { + "description": "TTLStrategy limits the lifetime of a Workflow that has finished execution depending on if it Succeeded or Failed. If this struct is set, once the Workflow finishes, it will be deleted after the time to live expires. If this field is unset, the controller config map will hold the default values Update", + "$ref": "#/definitions/io.argoproj.workflow.v1alpha1.TTLStrategy" + }, "volumeClaimTemplates": { "description": "VolumeClaimTemplates is a list of claims that containers are allowed to reference. The Workflow controller will create the claims at the beginning of the workflow and delete the claims upon completion of the workflow", "type": "array", diff --git a/examples/gc-ttl.yaml b/examples/gc-ttl.yaml index 5679520266c3..408524b4a930 100644 --- a/examples/gc-ttl.yaml +++ b/examples/gc-ttl.yaml @@ -1,21 +1,16 @@ # This example shows the ability to automatically delete workflows after a specified time period -# after the workflow completes. The ttlSecondsAfterFinished indicates the duration in seconds, after -# a workflow finishes, in which the workflow (and its pods) will be deleted. -# This example shows the ability to automatically delete workflows after a specified time period -# after the workflow completes. The ttlSecondsAfterFinished indicates the duration in seconds, after -# a workflow finishes, in which the workflow (and its pods) will be deleted. -# The TTLStrategy sets the strategy for how long workflows that are successful or completed should live. -# The former ttlSecondsAfterFinished will be despatched and will be replaced with SecondsAfterCompleted. -# However the user now also have the possibility to set a seperataion between workflows that were succesfull or failed +# after the workflow completes. The TTLStrategy sets the strategy for how long workflows that are +# successful, not successful, or completed should live. The former ttlSecondsAfterFinished will be +# deprecated and will be replaced with TTLStrategy.SecondsAfterCompleted. apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: gc-ttl- spec: TTLStrategy: - secondsAfterCompleted: 10 # Used to replace ttlSecondsAfterFinished which will be Despatched - secondsAfterSuccess: 5 # The time to live after success - secondsAfterFailed: 5 # The time to live after failure + secondsAfterCompleted: 10 # Time to live after workflow is completed, replaces ttlSecondsAfterFinished + secondsAfterSuccess: 5 # Time to live after workflow is successful + secondsAfterFailed: 5 # Time to live after workflow fails entrypoint: whalesay templates: - name: whalesay diff --git a/pkg/apis/workflow/v1alpha1/generated.pb.go b/pkg/apis/workflow/v1alpha1/generated.pb.go index ed7a3a0dc0db..150c40023c95 100644 --- a/pkg/apis/workflow/v1alpha1/generated.pb.go +++ b/pkg/apis/workflow/v1alpha1/generated.pb.go @@ -1011,10 +1011,38 @@ func (m *SuspendTemplate) XXX_DiscardUnknown() { var xxx_messageInfo_SuspendTemplate proto.InternalMessageInfo +func (m *TTLStrategy) Reset() { *m = TTLStrategy{} } +func (*TTLStrategy) ProtoMessage() {} +func (*TTLStrategy) Descriptor() ([]byte, []int) { + return fileDescriptor_c23edafa7e7ea072, []int{35} +} +func (m *TTLStrategy) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *TTLStrategy) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil +} +func (m *TTLStrategy) XXX_Merge(src proto.Message) { + xxx_messageInfo_TTLStrategy.Merge(m, src) +} +func (m *TTLStrategy) XXX_Size() int { + return m.Size() +} +func (m *TTLStrategy) XXX_DiscardUnknown() { + xxx_messageInfo_TTLStrategy.DiscardUnknown(m) +} + +var xxx_messageInfo_TTLStrategy proto.InternalMessageInfo + func (m *TarStrategy) Reset() { *m = TarStrategy{} } func (*TarStrategy) ProtoMessage() {} func (*TarStrategy) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{35} + return fileDescriptor_c23edafa7e7ea072, []int{36} } func (m *TarStrategy) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1042,7 +1070,7 @@ var xxx_messageInfo_TarStrategy proto.InternalMessageInfo func (m *Template) Reset() { *m = Template{} } func (*Template) ProtoMessage() {} func (*Template) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{36} + return fileDescriptor_c23edafa7e7ea072, []int{37} } func (m *Template) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1070,7 +1098,7 @@ var xxx_messageInfo_Template proto.InternalMessageInfo func (m *TemplateRef) Reset() { *m = TemplateRef{} } func (*TemplateRef) ProtoMessage() {} func (*TemplateRef) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{37} + return fileDescriptor_c23edafa7e7ea072, []int{38} } func (m *TemplateRef) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1098,7 +1126,7 @@ var xxx_messageInfo_TemplateRef proto.InternalMessageInfo func (m *UserContainer) Reset() { *m = UserContainer{} } func (*UserContainer) ProtoMessage() {} func (*UserContainer) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{38} + return fileDescriptor_c23edafa7e7ea072, []int{39} } func (m *UserContainer) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1126,7 +1154,7 @@ var xxx_messageInfo_UserContainer proto.InternalMessageInfo func (m *ValueFrom) Reset() { *m = ValueFrom{} } func (*ValueFrom) ProtoMessage() {} func (*ValueFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{39} + return fileDescriptor_c23edafa7e7ea072, []int{40} } func (m *ValueFrom) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1154,7 +1182,7 @@ var xxx_messageInfo_ValueFrom proto.InternalMessageInfo func (m *Workflow) Reset() { *m = Workflow{} } func (*Workflow) ProtoMessage() {} func (*Workflow) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{40} + return fileDescriptor_c23edafa7e7ea072, []int{41} } func (m *Workflow) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1182,7 +1210,7 @@ var xxx_messageInfo_Workflow proto.InternalMessageInfo func (m *WorkflowList) Reset() { *m = WorkflowList{} } func (*WorkflowList) ProtoMessage() {} func (*WorkflowList) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{41} + return fileDescriptor_c23edafa7e7ea072, []int{42} } func (m *WorkflowList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1210,7 +1238,7 @@ var xxx_messageInfo_WorkflowList proto.InternalMessageInfo func (m *WorkflowSpec) Reset() { *m = WorkflowSpec{} } func (*WorkflowSpec) ProtoMessage() {} func (*WorkflowSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{42} + return fileDescriptor_c23edafa7e7ea072, []int{43} } func (m *WorkflowSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1238,7 +1266,7 @@ var xxx_messageInfo_WorkflowSpec proto.InternalMessageInfo func (m *WorkflowStatus) Reset() { *m = WorkflowStatus{} } func (*WorkflowStatus) ProtoMessage() {} func (*WorkflowStatus) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{43} + return fileDescriptor_c23edafa7e7ea072, []int{44} } func (m *WorkflowStatus) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1266,7 +1294,7 @@ var xxx_messageInfo_WorkflowStatus proto.InternalMessageInfo func (m *WorkflowStep) Reset() { *m = WorkflowStep{} } func (*WorkflowStep) ProtoMessage() {} func (*WorkflowStep) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{44} + return fileDescriptor_c23edafa7e7ea072, []int{45} } func (m *WorkflowStep) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1294,7 +1322,7 @@ var xxx_messageInfo_WorkflowStep proto.InternalMessageInfo func (m *WorkflowTemplate) Reset() { *m = WorkflowTemplate{} } func (*WorkflowTemplate) ProtoMessage() {} func (*WorkflowTemplate) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{45} + return fileDescriptor_c23edafa7e7ea072, []int{46} } func (m *WorkflowTemplate) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1322,7 +1350,7 @@ var xxx_messageInfo_WorkflowTemplate proto.InternalMessageInfo func (m *WorkflowTemplateList) Reset() { *m = WorkflowTemplateList{} } func (*WorkflowTemplateList) ProtoMessage() {} func (*WorkflowTemplateList) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{46} + return fileDescriptor_c23edafa7e7ea072, []int{47} } func (m *WorkflowTemplateList) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1350,7 +1378,7 @@ var xxx_messageInfo_WorkflowTemplateList proto.InternalMessageInfo func (m *WorkflowTemplateSpec) Reset() { *m = WorkflowTemplateSpec{} } func (*WorkflowTemplateSpec) ProtoMessage() {} func (*WorkflowTemplateSpec) Descriptor() ([]byte, []int) { - return fileDescriptor_c23edafa7e7ea072, []int{47} + return fileDescriptor_c23edafa7e7ea072, []int{48} } func (m *WorkflowTemplateSpec) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -1415,6 +1443,7 @@ func init() { proto.RegisterType((*ScriptTemplate)(nil), "github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.ScriptTemplate") proto.RegisterType((*Sequence)(nil), "github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.Sequence") proto.RegisterType((*SuspendTemplate)(nil), "github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.SuspendTemplate") + proto.RegisterType((*TTLStrategy)(nil), "github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.TTLStrategy") proto.RegisterType((*TarStrategy)(nil), "github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.TarStrategy") proto.RegisterType((*Template)(nil), "github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.Template") proto.RegisterMapType((map[string]string)(nil), "github.com.argoproj.argo.pkg.apis.workflow.v1alpha1.Template.NodeSelectorEntry") @@ -1439,306 +1468,312 @@ func init() { } var fileDescriptor_c23edafa7e7ea072 = []byte{ - // 4783 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5c, 0x4f, 0x6c, 0x1c, 0x69, - 0x56, 0x4f, 0xdb, 0xee, 0x76, 0xf7, 0x6b, 0xff, 0xcb, 0x17, 0x67, 0x52, 0xe3, 0xcd, 0xb8, 0xb3, - 0xb5, 0x9a, 0x21, 0x0b, 0x33, 0xf6, 0x4e, 0xb2, 0x0b, 0xb3, 0xb3, 0xcc, 0xcc, 0xba, 0xdd, 0x76, - 0xe2, 0x24, 0x76, 0xcc, 0x6b, 0x27, 0xc3, 0x32, 0x2b, 0x96, 0x72, 0xd5, 0xe7, 0xee, 0x4a, 0x77, - 0x57, 0xd5, 0xd4, 0x57, 0x1d, 0x8f, 0x35, 0x48, 0x0c, 0x08, 0x04, 0x08, 0xad, 0x04, 0x97, 0x65, - 0xc5, 0x5e, 0x10, 0x07, 0xb8, 0x70, 0xe1, 0xca, 0x61, 0x91, 0x10, 0x87, 0x11, 0x17, 0xe6, 0xc6, - 0x1e, 0x90, 0xb5, 0x63, 0x24, 0x04, 0x02, 0x09, 0x89, 0x0b, 0x22, 0x27, 0xf4, 0xfd, 0xa9, 0xaf, - 0xfe, 0x74, 0x7b, 0xc6, 0xe9, 0x76, 0x82, 0xd0, 0xee, 0x29, 0xae, 0xf7, 0xde, 0xf7, 0x7b, 0xdf, - 0xdf, 0xf7, 0xbd, 0xf7, 0xbe, 0xd7, 0x81, 0xf5, 0x96, 0x1b, 0xb5, 0xfb, 0xfb, 0x2b, 0xb6, 0xdf, - 0x5b, 0xb5, 0xc2, 0x96, 0x1f, 0x84, 0xfe, 0x23, 0xf1, 0xc7, 0x6a, 0xd0, 0x69, 0xad, 0x5a, 0x81, - 0xcb, 0x56, 0x0f, 0xfd, 0xb0, 0x73, 0xd0, 0xf5, 0x0f, 0x57, 0x1f, 0xbf, 0x6e, 0x75, 0x83, 0xb6, - 0xf5, 0xfa, 0x6a, 0x8b, 0x7a, 0x34, 0xb4, 0x22, 0xea, 0xac, 0x04, 0xa1, 0x1f, 0xf9, 0xe4, 0x66, - 0x02, 0xb2, 0x12, 0x83, 0x88, 0x3f, 0x56, 0x82, 0x4e, 0x6b, 0x85, 0x83, 0xac, 0xc4, 0x20, 0x2b, - 0x31, 0xc8, 0xd2, 0x6b, 0x29, 0xcd, 0x2d, 0x9f, 0x2b, 0xe4, 0x58, 0xfb, 0xfd, 0x03, 0xf1, 0x25, - 0x3e, 0xc4, 0x5f, 0x52, 0xc7, 0x92, 0xd9, 0x79, 0x83, 0xad, 0xb8, 0x3e, 0xef, 0xd2, 0xaa, 0xed, - 0x87, 0x74, 0xf5, 0xf1, 0x40, 0x3f, 0x96, 0xbe, 0x9a, 0xc8, 0xf4, 0x2c, 0xbb, 0xed, 0x7a, 0x34, - 0x3c, 0x4a, 0xc6, 0xd1, 0xa3, 0x91, 0x35, 0xac, 0xd5, 0xea, 0x69, 0xad, 0xc2, 0xbe, 0x17, 0xb9, - 0x3d, 0x3a, 0xd0, 0xe0, 0xe7, 0x3f, 0xaf, 0x01, 0xb3, 0xdb, 0xb4, 0x67, 0xe5, 0xdb, 0x99, 0xff, - 0x50, 0x80, 0xf9, 0xb5, 0xd0, 0x6e, 0xbb, 0x8f, 0x69, 0x33, 0xe2, 0x8c, 0xd6, 0x11, 0x79, 0x0f, - 0x26, 0x23, 0x2b, 0x34, 0x0a, 0xd7, 0x0a, 0xd7, 0xab, 0x37, 0xbe, 0xb9, 0x32, 0xc2, 0x44, 0xae, - 0xec, 0x59, 0x61, 0x0c, 0x57, 0x9f, 0x3e, 0x39, 0xae, 0x4d, 0xee, 0x59, 0x21, 0x72, 0x54, 0xf2, - 0x1d, 0x98, 0xf2, 0x7c, 0x8f, 0x1a, 0x13, 0x02, 0x7d, 0x6d, 0x24, 0xf4, 0x1d, 0xdf, 0xd3, 0xbd, - 0xad, 0x97, 0x4f, 0x8e, 0x6b, 0x53, 0x9c, 0x82, 0x02, 0xd8, 0xfc, 0xcf, 0x02, 0x54, 0xd6, 0xc2, - 0x56, 0xbf, 0x47, 0xbd, 0x88, 0x91, 0x10, 0x20, 0xb0, 0x42, 0xab, 0x47, 0x23, 0x1a, 0x32, 0xa3, - 0x70, 0x6d, 0xf2, 0x7a, 0xf5, 0xc6, 0xdb, 0x23, 0x29, 0xdd, 0x8d, 0x61, 0xea, 0xe4, 0xe3, 0xe3, - 0xda, 0x85, 0x93, 0xe3, 0x1a, 0x68, 0x12, 0xc3, 0x94, 0x16, 0xe2, 0x41, 0xc5, 0x0a, 0x23, 0xf7, - 0xc0, 0xb2, 0x23, 0x66, 0x4c, 0x08, 0x95, 0x6f, 0x8d, 0xa4, 0x72, 0x4d, 0xa1, 0xd4, 0x2f, 0x2a, - 0x8d, 0x95, 0x98, 0xc2, 0x30, 0x51, 0x61, 0xfe, 0xfb, 0x24, 0x94, 0x63, 0x06, 0xb9, 0x06, 0x53, - 0x9e, 0xd5, 0xa3, 0x62, 0xf5, 0x2a, 0xf5, 0x19, 0xd5, 0x70, 0x6a, 0xc7, 0xea, 0xf1, 0x09, 0xb2, - 0x7a, 0x94, 0x4b, 0x04, 0x56, 0xd4, 0x16, 0x2b, 0x90, 0x92, 0xd8, 0xb5, 0xa2, 0x36, 0x0a, 0x0e, - 0xb9, 0x0a, 0x53, 0x3d, 0xdf, 0xa1, 0xc6, 0xe4, 0xb5, 0xc2, 0xf5, 0xa2, 0x9c, 0xe0, 0x6d, 0xdf, - 0xa1, 0x28, 0xa8, 0xbc, 0xfd, 0x41, 0xe8, 0xf7, 0x8c, 0xa9, 0x6c, 0xfb, 0xcd, 0xd0, 0xef, 0xa1, - 0xe0, 0x90, 0x3f, 0x28, 0xc0, 0x42, 0xdc, 0xbd, 0x7b, 0xbe, 0x6d, 0x45, 0xae, 0xef, 0x19, 0x45, - 0xb1, 0xe0, 0x1b, 0x63, 0x4d, 0x44, 0x0c, 0x56, 0x37, 0x94, 0xd6, 0x85, 0x3c, 0x07, 0x07, 0x14, - 0x93, 0x1b, 0x00, 0xad, 0xae, 0xbf, 0x6f, 0x75, 0xf9, 0x1c, 0x18, 0x25, 0xd1, 0x6b, 0xbd, 0x84, - 0xb7, 0x34, 0x07, 0x53, 0x52, 0xa4, 0x03, 0xd3, 0x96, 0x3c, 0x15, 0xc6, 0xb4, 0xe8, 0x77, 0x63, - 0xc4, 0x7e, 0x67, 0x4e, 0x56, 0xbd, 0x7a, 0x72, 0x5c, 0x9b, 0x56, 0x44, 0x8c, 0x35, 0x90, 0x57, - 0xa1, 0xec, 0x07, 0xbc, 0xab, 0x56, 0xd7, 0x28, 0x5f, 0x2b, 0x5c, 0x2f, 0xd7, 0x17, 0x54, 0xf7, - 0xca, 0xf7, 0x15, 0x1d, 0xb5, 0x84, 0xf9, 0xc7, 0x45, 0x18, 0x18, 0x35, 0x79, 0x1d, 0xaa, 0x0a, - 0xed, 0x9e, 0xdf, 0x62, 0x62, 0xf1, 0xcb, 0xf5, 0xf9, 0x93, 0xe3, 0x5a, 0x75, 0x2d, 0x21, 0x63, - 0x5a, 0x86, 0xbc, 0x0b, 0x13, 0xec, 0xa6, 0x3a, 0x86, 0xef, 0x8c, 0x34, 0xba, 0xe6, 0x4d, 0xbd, - 0x41, 0x4b, 0x27, 0xc7, 0xb5, 0x89, 0xe6, 0x4d, 0x9c, 0x60, 0x37, 0xb9, 0xf9, 0x68, 0xb9, 0x91, - 0xd8, 0x3c, 0xa3, 0x9a, 0x8f, 0x5b, 0x6e, 0xa4, 0xa1, 0x85, 0xf9, 0xb8, 0xe5, 0x46, 0xc8, 0x51, - 0xb9, 0xf9, 0x68, 0x47, 0x51, 0x20, 0x36, 0xdf, 0xa8, 0xe6, 0xe3, 0xf6, 0xde, 0xde, 0xae, 0x86, - 0x17, 0xbb, 0x9b, 0x53, 0x50, 0x00, 0x93, 0x0f, 0xf9, 0x4c, 0x4a, 0x9e, 0x1f, 0x1e, 0xa9, 0x5d, - 0x7b, 0x7b, 0xac, 0x5d, 0xeb, 0x87, 0x47, 0x5a, 0x9d, 0x5a, 0x13, 0xcd, 0xc0, 0xb4, 0x36, 0x31, - 0x3a, 0xe7, 0x80, 0x89, 0x4d, 0x3a, 0xf2, 0xe8, 0x1a, 0x9b, 0xcd, 0xdc, 0xe8, 0x1a, 0x9b, 0x4d, - 0x14, 0xc0, 0x7c, 0x6d, 0x42, 0xeb, 0x50, 0xed, 0xe9, 0xd1, 0xd6, 0x06, 0xad, 0xc3, 0xec, 0xda, - 0xa0, 0x75, 0x88, 0x1c, 0xd5, 0x6c, 0xc1, 0xe5, 0x98, 0x83, 0x34, 0xf0, 0x99, 0x2b, 0x06, 0x48, - 0x0f, 0xc8, 0x2a, 0x54, 0x6c, 0xdf, 0x3b, 0x70, 0x5b, 0xdb, 0x56, 0xa0, 0x0c, 0x93, 0xb6, 0x68, - 0xeb, 0x31, 0x03, 0x13, 0x19, 0xf2, 0x12, 0x4c, 0x76, 0xe8, 0x91, 0xb2, 0x50, 0x55, 0x25, 0x3a, - 0x79, 0x97, 0x1e, 0x21, 0xa7, 0x9b, 0x3f, 0x2c, 0xc0, 0xa5, 0x21, 0x93, 0xcb, 0x9b, 0xf5, 0xc3, - 0xae, 0xd2, 0xa0, 0x9b, 0x3d, 0xc0, 0x7b, 0xc8, 0xe9, 0xe4, 0x77, 0x0b, 0x30, 0x9f, 0x9a, 0xed, - 0xb5, 0xbe, 0x32, 0x82, 0xa3, 0x9f, 0xee, 0x0c, 0x56, 0xfd, 0x8a, 0xd2, 0x38, 0x9f, 0x63, 0x60, - 0x5e, 0xab, 0xf9, 0x8f, 0xe2, 0xd6, 0xcd, 0xd0, 0x88, 0x05, 0x73, 0x7d, 0x46, 0x43, 0x6e, 0xa2, - 0x9b, 0xd4, 0x0e, 0x69, 0xa4, 0x2e, 0xe0, 0x97, 0x57, 0xe4, 0xd5, 0xce, 0x7b, 0xb1, 0xc2, 0xbd, - 0x8c, 0x95, 0xc7, 0xaf, 0xaf, 0x48, 0x89, 0xbb, 0xf4, 0xa8, 0x49, 0xbb, 0x94, 0x63, 0xd4, 0xc9, - 0xc9, 0x71, 0x6d, 0xee, 0x41, 0x06, 0x00, 0x73, 0x80, 0x5c, 0x45, 0x60, 0x31, 0x76, 0xe8, 0x87, - 0x8e, 0x52, 0x31, 0xf1, 0xd4, 0x2a, 0x76, 0x33, 0x00, 0x98, 0x03, 0x34, 0xbf, 0x57, 0x80, 0xe9, - 0xba, 0x65, 0x77, 0xfc, 0x83, 0x03, 0x6e, 0xd7, 0x9c, 0x7e, 0x28, 0xad, 0xbf, 0x5c, 0x13, 0x6d, - 0xd7, 0x1a, 0x8a, 0x8e, 0x5a, 0x82, 0xbc, 0x02, 0x25, 0x39, 0x1d, 0xa2, 0x53, 0xc5, 0xfa, 0x9c, - 0x92, 0x2d, 0x6d, 0x0a, 0x2a, 0x2a, 0x2e, 0xf9, 0x1a, 0x54, 0x7b, 0xd6, 0x07, 0x31, 0x80, 0x30, - 0x33, 0x95, 0xfa, 0x25, 0x25, 0x5c, 0xdd, 0x4e, 0x58, 0x98, 0x96, 0x33, 0xbf, 0x05, 0xb0, 0xee, - 0x7b, 0x91, 0xeb, 0xf5, 0xe9, 0x7d, 0x8f, 0x7c, 0x09, 0x8a, 0x34, 0x0c, 0xfd, 0x50, 0x59, 0xca, - 0x59, 0xd5, 0xbc, 0xb8, 0xc1, 0x89, 0x28, 0x79, 0xb2, 0x47, 0x6e, 0x97, 0x3a, 0xa2, 0x47, 0xe5, - 0x74, 0x8f, 0x38, 0x15, 0x15, 0xd7, 0xfc, 0x93, 0x12, 0x4c, 0x37, 0xd6, 0x6e, 0xed, 0x59, 0xac, - 0x73, 0x86, 0xeb, 0xf7, 0x55, 0x28, 0x47, 0xb4, 0x17, 0x74, 0xad, 0x88, 0xaa, 0x0d, 0xae, 0x67, - 0x65, 0x4f, 0xd1, 0x51, 0x4b, 0x10, 0x9f, 0xfb, 0x12, 0xca, 0x99, 0x51, 0x26, 0xf5, 0xed, 0x11, - 0x37, 0xab, 0x42, 0x49, 0x3b, 0x13, 0x8a, 0x84, 0x89, 0x0e, 0xc2, 0xa0, 0x1a, 0x2b, 0x47, 0x7a, - 0xa0, 0xec, 0xec, 0x88, 0x4e, 0x60, 0x82, 0x23, 0xed, 0x5e, 0x8a, 0x80, 0x69, 0x2d, 0xe4, 0xab, - 0x30, 0xe3, 0xd0, 0x80, 0x7a, 0x0e, 0xf5, 0x6c, 0x97, 0x32, 0xa3, 0x78, 0x6d, 0x92, 0xcf, 0xcb, - 0xc9, 0x71, 0x6d, 0xa6, 0x91, 0xa2, 0x63, 0x46, 0x8a, 0x3c, 0x82, 0xca, 0xa1, 0x1b, 0xb5, 0xb7, - 0x22, 0xda, 0xe3, 0x26, 0x93, 0xfb, 0x59, 0x5f, 0x1f, 0xa9, 0xa3, 0x1c, 0x21, 0x99, 0x96, 0x77, - 0x63, 0x4c, 0x4c, 0xe0, 0xb9, 0x09, 0xe3, 0x1f, 0xc2, 0xe3, 0x13, 0xe6, 0xb3, 0x92, 0x6d, 0x20, - 0x18, 0x98, 0xc8, 0x10, 0x06, 0x33, 0xfc, 0xa3, 0x49, 0xdf, 0xef, 0x53, 0xcf, 0xa6, 0xe2, 0x62, - 0x1f, 0xd5, 0x0f, 0x8c, 0x41, 0xe4, 0x8c, 0xbc, 0x9b, 0x82, 0xc5, 0x8c, 0x12, 0xbe, 0xfb, 0x0e, - 0xdb, 0xd4, 0x33, 0x2a, 0xd9, 0xdd, 0xf7, 0x6e, 0x9b, 0x7a, 0x28, 0x38, 0xc4, 0x07, 0xb0, 0xf5, - 0x31, 0x30, 0x60, 0x8c, 0xdb, 0x3f, 0x39, 0x4d, 0xf5, 0x39, 0xee, 0x49, 0x25, 0xdf, 0x98, 0x52, - 0x61, 0xfe, 0x6d, 0x01, 0xaa, 0xfc, 0x70, 0xc4, 0x1b, 0xfa, 0x15, 0x28, 0x45, 0x56, 0xd8, 0x52, - 0xe6, 0xad, 0x92, 0x1c, 0xaa, 0x3d, 0x41, 0x45, 0xc5, 0x25, 0x16, 0x14, 0x23, 0x8b, 0x75, 0x62, - 0x07, 0xfa, 0x17, 0x47, 0xea, 0xa3, 0x3a, 0x95, 0xc9, 0xf9, 0xe6, 0x5f, 0x0c, 0x25, 0x32, 0xb9, - 0x0e, 0x65, 0x7e, 0x82, 0x37, 0x2d, 0x26, 0xbd, 0x95, 0x72, 0x7d, 0x86, 0x9f, 0xc2, 0x4d, 0x45, - 0x43, 0xcd, 0x35, 0xbf, 0x0d, 0x73, 0x1b, 0x1f, 0x50, 0xbb, 0x1f, 0xf9, 0xa1, 0xbc, 0xaf, 0xc8, - 0x1d, 0x20, 0x8c, 0x86, 0x8f, 0x5d, 0x9b, 0xae, 0xd9, 0xb6, 0xdf, 0xf7, 0xa2, 0x9d, 0xe4, 0xd4, - 0x2f, 0x29, 0x6d, 0xa4, 0x39, 0x20, 0x81, 0x43, 0x5a, 0x99, 0x7f, 0x39, 0x05, 0xd5, 0x94, 0xc7, - 0xc3, 0x57, 0x31, 0xa4, 0x81, 0x9f, 0xb7, 0x21, 0xfc, 0x4e, 0x45, 0xc1, 0xe1, 0x36, 0x24, 0xa4, - 0x8f, 0x5d, 0xc6, 0x0d, 0x60, 0xce, 0x86, 0xa0, 0xa2, 0xa3, 0x96, 0x20, 0x35, 0x28, 0x3a, 0x34, - 0x88, 0xda, 0x62, 0x90, 0x53, 0xf5, 0x0a, 0x9f, 0x88, 0x06, 0x27, 0xa0, 0xa4, 0x73, 0x81, 0x03, - 0x1a, 0xd9, 0x6d, 0x63, 0x4a, 0x9c, 0x3b, 0x21, 0xb0, 0xc9, 0x09, 0x28, 0xe9, 0x43, 0xee, 0xa6, - 0xe2, 0xb3, 0xbf, 0x9b, 0x4a, 0xe7, 0x7c, 0x37, 0x91, 0x00, 0x2e, 0x31, 0xd6, 0xde, 0x0d, 0xdd, - 0xc7, 0x56, 0x44, 0x45, 0x63, 0xa1, 0x67, 0xfa, 0x69, 0xf4, 0x5c, 0x39, 0x39, 0xae, 0x5d, 0x6a, - 0x36, 0x6f, 0xe7, 0x51, 0x70, 0x18, 0x34, 0x69, 0xc2, 0x65, 0xd7, 0x63, 0xd4, 0xee, 0x87, 0x74, - 0xab, 0xe5, 0xf9, 0x21, 0xbd, 0xed, 0x33, 0x0e, 0xa7, 0xdc, 0xfc, 0x97, 0xd4, 0xa2, 0x5d, 0xde, - 0x1a, 0x26, 0x84, 0xc3, 0xdb, 0x9a, 0x7f, 0x5f, 0x80, 0x99, 0xb4, 0x93, 0x47, 0x18, 0x40, 0xbb, - 0xb1, 0xd9, 0x94, 0x3b, 0x53, 0x79, 0x0d, 0xef, 0x8c, 0xec, 0x3b, 0x4a, 0x98, 0x24, 0x42, 0x4a, - 0x68, 0x98, 0x52, 0x73, 0x86, 0x28, 0xf2, 0x4b, 0x50, 0x3c, 0xf0, 0x43, 0x9b, 0xaa, 0xb3, 0xa5, - 0xcf, 0xe0, 0x26, 0x27, 0xa2, 0xe4, 0x99, 0xff, 0x5a, 0x80, 0x94, 0x06, 0xf2, 0x1b, 0x30, 0xcb, - 0x75, 0xdc, 0x0d, 0xf7, 0x33, 0xa3, 0xa9, 0x8f, 0x3c, 0x1a, 0x8d, 0x54, 0xbf, 0xac, 0xf4, 0xcf, - 0x66, 0xc8, 0x98, 0xd5, 0x47, 0x7e, 0x0e, 0x2a, 0x96, 0xe3, 0x84, 0x94, 0x31, 0x2a, 0x4d, 0x4f, - 0xa5, 0x3e, 0x2b, 0xee, 0xca, 0x98, 0x88, 0x09, 0x9f, 0x1f, 0x43, 0xee, 0x55, 0xf3, 0x9d, 0xad, - 0xfc, 0x10, 0x7d, 0x0c, 0xb9, 0x12, 0x4e, 0x47, 0x2d, 0x61, 0x7e, 0x77, 0x0a, 0xb2, 0xba, 0x89, - 0x03, 0xf3, 0x9d, 0x70, 0x7f, 0x7d, 0xdd, 0xb2, 0xdb, 0x23, 0xf9, 0x7c, 0x97, 0xb8, 0xb3, 0x79, - 0x37, 0x8b, 0x80, 0x79, 0x48, 0xa5, 0xe5, 0x2e, 0x3d, 0x8a, 0xac, 0xfd, 0x51, 0xdc, 0xbe, 0x58, - 0x4b, 0x1a, 0x01, 0xf3, 0x90, 0xdc, 0x2d, 0xeb, 0x84, 0xfb, 0xf1, 0x21, 0xcf, 0xbb, 0x65, 0x77, - 0x13, 0x16, 0xa6, 0xe5, 0xf8, 0x14, 0x76, 0xc2, 0x7d, 0xa4, 0x56, 0x37, 0x4e, 0x28, 0xe8, 0x29, - 0xbc, 0xab, 0xe8, 0xa8, 0x25, 0x48, 0x00, 0xa4, 0x13, 0xcf, 0x9e, 0x0e, 0x1c, 0x94, 0x2d, 0xba, - 0x3e, 0x6c, 0x34, 0x5a, 0x28, 0x3d, 0xa0, 0x17, 0xb8, 0x6d, 0xbe, 0x3b, 0x80, 0x83, 0x43, 0xb0, - 0xc9, 0xb7, 0xe0, 0x4a, 0x27, 0xdc, 0x57, 0x86, 0x7c, 0x37, 0x74, 0x3d, 0xdb, 0x0d, 0x32, 0x99, - 0x84, 0x9a, 0xea, 0xee, 0x95, 0xbb, 0xc3, 0xc5, 0xf0, 0xb4, 0xf6, 0xe6, 0x6b, 0x30, 0x93, 0x8e, - 0x44, 0x3f, 0x27, 0x7a, 0x31, 0xff, 0xa3, 0x00, 0xa5, 0x2d, 0x2f, 0xe8, 0xff, 0x84, 0x24, 0xb5, - 0xfe, 0x6c, 0x0a, 0xa6, 0xb8, 0xeb, 0x45, 0xae, 0xc3, 0x54, 0x74, 0x14, 0xc8, 0xbb, 0x75, 0xb2, - 0xbe, 0x18, 0x1b, 0x9a, 0xbd, 0xa3, 0x80, 0x3e, 0x51, 0xff, 0xa2, 0x90, 0x20, 0x6f, 0x43, 0xc9, - 0xeb, 0xf7, 0x1e, 0x5a, 0x5d, 0x65, 0x94, 0x5e, 0x89, 0x5d, 0x8b, 0x1d, 0x41, 0x7d, 0x72, 0x5c, - 0x5b, 0xa4, 0x9e, 0xed, 0x3b, 0xae, 0xd7, 0x5a, 0x7d, 0xc4, 0x7c, 0x6f, 0x65, 0xa7, 0xdf, 0xdb, - 0xa7, 0x21, 0xaa, 0x56, 0xe4, 0xcb, 0x30, 0xbd, 0xef, 0xfb, 0x5d, 0x0e, 0x20, 0x4d, 0xd6, 0xbc, - 0x02, 0x98, 0xae, 0x4b, 0x32, 0xc6, 0x7c, 0xee, 0xc5, 0xb0, 0x28, 0xe4, 0x92, 0x53, 0x59, 0x2f, - 0xa6, 0x29, 0xa8, 0xa8, 0xb8, 0xa4, 0x07, 0xa5, 0x9e, 0x15, 0x70, 0xb9, 0xa2, 0x98, 0xb2, 0x8d, - 0x91, 0xfd, 0xd3, 0x95, 0x6d, 0x81, 0xb3, 0xe1, 0x45, 0xe1, 0x51, 0xa2, 0x4e, 0x12, 0x51, 0x29, - 0x21, 0x2e, 0x4c, 0x77, 0x5d, 0x16, 0x71, 0x7d, 0xa5, 0x31, 0x76, 0x05, 0xd7, 0xf7, 0xd0, 0xea, - 0xf6, 0x69, 0x32, 0x03, 0xf7, 0x24, 0x2c, 0xc6, 0xf8, 0x4b, 0x47, 0x50, 0x4d, 0xf5, 0x88, 0x2c, - 0xc8, 0x88, 0x5d, 0x6c, 0x5e, 0x11, 0xa4, 0x93, 0x3d, 0x28, 0x3e, 0xe6, 0x18, 0xca, 0xd8, 0x8c, - 0xd9, 0x13, 0x94, 0x60, 0x6f, 0x4e, 0xbc, 0x51, 0x78, 0xb3, 0xfc, 0xfd, 0x3f, 0xad, 0x5d, 0xf8, - 0xe8, 0x9f, 0xae, 0x5d, 0x30, 0xff, 0x6e, 0x12, 0x2a, 0x5a, 0xe4, 0xff, 0xf7, 0x4e, 0x09, 0x73, - 0x3b, 0xe5, 0xce, 0x78, 0xf3, 0x75, 0xa6, 0xed, 0xb2, 0x96, 0xdd, 0x2e, 0x33, 0xf5, 0x9f, 0x49, - 0x2d, 0xf5, 0x93, 0xe3, 0x9a, 0x91, 0x9d, 0x04, 0xb4, 0x0e, 0xb7, 0x29, 0x63, 0x56, 0x8b, 0x26, - 0xdb, 0xe0, 0xeb, 0x9f, 0xb7, 0x0d, 0x16, 0xd3, 0xdb, 0xa0, 0x32, 0x7c, 0x19, 0x3f, 0x9a, 0x84, - 0xf2, 0x36, 0x8d, 0x2c, 0xc7, 0x8a, 0x2c, 0xf2, 0x3b, 0x05, 0xa8, 0x5a, 0x9e, 0xe7, 0x47, 0x22, - 0x6e, 0x8f, 0xcd, 0xdb, 0xce, 0x48, 0xd3, 0x11, 0x83, 0xae, 0xac, 0x25, 0x80, 0x72, 0x4a, 0xf4, - 0xcd, 0x94, 0xe2, 0x60, 0x5a, 0x2f, 0x79, 0x1f, 0x4a, 0x5d, 0x6b, 0x9f, 0x76, 0x63, 0x6b, 0xb7, - 0x35, 0x5e, 0x0f, 0xee, 0x09, 0xac, 0xdc, 0x7a, 0x48, 0x22, 0x2a, 0x45, 0x4b, 0x6f, 0xc3, 0x42, - 0xbe, 0xa3, 0x4f, 0x33, 0xa3, 0x7c, 0x31, 0x52, 0x6a, 0x9e, 0xa6, 0xa9, 0xf9, 0x3f, 0x15, 0x80, - 0x1d, 0xdf, 0xa1, 0xcd, 0xc8, 0x8a, 0xfa, 0x8c, 0x2c, 0xc1, 0x84, 0xeb, 0xa8, 0xab, 0x08, 0x54, - 0x6f, 0x27, 0xb6, 0x1a, 0x38, 0xe1, 0x3a, 0x3a, 0xc5, 0x31, 0x71, 0x6a, 0x8a, 0xe3, 0x6b, 0x50, - 0x75, 0x5c, 0x16, 0x74, 0xad, 0xa3, 0x9d, 0x21, 0xbe, 0x40, 0x23, 0x61, 0x61, 0x5a, 0x8e, 0xbc, - 0xaa, 0xce, 0xaf, 0x3c, 0x28, 0x46, 0xee, 0xfc, 0x96, 0x79, 0xf7, 0x52, 0x67, 0xf8, 0x0d, 0x98, - 0x89, 0x53, 0x08, 0x42, 0x4b, 0x51, 0xb4, 0x8a, 0x4f, 0xfd, 0xcc, 0x5e, 0x8a, 0x87, 0x19, 0xc9, - 0x7c, 0x8a, 0xa3, 0xf4, 0x5c, 0x52, 0x1c, 0x0d, 0x58, 0x60, 0x91, 0x1f, 0x52, 0x27, 0x96, 0xd8, - 0x6a, 0x18, 0x24, 0x33, 0xd0, 0x85, 0x66, 0x8e, 0x8f, 0x03, 0x2d, 0xc8, 0x2e, 0x2c, 0xc6, 0x9d, - 0x48, 0x0f, 0xd0, 0xb8, 0x24, 0x90, 0xae, 0x2a, 0xa4, 0xc5, 0x77, 0x87, 0xc8, 0xe0, 0xd0, 0x96, - 0xe4, 0x1b, 0x30, 0x1b, 0x77, 0xb3, 0x69, 0xfb, 0x01, 0x35, 0x16, 0x05, 0x94, 0xf6, 0x96, 0xf7, - 0xd2, 0x4c, 0xcc, 0xca, 0x92, 0xaf, 0x40, 0x31, 0x68, 0x5b, 0x8c, 0xaa, 0x8c, 0x48, 0x1c, 0xf8, - 0x16, 0x77, 0x39, 0xf1, 0xc9, 0x71, 0xad, 0xc2, 0xd7, 0x4c, 0x7c, 0xa0, 0x14, 0x24, 0x37, 0x00, - 0xf6, 0xfd, 0xbe, 0xe7, 0x58, 0xe1, 0xd1, 0x56, 0x43, 0x84, 0x41, 0xa9, 0xc7, 0x98, 0xba, 0xe6, - 0x60, 0x4a, 0x8a, 0x5b, 0xdb, 0x9e, 0xb4, 0x3b, 0x2a, 0xb1, 0xa1, 0xad, 0xad, 0x36, 0x47, 0x8a, - 0x4f, 0xde, 0x83, 0x0a, 0x8b, 0xac, 0x30, 0xa2, 0xce, 0x5a, 0xa4, 0xb2, 0x1b, 0x3f, 0x9b, 0xf2, - 0x0b, 0xf5, 0xd3, 0x68, 0xb2, 0xa6, 0x3d, 0x1a, 0x59, 0xdc, 0x53, 0xdc, 0x73, 0x7b, 0x34, 0x71, - 0x49, 0x9a, 0x31, 0x08, 0x26, 0x78, 0xe4, 0x57, 0x01, 0x0e, 0x5c, 0xcf, 0x65, 0x6d, 0x81, 0x5e, - 0x7d, 0x6a, 0x74, 0x3d, 0xce, 0x4d, 0x8d, 0x82, 0x29, 0x44, 0x1e, 0x30, 0x05, 0xbe, 0xb3, 0xb5, - 0x6b, 0xcc, 0x88, 0x51, 0xea, 0x80, 0x69, 0x97, 0x13, 0x51, 0xf2, 0xc8, 0x75, 0x28, 0x3b, 0x16, - 0xed, 0xf9, 0x1e, 0x75, 0x8c, 0xd9, 0x24, 0x69, 0xd1, 0x50, 0x34, 0xd4, 0x5c, 0xf2, 0x1d, 0x28, - 0xb9, 0xc2, 0x5f, 0x34, 0xe6, 0x44, 0x57, 0xbf, 0x31, 0xda, 0x8d, 0x22, 0x20, 0xea, 0xc0, 0xcd, - 0x95, 0xfc, 0x1b, 0x15, 0x2c, 0xb1, 0x61, 0xda, 0xef, 0x47, 0x42, 0xc3, 0xbc, 0xd0, 0x30, 0x5a, - 0x92, 0xe6, 0xbe, 0xc4, 0x90, 0x8f, 0x63, 0xea, 0x03, 0x63, 0x64, 0x3e, 0x5e, 0xbb, 0xed, 0x76, - 0x9d, 0x90, 0x7a, 0xc6, 0x82, 0x88, 0xc7, 0xc4, 0x78, 0xd7, 0x15, 0x0d, 0x35, 0x97, 0xfc, 0x02, - 0xcc, 0xfa, 0xfd, 0x48, 0xec, 0x1b, 0xbe, 0xed, 0x98, 0x71, 0x51, 0x88, 0x5f, 0xe4, 0xbb, 0xf8, - 0x7e, 0x9a, 0x81, 0x59, 0x39, 0x73, 0x0e, 0x66, 0xd2, 0x2f, 0xca, 0xe6, 0x1f, 0x4d, 0x40, 0xdc, - 0x8f, 0x9f, 0x04, 0x57, 0x9b, 0x98, 0x50, 0x0a, 0x29, 0xeb, 0x77, 0x23, 0x65, 0xa9, 0xc5, 0x5a, - 0xa3, 0xa0, 0xa0, 0xe2, 0x98, 0x87, 0x30, 0xcb, 0x7b, 0xdb, 0xed, 0xd2, 0x6e, 0x33, 0xa2, 0x01, - 0x23, 0x07, 0x50, 0x64, 0xfc, 0x0f, 0x35, 0x27, 0xa3, 0xbd, 0x55, 0xc5, 0x76, 0x8a, 0x43, 0x26, - 0xfb, 0x5d, 0x28, 0x40, 0x09, 0x6f, 0x7e, 0x6f, 0x02, 0x2a, 0x7a, 0x9e, 0xce, 0x90, 0x5e, 0x7f, - 0x19, 0xa6, 0x1d, 0x7a, 0x60, 0xf1, 0xd1, 0xa8, 0xe7, 0x23, 0xbe, 0xad, 0x1a, 0x92, 0x84, 0x31, - 0x8f, 0xd4, 0xe2, 0x9b, 0x50, 0x0e, 0x59, 0xa4, 0xbc, 0xd2, 0x8e, 0x26, 0xe9, 0x40, 0x45, 0xfc, - 0xb1, 0x19, 0x3f, 0x75, 0x8f, 0xba, 0xee, 0x0f, 0x63, 0x14, 0x99, 0x48, 0xd0, 0x9f, 0x98, 0xe0, - 0xe7, 0x9e, 0xa8, 0x8b, 0x67, 0x79, 0xa2, 0x36, 0x37, 0x81, 0x1b, 0x86, 0x5b, 0xeb, 0xe4, 0x2d, - 0x28, 0x33, 0xb5, 0x75, 0xd5, 0xbc, 0x7c, 0x31, 0x0e, 0xa1, 0xe3, 0x2d, 0xfd, 0xe4, 0xb8, 0x36, - 0x2b, 0x84, 0x63, 0x02, 0xea, 0x26, 0xe6, 0x2a, 0x54, 0x53, 0x4f, 0x7a, 0x7c, 0x86, 0xb9, 0xbf, - 0x92, 0x9f, 0xe1, 0x86, 0x15, 0x59, 0x28, 0x38, 0xe6, 0x93, 0x09, 0x58, 0x40, 0xca, 0xfc, 0x7e, - 0x68, 0xd3, 0x74, 0x5a, 0xd7, 0xb2, 0x53, 0x2f, 0x3d, 0xda, 0xc5, 0x59, 0x13, 0x54, 0x54, 0x5c, - 0x7e, 0xdd, 0xf4, 0x68, 0xd8, 0xd2, 0x87, 0x4d, 0x2d, 0x92, 0xbe, 0x6e, 0xb6, 0xd3, 0x4c, 0xcc, - 0xca, 0x92, 0x57, 0xa1, 0xdc, 0xb3, 0x3c, 0xf7, 0x80, 0xb2, 0x28, 0x9f, 0x6f, 0xd9, 0x56, 0x74, - 0xd4, 0x12, 0xe4, 0x16, 0x5c, 0x64, 0x34, 0xba, 0x7f, 0xe8, 0xd1, 0x10, 0xe9, 0x01, 0x0d, 0x45, - 0x1a, 0x7e, 0x4a, 0x98, 0xcc, 0x17, 0x55, 0xb3, 0x8b, 0xcd, 0xbc, 0x00, 0x0e, 0xb6, 0x11, 0x57, - 0x77, 0xdf, 0xb6, 0x29, 0x63, 0xeb, 0xbe, 0xe7, 0xb8, 0xba, 0x9a, 0x21, 0x7d, 0x75, 0xe7, 0xf8, - 0x38, 0xd0, 0x82, 0xa3, 0x1c, 0x58, 0x6e, 0xb7, 0x1f, 0xd2, 0x04, 0xa5, 0x94, 0x45, 0xd9, 0xcc, - 0xf1, 0x71, 0xa0, 0x85, 0xf9, 0x2f, 0x05, 0x98, 0x45, 0x1a, 0x85, 0x47, 0x7a, 0x52, 0x6a, 0x50, - 0xec, 0xba, 0x3d, 0x57, 0xa6, 0x8e, 0x8a, 0x72, 0x27, 0xdf, 0xe3, 0x04, 0x94, 0x74, 0xd2, 0x80, - 0x6a, 0xc8, 0x5b, 0xec, 0xfa, 0x5d, 0xd7, 0x8e, 0x27, 0xdc, 0x8c, 0xbd, 0x31, 0x4c, 0x58, 0x4f, - 0xb2, 0x9f, 0x98, 0x6e, 0x46, 0x3c, 0x98, 0xde, 0x97, 0xef, 0x7a, 0xea, 0x19, 0x6a, 0x34, 0x63, - 0xaf, 0xde, 0x06, 0x45, 0x0e, 0x26, 0x7e, 0x28, 0x7c, 0x92, 0xfc, 0x89, 0xb1, 0x12, 0xf3, 0xfb, - 0x05, 0x80, 0xa4, 0xc0, 0x80, 0x74, 0xa0, 0xcc, 0x6e, 0xd6, 0xfb, 0x76, 0x47, 0xe7, 0xc8, 0x46, - 0x7c, 0x4a, 0x51, 0x20, 0xc9, 0xce, 0x89, 0x29, 0xa8, 0x15, 0x7c, 0xde, 0xf3, 0xf3, 0x5f, 0x4d, - 0x82, 0x6e, 0xc5, 0xf7, 0x24, 0xf5, 0x9c, 0xc0, 0x77, 0xbd, 0x28, 0xff, 0xc8, 0xb9, 0xa1, 0xe8, - 0xa8, 0x25, 0xf8, 0x31, 0xd9, 0x97, 0x83, 0x98, 0xc8, 0x1e, 0x13, 0xd5, 0x07, 0xc5, 0xe5, 0x72, - 0x21, 0x6d, 0x25, 0xef, 0x9b, 0x5a, 0x0e, 0x05, 0x15, 0x15, 0x97, 0xdf, 0x8e, 0x71, 0x92, 0x58, - 0x6d, 0x6d, 0x71, 0x3b, 0xc6, 0xf9, 0x64, 0xd4, 0x5c, 0xd2, 0x86, 0x79, 0x4b, 0xec, 0xc8, 0x24, - 0xf1, 0xfd, 0x54, 0x39, 0xfc, 0xe4, 0x71, 0x3b, 0x8b, 0x82, 0x79, 0x58, 0xae, 0x89, 0x25, 0xcd, - 0x9f, 0x3e, 0x95, 0xaf, 0x35, 0x35, 0xb3, 0x28, 0x98, 0x87, 0xe5, 0x8e, 0x61, 0xe8, 0x77, 0xe9, - 0x1a, 0xee, 0x28, 0x07, 0x54, 0x3b, 0x86, 0x28, 0xc9, 0x18, 0xf3, 0xcd, 0xdf, 0x2b, 0xc0, 0x5c, - 0xd3, 0x0e, 0xdd, 0x20, 0xd2, 0x26, 0x6b, 0x47, 0x54, 0x25, 0x44, 0x16, 0x77, 0xd9, 0xd4, 0x9e, - 0x7a, 0xe9, 0x94, 0x1c, 0xa2, 0x14, 0xca, 0x14, 0x2d, 0x48, 0x12, 0x26, 0x10, 0x22, 0xd2, 0x17, - 0x46, 0x31, 0xbf, 0xb6, 0x4d, 0x41, 0x45, 0xc5, 0x35, 0x7f, 0x50, 0x80, 0xb2, 0x7e, 0xb1, 0xfb, - 0x12, 0x14, 0xc5, 0x43, 0x90, 0xda, 0x3b, 0xfa, 0x0e, 0x5c, 0xe7, 0x44, 0x94, 0x3c, 0x2e, 0x24, - 0xbc, 0x50, 0x05, 0x9c, 0xba, 0x28, 0xad, 0x30, 0x42, 0xc9, 0xe3, 0x9b, 0x96, 0x7a, 0x8e, 0xda, - 0x2f, 0x7a, 0xd3, 0x6e, 0x78, 0x0e, 0x72, 0xba, 0x78, 0xcc, 0xf6, 0xc3, 0x9e, 0x15, 0xe5, 0xf3, - 0x10, 0x9b, 0x82, 0x8a, 0x8a, 0x6b, 0xbe, 0x03, 0xf3, 0xcd, 0x3e, 0x0b, 0xa8, 0xa7, 0xc3, 0x8e, - 0xa7, 0x7b, 0xc7, 0x37, 0x67, 0xa1, 0x9a, 0xaa, 0xfe, 0x33, 0xff, 0xeb, 0x0a, 0xe8, 0x77, 0xed, - 0x9f, 0xbe, 0x8e, 0x8f, 0x14, 0x3a, 0xda, 0xda, 0x91, 0x2f, 0x8e, 0xef, 0xc8, 0xeb, 0x75, 0xcf, - 0x39, 0xf3, 0xad, 0xc4, 0x99, 0x2f, 0x9d, 0x83, 0x33, 0xaf, 0x4f, 0xe2, 0x80, 0x43, 0xff, 0xfb, - 0x05, 0x98, 0xf1, 0x7c, 0x87, 0xc6, 0xe7, 0xdd, 0x98, 0x16, 0x0e, 0xe4, 0xfd, 0xb1, 0x26, 0x71, - 0x65, 0x27, 0x85, 0x28, 0x93, 0x2c, 0x3a, 0x13, 0x90, 0x66, 0x61, 0x46, 0x35, 0xd9, 0x84, 0xb2, - 0x75, 0xc0, 0x23, 0xb0, 0xe8, 0x48, 0x3d, 0xd0, 0x5f, 0x1d, 0x66, 0x01, 0xd6, 0x94, 0x8c, 0x34, - 0xae, 0xf1, 0x17, 0xea, 0xb6, 0xfc, 0x76, 0xea, 0xa9, 0x44, 0x8f, 0x08, 0x51, 0x47, 0xbd, 0x9d, - 0xe2, 0x6c, 0x51, 0xca, 0xaf, 0x51, 0x14, 0xd4, 0x0a, 0xb8, 0xbb, 0x2e, 0x63, 0x3c, 0x11, 0xe0, - 0x96, 0xa5, 0xbb, 0x2e, 0xe3, 0x3f, 0x54, 0x1c, 0xd2, 0x8a, 0xbd, 0xf3, 0xaa, 0x98, 0xdc, 0xfa, - 0xc8, 0x11, 0x8b, 0x76, 0xf8, 0x87, 0xbb, 0xe7, 0xe4, 0x4e, 0xda, 0x88, 0xce, 0x9c, 0xc5, 0x88, - 0xce, 0x9e, 0x6a, 0x40, 0x5b, 0x50, 0x62, 0xc2, 0x44, 0x8b, 0xc0, 0xb6, 0x7a, 0x63, 0x7d, 0xb4, - 0x1b, 0x3e, 0x63, 0xe5, 0xe5, 0xec, 0x48, 0x1a, 0x2a, 0x78, 0xe2, 0x43, 0x39, 0x54, 0x0e, 0xac, - 0x8a, 0x8d, 0x47, 0xcb, 0xcb, 0xe7, 0xbd, 0x60, 0xb9, 0x3f, 0x62, 0x2a, 0x6a, 0x25, 0xe4, 0x3d, - 0x98, 0x74, 0xac, 0x96, 0x8a, 0x92, 0xbf, 0x39, 0x72, 0x29, 0x43, 0xac, 0x46, 0x94, 0xdd, 0x35, - 0xd6, 0x6e, 0x21, 0x47, 0x25, 0x1d, 0x98, 0x66, 0xd2, 0x62, 0x1b, 0x0b, 0x63, 0x54, 0xb3, 0xe5, - 0xac, 0xbe, 0x8c, 0x9b, 0x14, 0x11, 0x63, 0x0d, 0x64, 0x03, 0xa6, 0x1f, 0xfb, 0xdd, 0x7e, 0x4f, - 0x85, 0xd7, 0xd5, 0x1b, 0x4b, 0xc3, 0x56, 0xfb, 0xa1, 0x10, 0x49, 0x8c, 0x80, 0xfc, 0x66, 0x18, - 0xb7, 0x25, 0xbf, 0x55, 0x80, 0x39, 0x7e, 0x74, 0xf4, 0x3e, 0x60, 0x06, 0x19, 0x63, 0xa7, 0x3e, - 0x60, 0x34, 0x4c, 0x76, 0xd8, 0x0b, 0x4a, 0xed, 0xdc, 0x56, 0x46, 0x03, 0xe6, 0x34, 0x92, 0x00, - 0xca, 0xcc, 0x75, 0xa8, 0x6d, 0x85, 0xcc, 0xb8, 0x74, 0x6e, 0xda, 0x13, 0xc7, 0x52, 0x61, 0xa3, - 0xd6, 0x42, 0x7e, 0x5b, 0x54, 0x20, 0xaa, 0x1a, 0x5c, 0x55, 0x17, 0xbd, 0x78, 0x9e, 0x75, 0xd1, - 0x97, 0x64, 0xf9, 0x61, 0x46, 0x03, 0xe6, 0x55, 0x92, 0xfb, 0x70, 0x99, 0x87, 0x63, 0x8f, 0x69, - 0x83, 0x5a, 0x4e, 0xd7, 0xf5, 0x68, 0x93, 0xda, 0xbe, 0xe7, 0x30, 0xe3, 0xb2, 0x78, 0x39, 0x79, - 0xf1, 0xe4, 0xb8, 0x76, 0x79, 0x6d, 0x98, 0x00, 0x0e, 0x6f, 0x47, 0x3e, 0x84, 0xd9, 0x30, 0x1d, - 0x94, 0x18, 0x2f, 0x8c, 0xf1, 0x6c, 0x9f, 0x09, 0x6f, 0x64, 0xfa, 0x26, 0x43, 0xc2, 0xac, 0x2e, - 0xf2, 0x3a, 0x54, 0x03, 0x65, 0xa9, 0x5c, 0xd6, 0x33, 0xae, 0x88, 0x31, 0x88, 0x1b, 0x75, 0x37, - 0x21, 0x63, 0x5a, 0x86, 0x3c, 0x80, 0x6a, 0xe4, 0x77, 0x69, 0xa8, 0x9e, 0x18, 0x0c, 0xb1, 0xf8, - 0xcb, 0xc3, 0x76, 0xf2, 0x9e, 0x16, 0x4b, 0x12, 0xd8, 0x09, 0x8d, 0x61, 0x1a, 0x87, 0x07, 0xb7, - 0xcc, 0x6e, 0x53, 0xa7, 0xdf, 0xa5, 0xa1, 0x88, 0xe4, 0x5f, 0xcc, 0x06, 0xb7, 0xcd, 0x34, 0x13, - 0xb3, 0xb2, 0x3c, 0x5c, 0x0d, 0x42, 0xd7, 0x0f, 0xdd, 0xe8, 0x68, 0xbd, 0x6b, 0x31, 0x26, 0x00, - 0x96, 0x04, 0x80, 0x0e, 0x57, 0x77, 0xf3, 0x02, 0x38, 0xd8, 0x86, 0xc7, 0x04, 0x31, 0xd1, 0xf8, - 0x82, 0x88, 0x09, 0x85, 0x59, 0x8a, 0xdb, 0xa2, 0xe6, 0x9e, 0x52, 0xc4, 0x74, 0x75, 0x94, 0x22, - 0x26, 0xe2, 0xc0, 0x55, 0xab, 0x1f, 0xf9, 0x3d, 0x4e, 0xc8, 0x36, 0xd9, 0xf3, 0x3b, 0xd4, 0x33, - 0xae, 0x89, 0xbb, 0xea, 0xda, 0xc9, 0x71, 0xed, 0xea, 0xda, 0x67, 0xc8, 0xe1, 0x67, 0xa2, 0x90, - 0x1e, 0x94, 0xa9, 0x2a, 0xc4, 0x32, 0xbe, 0x38, 0xc6, 0x25, 0x91, 0xad, 0xe6, 0x92, 0x13, 0x14, - 0xd3, 0x50, 0xab, 0x20, 0x7b, 0x50, 0x6d, 0xfb, 0x2c, 0x5a, 0xeb, 0xba, 0x16, 0xa3, 0xcc, 0x78, - 0x49, 0xec, 0x93, 0xa1, 0xf7, 0xdb, 0xed, 0x58, 0x2c, 0xd9, 0x26, 0xb7, 0x93, 0x96, 0x98, 0x86, - 0x21, 0x54, 0x04, 0x48, 0x7d, 0xb1, 0x6a, 0xbe, 0x17, 0xd1, 0x0f, 0x22, 0x63, 0x59, 0x8c, 0xe5, - 0x95, 0x61, 0xc8, 0xbb, 0xbe, 0xd3, 0xcc, 0x4a, 0xcb, 0x53, 0x9e, 0x23, 0x62, 0x1e, 0x93, 0xbc, - 0x01, 0x33, 0x81, 0xef, 0x34, 0x03, 0x6a, 0xef, 0x5a, 0x91, 0xdd, 0x36, 0x6a, 0xd9, 0x07, 0x92, - 0xdd, 0x14, 0x0f, 0x33, 0x92, 0x4b, 0xef, 0xc0, 0xc5, 0x01, 0x7f, 0xea, 0xa9, 0x5e, 0x93, 0xfe, - 0xbc, 0x00, 0x69, 0x77, 0xf6, 0xdc, 0xfd, 0xfe, 0x5b, 0x70, 0x51, 0xfd, 0xae, 0x89, 0x5f, 0xb6, - 0xdd, 0xbe, 0xae, 0x04, 0x4e, 0xa5, 0x76, 0x30, 0x2f, 0x80, 0x83, 0x6d, 0xcc, 0xbf, 0x28, 0xc0, - 0x6c, 0xc6, 0x7c, 0x9f, 0x7b, 0x54, 0xb8, 0x09, 0xa4, 0xe7, 0x86, 0xa1, 0x1f, 0xca, 0x3b, 0x70, - 0x9b, 0xef, 0x65, 0xa6, 0x0a, 0x8a, 0x45, 0x21, 0xca, 0xf6, 0x00, 0x17, 0x87, 0xb4, 0x30, 0xff, - 0xba, 0x00, 0x49, 0xee, 0x50, 0x57, 0x5f, 0x15, 0x4e, 0xad, 0xbe, 0x7a, 0x15, 0xca, 0x8f, 0x98, - 0xef, 0xed, 0x26, 0x35, 0x5a, 0x7a, 0x42, 0xef, 0x34, 0xef, 0xef, 0x08, 0x49, 0x2d, 0x21, 0xa4, - 0xdf, 0xdf, 0x74, 0xbb, 0xd1, 0x60, 0x25, 0xd3, 0x9d, 0x5f, 0x92, 0x74, 0xd4, 0x12, 0x64, 0x15, - 0x2a, 0x3a, 0x5d, 0xad, 0xc2, 0x49, 0x3d, 0x09, 0x3a, 0x57, 0x8b, 0x89, 0x8c, 0xf9, 0xc3, 0x09, - 0x28, 0xc7, 0xb9, 0x5e, 0xf2, 0x6b, 0x29, 0x67, 0x59, 0x4e, 0xf0, 0x57, 0xce, 0xf6, 0x88, 0x72, - 0x7f, 0xff, 0x11, 0xb5, 0x23, 0xee, 0x11, 0x27, 0xc9, 0xd1, 0x84, 0x96, 0xf2, 0x90, 0x6d, 0x98, - 0x62, 0x01, 0xb5, 0xc7, 0xfa, 0x8d, 0x99, 0x4e, 0x4d, 0x07, 0xd4, 0x4e, 0x26, 0x98, 0x7f, 0xa1, - 0x00, 0x27, 0x1d, 0x28, 0x31, 0xf1, 0x58, 0xaa, 0x02, 0xcf, 0xf5, 0x31, 0x33, 0xe0, 0x1c, 0x2a, - 0x5d, 0x1d, 0xc0, 0xbf, 0x51, 0xa9, 0x30, 0x3f, 0x29, 0xc0, 0x4c, 0x2c, 0x7a, 0xcf, 0x65, 0x11, - 0xf9, 0xf6, 0xc0, 0x24, 0xae, 0x9c, 0x6d, 0x12, 0x79, 0x6b, 0x31, 0x85, 0x7a, 0x81, 0x63, 0x4a, - 0x6a, 0x02, 0xf7, 0xa1, 0xe8, 0x8a, 0xaa, 0xea, 0x71, 0x5e, 0x1f, 0xe2, 0xfe, 0x26, 0x91, 0x83, - 0xac, 0xaa, 0x96, 0xd0, 0xe6, 0xdf, 0x5c, 0x4a, 0x86, 0xc4, 0xa7, 0x95, 0x78, 0x50, 0x89, 0x0f, - 0x78, 0xfc, 0xaa, 0xf0, 0xd6, 0x58, 0x41, 0x61, 0xb2, 0x29, 0x63, 0x0a, 0xc3, 0x44, 0x05, 0xb9, - 0x01, 0x40, 0xb9, 0x65, 0x93, 0xb9, 0xbb, 0x89, 0x6c, 0xd2, 0x7d, 0x43, 0x73, 0x30, 0x25, 0xf5, - 0xfc, 0x13, 0x0e, 0xc3, 0xaf, 0xe8, 0xa9, 0x67, 0x72, 0x45, 0x5f, 0x3d, 0xf7, 0x2b, 0xfa, 0xa5, - 0x67, 0x7f, 0x45, 0xa7, 0x02, 0x92, 0xe2, 0x18, 0x01, 0xc9, 0x87, 0xb0, 0x28, 0xff, 0x5c, 0xef, - 0x5a, 0x6e, 0x4f, 0xef, 0x17, 0x55, 0x46, 0xf5, 0xe5, 0xa1, 0x17, 0x33, 0x0d, 0x99, 0xcb, 0x22, - 0xea, 0x45, 0x0f, 0x93, 0x96, 0xc9, 0x1b, 0xfc, 0xc3, 0x21, 0x70, 0x38, 0x54, 0x49, 0xde, 0x83, - 0x9d, 0x3e, 0x83, 0x07, 0xfb, 0x83, 0x02, 0x5c, 0xb6, 0x86, 0xfd, 0xd8, 0x4a, 0xe5, 0x31, 0xee, - 0x8c, 0x15, 0x4f, 0x64, 0x10, 0x55, 0x3c, 0x30, 0x8c, 0x85, 0xc3, 0xfb, 0x40, 0x5e, 0x4e, 0x42, - 0xd2, 0x8a, 0xd8, 0x54, 0xc3, 0x83, 0xc9, 0xef, 0xe6, 0x53, 0x41, 0x20, 0x66, 0xbb, 0x39, 0xb6, - 0xc1, 0x3e, 0x87, 0x74, 0x50, 0x75, 0x8c, 0x74, 0x50, 0x2e, 0xbc, 0x98, 0x39, 0xa7, 0xf0, 0xc2, - 0x83, 0x05, 0xb7, 0x67, 0xb5, 0xe8, 0x6e, 0xbf, 0xdb, 0x95, 0x19, 0x70, 0x66, 0xcc, 0x0a, 0xec, - 0xa1, 0xb5, 0xaf, 0x3c, 0xdc, 0xeb, 0xca, 0xfb, 0x51, 0xbf, 0x65, 0x25, 0x6f, 0x4d, 0x5b, 0x39, - 0x24, 0x1c, 0xc0, 0xe6, 0xdb, 0x92, 0xbb, 0xad, 0x3b, 0x34, 0xe2, 0xb3, 0x2d, 0x32, 0x25, 0xea, - 0x47, 0xa5, 0xb7, 0x13, 0x32, 0xa6, 0x65, 0xc8, 0x5d, 0xa8, 0x38, 0x1e, 0x53, 0x2f, 0x4d, 0xf3, - 0xc2, 0x4a, 0xbd, 0xc6, 0x6d, 0x5b, 0x63, 0xa7, 0xa9, 0xdf, 0x98, 0xae, 0x0e, 0xfe, 0x6a, 0x7e, - 0x45, 0xf3, 0x31, 0x69, 0x4f, 0xb6, 0x05, 0x98, 0x2a, 0x04, 0x97, 0xa9, 0x8d, 0x6b, 0xa7, 0x78, - 0xc8, 0x8d, 0x9d, 0xb8, 0x6e, 0x7d, 0x56, 0xa9, 0x53, 0xe5, 0xdd, 0x09, 0x02, 0x79, 0x05, 0x4a, - 0xbe, 0xb7, 0xf1, 0x81, 0x1b, 0x19, 0x17, 0xb3, 0x19, 0xf0, 0xfb, 0x82, 0x8a, 0x8a, 0x4b, 0x1e, - 0xc0, 0x95, 0x28, 0xea, 0xaa, 0xd0, 0x76, 0xed, 0x20, 0xa2, 0x61, 0x5c, 0xaf, 0x21, 0x0a, 0x76, - 0x8a, 0xf5, 0x2f, 0x9c, 0x1c, 0xd7, 0xae, 0xec, 0xed, 0xdd, 0x1b, 0x26, 0x82, 0xa7, 0xb5, 0x3d, - 0x3d, 0xe8, 0xbe, 0x34, 0x62, 0xd0, 0x9d, 0x8e, 0xf3, 0x16, 0x3f, 0x33, 0xce, 0x1b, 0x88, 0x4b, - 0x2f, 0x3f, 0x45, 0x5c, 0xfa, 0x9e, 0xa8, 0x4a, 0xb9, 0xb5, 0xae, 0x62, 0xfa, 0x37, 0x47, 0x4b, - 0x25, 0x72, 0x04, 0xf9, 0x36, 0x29, 0xfe, 0x44, 0x89, 0x49, 0x76, 0x61, 0x31, 0xf0, 0x9d, 0x81, - 0xb0, 0x56, 0x04, 0xf1, 0xa9, 0x7a, 0xa6, 0xdd, 0x21, 0x32, 0x38, 0xb4, 0xa5, 0xb0, 0xa5, 0x09, - 0xdd, 0x30, 0xc4, 0xc4, 0x48, 0x5b, 0x9a, 0x90, 0x31, 0x2d, 0x93, 0x8f, 0xf2, 0x5e, 0x7c, 0x66, - 0x51, 0xde, 0xd2, 0x73, 0x88, 0xf2, 0xbe, 0xf0, 0xfc, 0xa2, 0xbc, 0x4f, 0xcb, 0x30, 0x97, 0xf5, - 0x5f, 0x93, 0x82, 0xb0, 0xc2, 0x59, 0x0b, 0xc2, 0x32, 0x15, 0x5b, 0x13, 0xcf, 0xb4, 0x62, 0x6b, - 0xf2, 0xdc, 0x2b, 0xb6, 0x52, 0x95, 0x69, 0x53, 0x9f, 0x53, 0x99, 0xb6, 0x06, 0xf3, 0xb6, 0xdf, - 0x0b, 0xc4, 0x2f, 0x47, 0x54, 0x7d, 0x92, 0xac, 0x21, 0xd0, 0xcf, 0x9d, 0xeb, 0x59, 0x36, 0xe6, - 0xe5, 0xc9, 0xaf, 0x43, 0xd1, 0x13, 0x0d, 0x4b, 0x63, 0x94, 0xc4, 0x66, 0x17, 0x4c, 0x5c, 0x94, - 0xaa, 0x2a, 0x35, 0x4e, 0x9b, 0x16, 0x05, 0xed, 0x49, 0xfc, 0x07, 0x4a, 0xa5, 0xdc, 0xe3, 0x98, - 0xcf, 0xd6, 0x23, 0x32, 0xa3, 0x22, 0x3a, 0xf2, 0xcb, 0xe7, 0xd1, 0x91, 0x6c, 0xf1, 0xa3, 0xea, - 0x52, 0xf2, 0x14, 0x9c, 0xe5, 0x62, 0xbe, 0x27, 0x24, 0x84, 0x17, 0x82, 0x61, 0xfe, 0x18, 0x53, - 0xcf, 0x4b, 0x9f, 0xe5, 0x15, 0x2e, 0x2b, 0x2d, 0x2f, 0x0c, 0xf5, 0xe8, 0x18, 0x9e, 0x82, 0x9c, - 0xae, 0x7f, 0x2b, 0x3f, 0xab, 0xfa, 0xb7, 0xa5, 0x23, 0x59, 0x97, 0x7b, 0x6a, 0x49, 0xef, 0x83, - 0x6c, 0x99, 0xfd, 0x3b, 0x23, 0xfe, 0x87, 0x2a, 0x71, 0xe5, 0x6f, 0xba, 0x9c, 0xf8, 0x37, 0x0b, - 0xb0, 0x38, 0x6c, 0x59, 0x86, 0xf4, 0xa2, 0x99, 0xed, 0xc5, 0x78, 0x71, 0x5b, 0xda, 0xc6, 0xfc, - 0x5b, 0x31, 0x15, 0x25, 0x46, 0x34, 0xf8, 0xe9, 0x13, 0xf2, 0x48, 0x4f, 0xc8, 0x99, 0x9f, 0x4a, - 0x17, 0x9f, 0xe3, 0x4f, 0xa5, 0x4b, 0x23, 0xfc, 0x54, 0x7a, 0xfa, 0x79, 0xfe, 0x54, 0xba, 0x7c, - 0xc6, 0x9f, 0x4a, 0x57, 0x9e, 0xfd, 0x4f, 0xa5, 0x3f, 0x2d, 0xc0, 0x42, 0xbe, 0x72, 0xfb, 0x39, - 0x64, 0xcb, 0x3a, 0x99, 0x6c, 0xd9, 0xd6, 0x58, 0xc6, 0x5c, 0x57, 0x8b, 0x9f, 0x92, 0x35, 0x33, - 0x7f, 0x5c, 0x80, 0x81, 0xea, 0xf4, 0xe7, 0x90, 0xd0, 0x7a, 0x94, 0x4d, 0x68, 0x6d, 0x9c, 0xcb, - 0x20, 0x4f, 0x49, 0x6c, 0xfd, 0xf7, 0x90, 0x21, 0xfe, 0x9f, 0x24, 0xb8, 0x32, 0xa6, 0x6d, 0xe2, - 0xd9, 0x9b, 0xb6, 0xfa, 0xca, 0xc7, 0x9f, 0x2e, 0x5f, 0xf8, 0xe4, 0xd3, 0xe5, 0x0b, 0x3f, 0xfa, - 0x74, 0xf9, 0xc2, 0x47, 0x27, 0xcb, 0x85, 0x8f, 0x4f, 0x96, 0x0b, 0x9f, 0x9c, 0x2c, 0x17, 0x7e, - 0x74, 0xb2, 0x5c, 0xf8, 0xf1, 0xc9, 0x72, 0xe1, 0x0f, 0xff, 0x79, 0xf9, 0xc2, 0xaf, 0x94, 0x63, - 0xdc, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0x4a, 0x1b, 0x70, 0xfc, 0xe9, 0x4d, 0x00, 0x00, + // 4879 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x7c, 0x4d, 0x6c, 0x1c, 0x57, + 0x72, 0xbf, 0x86, 0xe4, 0x0c, 0x67, 0x6a, 0x48, 0x91, 0x7a, 0xa2, 0xa4, 0x36, 0x2d, 0x73, 0xb4, + 0x6d, 0xd8, 0x7f, 0xed, 0x3f, 0x36, 0xb9, 0x96, 0x76, 0x13, 0xaf, 0x37, 0xb6, 0x97, 0xc3, 0x0f, + 0x89, 0x92, 0x48, 0x31, 0x35, 0x94, 0x9c, 0x8d, 0x17, 0xd9, 0x34, 0xbb, 0x1f, 0x67, 0x5a, 0x9c, + 0xe9, 0x6e, 0xf7, 0xeb, 0x11, 0x4d, 0x38, 0x40, 0x9c, 0x20, 0x41, 0x12, 0x04, 0x0b, 0x24, 0x97, + 0xcd, 0x22, 0x7b, 0x09, 0x72, 0x48, 0x2e, 0xb9, 0x04, 0xc8, 0x29, 0x87, 0x3d, 0x04, 0x39, 0x18, + 0xb9, 0xc4, 0xb7, 0xec, 0x21, 0x20, 0xd6, 0x0c, 0x10, 0x24, 0x48, 0x80, 0x20, 0xb9, 0x04, 0xd1, + 0x29, 0x78, 0x1f, 0xfd, 0xfa, 0x63, 0x9a, 0x36, 0x35, 0x43, 0x29, 0x08, 0x76, 0x4f, 0x62, 0x57, + 0xd5, 0xfb, 0xd5, 0xeb, 0xd7, 0xf5, 0xea, 0x55, 0xd5, 0xab, 0x11, 0xac, 0xb4, 0xdd, 0xa8, 0xd3, + 0xdf, 0x5d, 0xb4, 0xfd, 0xde, 0x92, 0x15, 0xb6, 0xfd, 0x20, 0xf4, 0x1f, 0x89, 0x3f, 0x96, 0x82, + 0xfd, 0xf6, 0x92, 0x15, 0xb8, 0x6c, 0xe9, 0xc0, 0x0f, 0xf7, 0xf7, 0xba, 0xfe, 0xc1, 0xd2, 0xe3, + 0x37, 0xac, 0x6e, 0xd0, 0xb1, 0xde, 0x58, 0x6a, 0x53, 0x8f, 0x86, 0x56, 0x44, 0x9d, 0xc5, 0x20, + 0xf4, 0x23, 0x9f, 0xdc, 0x4c, 0x40, 0x16, 0x63, 0x10, 0xf1, 0xc7, 0x62, 0xb0, 0xdf, 0x5e, 0xe4, + 0x20, 0x8b, 0x31, 0xc8, 0x62, 0x0c, 0x32, 0xff, 0x7a, 0x4a, 0x73, 0xdb, 0xe7, 0x0a, 0x39, 0xd6, + 0x6e, 0x7f, 0x4f, 0x3c, 0x89, 0x07, 0xf1, 0x97, 0xd4, 0x31, 0x6f, 0xee, 0xbf, 0xc9, 0x16, 0x5d, + 0x9f, 0x4f, 0x69, 0xc9, 0xf6, 0x43, 0xba, 0xf4, 0x78, 0x60, 0x1e, 0xf3, 0x5f, 0x4d, 0x64, 0x7a, + 0x96, 0xdd, 0x71, 0x3d, 0x1a, 0x1e, 0x26, 0xef, 0xd1, 0xa3, 0x91, 0x55, 0x34, 0x6a, 0xe9, 0xa4, + 0x51, 0x61, 0xdf, 0x8b, 0xdc, 0x1e, 0x1d, 0x18, 0xf0, 0xb3, 0x5f, 0x34, 0x80, 0xd9, 0x1d, 0xda, + 0xb3, 0xf2, 0xe3, 0xcc, 0xbf, 0x2b, 0xc1, 0xcc, 0x72, 0x68, 0x77, 0xdc, 0xc7, 0xb4, 0x15, 0x71, + 0x46, 0xfb, 0x90, 0xbc, 0x0f, 0xe3, 0x91, 0x15, 0x1a, 0xa5, 0x6b, 0xa5, 0xeb, 0xf5, 0x1b, 0xdf, + 0x5c, 0x1c, 0x62, 0x21, 0x17, 0x77, 0xac, 0x30, 0x86, 0x6b, 0x4e, 0x1e, 0x1f, 0x35, 0xc6, 0x77, + 0xac, 0x10, 0x39, 0x2a, 0xf9, 0x0e, 0x4c, 0x78, 0xbe, 0x47, 0x8d, 0x31, 0x81, 0xbe, 0x3c, 0x14, + 0xfa, 0x96, 0xef, 0xe9, 0xd9, 0x36, 0xab, 0xc7, 0x47, 0x8d, 0x09, 0x4e, 0x41, 0x01, 0x6c, 0xfe, + 0x7b, 0x09, 0x6a, 0xcb, 0x61, 0xbb, 0xdf, 0xa3, 0x5e, 0xc4, 0x48, 0x08, 0x10, 0x58, 0xa1, 0xd5, + 0xa3, 0x11, 0x0d, 0x99, 0x51, 0xba, 0x36, 0x7e, 0xbd, 0x7e, 0xe3, 0x9d, 0xa1, 0x94, 0x6e, 0xc7, + 0x30, 0x4d, 0xf2, 0xc9, 0x51, 0xe3, 0xdc, 0xf1, 0x51, 0x03, 0x34, 0x89, 0x61, 0x4a, 0x0b, 0xf1, + 0xa0, 0x66, 0x85, 0x91, 0xbb, 0x67, 0xd9, 0x11, 0x33, 0xc6, 0x84, 0xca, 0xb7, 0x87, 0x52, 0xb9, + 0xac, 0x50, 0x9a, 0x17, 0x94, 0xc6, 0x5a, 0x4c, 0x61, 0x98, 0xa8, 0x30, 0xff, 0x75, 0x1c, 0xaa, + 0x31, 0x83, 0x5c, 0x83, 0x09, 0xcf, 0xea, 0x51, 0xf1, 0xf5, 0x6a, 0xcd, 0x29, 0x35, 0x70, 0x62, + 0xcb, 0xea, 0xf1, 0x05, 0xb2, 0x7a, 0x94, 0x4b, 0x04, 0x56, 0xd4, 0x11, 0x5f, 0x20, 0x25, 0xb1, + 0x6d, 0x45, 0x1d, 0x14, 0x1c, 0x72, 0x15, 0x26, 0x7a, 0xbe, 0x43, 0x8d, 0xf1, 0x6b, 0xa5, 0xeb, + 0x65, 0xb9, 0xc0, 0x9b, 0xbe, 0x43, 0x51, 0x50, 0xf9, 0xf8, 0xbd, 0xd0, 0xef, 0x19, 0x13, 0xd9, + 0xf1, 0xeb, 0xa1, 0xdf, 0x43, 0xc1, 0x21, 0xbf, 0x57, 0x82, 0xd9, 0x78, 0x7a, 0xf7, 0x7c, 0xdb, + 0x8a, 0x5c, 0xdf, 0x33, 0xca, 0xe2, 0x83, 0xaf, 0x8d, 0xb4, 0x10, 0x31, 0x58, 0xd3, 0x50, 0x5a, + 0x67, 0xf3, 0x1c, 0x1c, 0x50, 0x4c, 0x6e, 0x00, 0xb4, 0xbb, 0xfe, 0xae, 0xd5, 0xe5, 0x6b, 0x60, + 0x54, 0xc4, 0xac, 0xf5, 0x27, 0xbc, 0xa5, 0x39, 0x98, 0x92, 0x22, 0xfb, 0x30, 0x69, 0xc9, 0x5d, + 0x61, 0x4c, 0x8a, 0x79, 0xaf, 0x0e, 0x39, 0xef, 0xcc, 0xce, 0x6a, 0xd6, 0x8f, 0x8f, 0x1a, 0x93, + 0x8a, 0x88, 0xb1, 0x06, 0xf2, 0x1a, 0x54, 0xfd, 0x80, 0x4f, 0xd5, 0xea, 0x1a, 0xd5, 0x6b, 0xa5, + 0xeb, 0xd5, 0xe6, 0xac, 0x9a, 0x5e, 0xf5, 0xbe, 0xa2, 0xa3, 0x96, 0x30, 0xff, 0xb0, 0x0c, 0x03, + 0x6f, 0x4d, 0xde, 0x80, 0xba, 0x42, 0xbb, 0xe7, 0xb7, 0x99, 0xf8, 0xf8, 0xd5, 0xe6, 0xcc, 0xf1, + 0x51, 0xa3, 0xbe, 0x9c, 0x90, 0x31, 0x2d, 0x43, 0xde, 0x83, 0x31, 0x76, 0x53, 0x6d, 0xc3, 0x77, + 0x87, 0x7a, 0xbb, 0xd6, 0x4d, 0x6d, 0xa0, 0x95, 0xe3, 0xa3, 0xc6, 0x58, 0xeb, 0x26, 0x8e, 0xb1, + 0x9b, 0xdc, 0x7d, 0xb4, 0xdd, 0x48, 0x18, 0xcf, 0xb0, 0xee, 0xe3, 0x96, 0x1b, 0x69, 0x68, 0xe1, + 0x3e, 0x6e, 0xb9, 0x11, 0x72, 0x54, 0xee, 0x3e, 0x3a, 0x51, 0x14, 0x08, 0xe3, 0x1b, 0xd6, 0x7d, + 0xdc, 0xde, 0xd9, 0xd9, 0xd6, 0xf0, 0xc2, 0xba, 0x39, 0x05, 0x05, 0x30, 0xf9, 0x88, 0xaf, 0xa4, + 0xe4, 0xf9, 0xe1, 0xa1, 0xb2, 0xda, 0xdb, 0x23, 0x59, 0xad, 0x1f, 0x1e, 0x6a, 0x75, 0xea, 0x9b, + 0x68, 0x06, 0xa6, 0xb5, 0x89, 0xb7, 0x73, 0xf6, 0x98, 0x30, 0xd2, 0xa1, 0xdf, 0x6e, 0x75, 0xbd, + 0x95, 0x7b, 0xbb, 0xd5, 0xf5, 0x16, 0x0a, 0x60, 0xfe, 0x6d, 0x42, 0xeb, 0x40, 0xd9, 0xf4, 0x70, + 0xdf, 0x06, 0xad, 0x83, 0xec, 0xb7, 0x41, 0xeb, 0x00, 0x39, 0xaa, 0xd9, 0x86, 0x4b, 0x31, 0x07, + 0x69, 0xe0, 0x33, 0x57, 0xbc, 0x20, 0xdd, 0x23, 0x4b, 0x50, 0xb3, 0x7d, 0x6f, 0xcf, 0x6d, 0x6f, + 0x5a, 0x81, 0x72, 0x4c, 0xda, 0xa3, 0xad, 0xc4, 0x0c, 0x4c, 0x64, 0xc8, 0x4b, 0x30, 0xbe, 0x4f, + 0x0f, 0x95, 0x87, 0xaa, 0x2b, 0xd1, 0xf1, 0xbb, 0xf4, 0x10, 0x39, 0xdd, 0xfc, 0x61, 0x09, 0x2e, + 0x16, 0x2c, 0x2e, 0x1f, 0xd6, 0x0f, 0xbb, 0x4a, 0x83, 0x1e, 0xf6, 0x00, 0xef, 0x21, 0xa7, 0x93, + 0xdf, 0x2e, 0xc1, 0x4c, 0x6a, 0xb5, 0x97, 0xfb, 0xca, 0x09, 0x0e, 0xbf, 0xbb, 0x33, 0x58, 0xcd, + 0x2b, 0x4a, 0xe3, 0x4c, 0x8e, 0x81, 0x79, 0xad, 0xe6, 0xdf, 0x8b, 0x53, 0x37, 0x43, 0x23, 0x16, + 0x9c, 0xef, 0x33, 0x1a, 0x72, 0x17, 0xdd, 0xa2, 0x76, 0x48, 0x23, 0x75, 0x00, 0xbf, 0xb2, 0x28, + 0x8f, 0x76, 0x3e, 0x8b, 0x45, 0x1e, 0x65, 0x2c, 0x3e, 0x7e, 0x63, 0x51, 0x4a, 0xdc, 0xa5, 0x87, + 0x2d, 0xda, 0xa5, 0x1c, 0xa3, 0x49, 0x8e, 0x8f, 0x1a, 0xe7, 0x1f, 0x64, 0x00, 0x30, 0x07, 0xc8, + 0x55, 0x04, 0x16, 0x63, 0x07, 0x7e, 0xe8, 0x28, 0x15, 0x63, 0x4f, 0xad, 0x62, 0x3b, 0x03, 0x80, + 0x39, 0x40, 0xf3, 0x7b, 0x25, 0x98, 0x6c, 0x5a, 0xf6, 0xbe, 0xbf, 0xb7, 0xc7, 0xfd, 0x9a, 0xd3, + 0x0f, 0xa5, 0xf7, 0x97, 0xdf, 0x44, 0xfb, 0xb5, 0x55, 0x45, 0x47, 0x2d, 0x41, 0x5e, 0x85, 0x8a, + 0x5c, 0x0e, 0x31, 0xa9, 0x72, 0xf3, 0xbc, 0x92, 0xad, 0xac, 0x0b, 0x2a, 0x2a, 0x2e, 0xf9, 0x1a, + 0xd4, 0x7b, 0xd6, 0x87, 0x31, 0x80, 0x70, 0x33, 0xb5, 0xe6, 0x45, 0x25, 0x5c, 0xdf, 0x4c, 0x58, + 0x98, 0x96, 0x33, 0xbf, 0x05, 0xb0, 0xe2, 0x7b, 0x91, 0xeb, 0xf5, 0xe9, 0x7d, 0x8f, 0xbc, 0x0c, + 0x65, 0x1a, 0x86, 0x7e, 0xa8, 0x3c, 0xe5, 0xb4, 0x1a, 0x5e, 0x5e, 0xe3, 0x44, 0x94, 0x3c, 0x39, + 0x23, 0xb7, 0x4b, 0x1d, 0x31, 0xa3, 0x6a, 0x7a, 0x46, 0x9c, 0x8a, 0x8a, 0x6b, 0xfe, 0x51, 0x05, + 0x26, 0x57, 0x97, 0x6f, 0xed, 0x58, 0x6c, 0xff, 0x14, 0xc7, 0xef, 0x6b, 0x50, 0x8d, 0x68, 0x2f, + 0xe8, 0x5a, 0x11, 0x55, 0x06, 0xae, 0x57, 0x65, 0x47, 0xd1, 0x51, 0x4b, 0x10, 0x9f, 0xc7, 0x12, + 0x2a, 0x98, 0x51, 0x2e, 0xf5, 0x9d, 0x21, 0x8d, 0x55, 0xa1, 0xa4, 0x83, 0x09, 0x45, 0xc2, 0x44, + 0x07, 0x61, 0x50, 0x8f, 0x95, 0x23, 0xdd, 0x53, 0x7e, 0x76, 0xc8, 0x20, 0x30, 0xc1, 0x91, 0x7e, + 0x2f, 0x45, 0xc0, 0xb4, 0x16, 0xf2, 0x55, 0x98, 0x72, 0x68, 0x40, 0x3d, 0x87, 0x7a, 0xb6, 0x4b, + 0x99, 0x51, 0xbe, 0x36, 0xce, 0xd7, 0xe5, 0xf8, 0xa8, 0x31, 0xb5, 0x9a, 0xa2, 0x63, 0x46, 0x8a, + 0x3c, 0x82, 0xda, 0x81, 0x1b, 0x75, 0x36, 0x22, 0xda, 0xe3, 0x2e, 0x93, 0xc7, 0x59, 0x5f, 0x1f, + 0x6a, 0xa2, 0x1c, 0x21, 0x59, 0x96, 0xf7, 0x62, 0x4c, 0x4c, 0xe0, 0xb9, 0x0b, 0xe3, 0x0f, 0x22, + 0xe2, 0x13, 0xee, 0xb3, 0x96, 0x1d, 0x20, 0x18, 0x98, 0xc8, 0x10, 0x06, 0x53, 0xfc, 0xa1, 0x45, + 0x3f, 0xe8, 0x53, 0xcf, 0xa6, 0xe2, 0x60, 0x1f, 0x36, 0x0e, 0x8c, 0x41, 0xe4, 0x8a, 0xbc, 0x97, + 0x82, 0xc5, 0x8c, 0x12, 0x6e, 0x7d, 0x07, 0x1d, 0xea, 0x19, 0xb5, 0xac, 0xf5, 0xbd, 0xd7, 0xa1, + 0x1e, 0x0a, 0x0e, 0xf1, 0x01, 0x6c, 0xbd, 0x0d, 0x0c, 0x18, 0xe1, 0xf4, 0x4f, 0x76, 0x53, 0xf3, + 0x3c, 0x8f, 0xa4, 0x92, 0x67, 0x4c, 0xa9, 0x30, 0xff, 0xba, 0x04, 0x75, 0xbe, 0x39, 0x62, 0x83, + 0x7e, 0x15, 0x2a, 0x91, 0x15, 0xb6, 0x95, 0x7b, 0xab, 0x25, 0x9b, 0x6a, 0x47, 0x50, 0x51, 0x71, + 0x89, 0x05, 0xe5, 0xc8, 0x62, 0xfb, 0x71, 0x00, 0xfd, 0xf3, 0x43, 0xcd, 0x51, 0xed, 0xca, 0x64, + 0x7f, 0xf3, 0x27, 0x86, 0x12, 0x99, 0x5c, 0x87, 0x2a, 0xdf, 0xc1, 0xeb, 0x16, 0x93, 0xd1, 0x4a, + 0xb5, 0x39, 0xc5, 0x77, 0xe1, 0xba, 0xa2, 0xa1, 0xe6, 0x9a, 0xdf, 0x86, 0xf3, 0x6b, 0x1f, 0x52, + 0xbb, 0x1f, 0xf9, 0xa1, 0x3c, 0xaf, 0xc8, 0x1d, 0x20, 0x8c, 0x86, 0x8f, 0x5d, 0x9b, 0x2e, 0xdb, + 0xb6, 0xdf, 0xf7, 0xa2, 0xad, 0x64, 0xd7, 0xcf, 0x2b, 0x6d, 0xa4, 0x35, 0x20, 0x81, 0x05, 0xa3, + 0xcc, 0x3f, 0x9f, 0x80, 0x7a, 0x2a, 0xe2, 0xe1, 0x5f, 0x31, 0xa4, 0x81, 0x9f, 0xf7, 0x21, 0xfc, + 0x4c, 0x45, 0xc1, 0xe1, 0x3e, 0x24, 0xa4, 0x8f, 0x5d, 0xc6, 0x1d, 0x60, 0xce, 0x87, 0xa0, 0xa2, + 0xa3, 0x96, 0x20, 0x0d, 0x28, 0x3b, 0x34, 0x88, 0x3a, 0xe2, 0x25, 0x27, 0x9a, 0x35, 0xbe, 0x10, + 0xab, 0x9c, 0x80, 0x92, 0xce, 0x05, 0xf6, 0x68, 0x64, 0x77, 0x8c, 0x09, 0xb1, 0xef, 0x84, 0xc0, + 0x3a, 0x27, 0xa0, 0xa4, 0x17, 0x9c, 0x4d, 0xe5, 0x67, 0x7f, 0x36, 0x55, 0xce, 0xf8, 0x6c, 0x22, + 0x01, 0x5c, 0x64, 0xac, 0xb3, 0x1d, 0xba, 0x8f, 0xad, 0x88, 0x8a, 0xc1, 0x42, 0xcf, 0xe4, 0xd3, + 0xe8, 0xb9, 0x72, 0x7c, 0xd4, 0xb8, 0xd8, 0x6a, 0xdd, 0xce, 0xa3, 0x60, 0x11, 0x34, 0x69, 0xc1, + 0x25, 0xd7, 0x63, 0xd4, 0xee, 0x87, 0x74, 0xa3, 0xed, 0xf9, 0x21, 0xbd, 0xed, 0x33, 0x0e, 0xa7, + 0xc2, 0xfc, 0x97, 0xd4, 0x47, 0xbb, 0xb4, 0x51, 0x24, 0x84, 0xc5, 0x63, 0xcd, 0xbf, 0x2d, 0xc1, + 0x54, 0x3a, 0xc8, 0x23, 0x0c, 0xa0, 0xb3, 0xba, 0xde, 0x92, 0x96, 0xa9, 0xa2, 0x86, 0x77, 0x87, + 0x8e, 0x1d, 0x25, 0x4c, 0x92, 0x21, 0x25, 0x34, 0x4c, 0xa9, 0x39, 0x45, 0x16, 0xf9, 0x32, 0x94, + 0xf7, 0xfc, 0xd0, 0xa6, 0x6a, 0x6f, 0xe9, 0x3d, 0xb8, 0xce, 0x89, 0x28, 0x79, 0xe6, 0x3f, 0x97, + 0x20, 0xa5, 0x81, 0xfc, 0x1a, 0x4c, 0x73, 0x1d, 0x77, 0xc3, 0xdd, 0xcc, 0xdb, 0x34, 0x87, 0x7e, + 0x1b, 0x8d, 0xd4, 0xbc, 0xa4, 0xf4, 0x4f, 0x67, 0xc8, 0x98, 0xd5, 0x47, 0x7e, 0x06, 0x6a, 0x96, + 0xe3, 0x84, 0x94, 0x31, 0x2a, 0x5d, 0x4f, 0xad, 0x39, 0x2d, 0xce, 0xca, 0x98, 0x88, 0x09, 0x9f, + 0x6f, 0x43, 0x1e, 0x55, 0x73, 0xcb, 0x56, 0x71, 0x88, 0xde, 0x86, 0x5c, 0x09, 0xa7, 0xa3, 0x96, + 0x30, 0xbf, 0x3b, 0x01, 0x59, 0xdd, 0xc4, 0x81, 0x99, 0xfd, 0x70, 0x77, 0x65, 0xc5, 0xb2, 0x3b, + 0x43, 0xc5, 0x7c, 0x17, 0x79, 0xb0, 0x79, 0x37, 0x8b, 0x80, 0x79, 0x48, 0xa5, 0xe5, 0x2e, 0x3d, + 0x8c, 0xac, 0xdd, 0x61, 0xc2, 0xbe, 0x58, 0x4b, 0x1a, 0x01, 0xf3, 0x90, 0x3c, 0x2c, 0xdb, 0x0f, + 0x77, 0xe3, 0x4d, 0x9e, 0x0f, 0xcb, 0xee, 0x26, 0x2c, 0x4c, 0xcb, 0xf1, 0x25, 0xdc, 0x0f, 0x77, + 0x91, 0x5a, 0xdd, 0xb8, 0xa0, 0xa0, 0x97, 0xf0, 0xae, 0xa2, 0xa3, 0x96, 0x20, 0x01, 0x90, 0xfd, + 0x78, 0xf5, 0x74, 0xe2, 0xa0, 0x7c, 0xd1, 0xf5, 0xa2, 0xb7, 0xd1, 0x42, 0xe9, 0x17, 0xba, 0xcc, + 0x7d, 0xf3, 0xdd, 0x01, 0x1c, 0x2c, 0xc0, 0x26, 0xdf, 0x82, 0x2b, 0xfb, 0xe1, 0xae, 0x72, 0xe4, + 0xdb, 0xa1, 0xeb, 0xd9, 0x6e, 0x90, 0xa9, 0x24, 0x34, 0xd4, 0x74, 0xaf, 0xdc, 0x2d, 0x16, 0xc3, + 0x93, 0xc6, 0x9b, 0xaf, 0xc3, 0x54, 0x3a, 0x13, 0xfd, 0x82, 0xec, 0xc5, 0xfc, 0xb7, 0x12, 0x54, + 0x36, 0xbc, 0xa0, 0xff, 0x13, 0x52, 0xd4, 0xfa, 0x93, 0x09, 0x98, 0xe0, 0xa1, 0x17, 0xb9, 0x0e, + 0x13, 0xd1, 0x61, 0x20, 0xcf, 0xd6, 0xf1, 0xe6, 0x5c, 0xec, 0x68, 0x76, 0x0e, 0x03, 0xfa, 0x44, + 0xfd, 0x8b, 0x42, 0x82, 0xbc, 0x03, 0x15, 0xaf, 0xdf, 0x7b, 0x68, 0x75, 0x95, 0x53, 0x7a, 0x35, + 0x0e, 0x2d, 0xb6, 0x04, 0xf5, 0xc9, 0x51, 0x63, 0x8e, 0x7a, 0xb6, 0xef, 0xb8, 0x5e, 0x7b, 0xe9, + 0x11, 0xf3, 0xbd, 0xc5, 0xad, 0x7e, 0x6f, 0x97, 0x86, 0xa8, 0x46, 0x91, 0x2f, 0xc3, 0xe4, 0xae, + 0xef, 0x77, 0x39, 0x80, 0x74, 0x59, 0x33, 0x0a, 0x60, 0xb2, 0x29, 0xc9, 0x18, 0xf3, 0x79, 0x14, + 0xc3, 0xa2, 0x90, 0x4b, 0x4e, 0x64, 0xa3, 0x98, 0x96, 0xa0, 0xa2, 0xe2, 0x92, 0x1e, 0x54, 0x7a, + 0x56, 0xc0, 0xe5, 0xca, 0x62, 0xc9, 0xd6, 0x86, 0x8e, 0x4f, 0x17, 0x37, 0x05, 0xce, 0x9a, 0x17, + 0x85, 0x87, 0x89, 0x3a, 0x49, 0x44, 0xa5, 0x84, 0xb8, 0x30, 0xd9, 0x75, 0x59, 0xc4, 0xf5, 0x55, + 0x46, 0xb0, 0x0a, 0xae, 0xef, 0xa1, 0xd5, 0xed, 0xd3, 0x64, 0x05, 0xee, 0x49, 0x58, 0x8c, 0xf1, + 0xe7, 0x0f, 0xa1, 0x9e, 0x9a, 0x11, 0x99, 0x95, 0x19, 0xbb, 0x30, 0x5e, 0x91, 0xa4, 0x93, 0x1d, + 0x28, 0x3f, 0xe6, 0x18, 0xca, 0xd9, 0x8c, 0x38, 0x13, 0x94, 0x60, 0x6f, 0x8d, 0xbd, 0x59, 0x7a, + 0xab, 0xfa, 0xfd, 0x3f, 0x6e, 0x9c, 0xfb, 0xf8, 0x1f, 0xae, 0x9d, 0x33, 0xff, 0x66, 0x1c, 0x6a, + 0x5a, 0xe4, 0xff, 0xb6, 0xa5, 0x84, 0x39, 0x4b, 0xb9, 0x33, 0xda, 0x7a, 0x9d, 0xca, 0x5c, 0x96, + 0xb3, 0xe6, 0x32, 0xd5, 0xfc, 0x7f, 0xa9, 0x4f, 0xfd, 0xe4, 0xa8, 0x61, 0x64, 0x17, 0x01, 0xad, + 0x83, 0x4d, 0xca, 0x98, 0xd5, 0xa6, 0x89, 0x19, 0x7c, 0xfd, 0x8b, 0xcc, 0x60, 0x2e, 0x6d, 0x06, + 0xb5, 0xe2, 0xcf, 0xf8, 0xf1, 0x38, 0x54, 0x37, 0x69, 0x64, 0x39, 0x56, 0x64, 0x91, 0xdf, 0x2a, + 0x41, 0xdd, 0xf2, 0x3c, 0x3f, 0x12, 0x79, 0x7b, 0xec, 0xde, 0xb6, 0x86, 0x5a, 0x8e, 0x18, 0x74, + 0x71, 0x39, 0x01, 0x94, 0x4b, 0xa2, 0x4f, 0xa6, 0x14, 0x07, 0xd3, 0x7a, 0xc9, 0x07, 0x50, 0xe9, + 0x5a, 0xbb, 0xb4, 0x1b, 0x7b, 0xbb, 0x8d, 0xd1, 0x66, 0x70, 0x4f, 0x60, 0xe5, 0xbe, 0x87, 0x24, + 0xa2, 0x52, 0x34, 0xff, 0x0e, 0xcc, 0xe6, 0x27, 0xfa, 0x34, 0x2b, 0xca, 0x3f, 0x46, 0x4a, 0xcd, + 0xd3, 0x0c, 0x35, 0xff, 0xbb, 0x06, 0xb0, 0xe5, 0x3b, 0xb4, 0x15, 0x59, 0x51, 0x9f, 0x91, 0x79, + 0x18, 0x73, 0x1d, 0x75, 0x14, 0x81, 0x9a, 0xed, 0xd8, 0xc6, 0x2a, 0x8e, 0xb9, 0x8e, 0x2e, 0x71, + 0x8c, 0x9d, 0x58, 0xe2, 0xf8, 0x1a, 0xd4, 0x1d, 0x97, 0x05, 0x5d, 0xeb, 0x70, 0xab, 0x20, 0x16, + 0x58, 0x4d, 0x58, 0x98, 0x96, 0x23, 0xaf, 0xa9, 0xfd, 0x2b, 0x37, 0x8a, 0x91, 0xdb, 0xbf, 0x55, + 0x3e, 0xbd, 0xd4, 0x1e, 0x7e, 0x13, 0xa6, 0xe2, 0x12, 0x82, 0xd0, 0x52, 0x16, 0xa3, 0xe2, 0x5d, + 0x3f, 0xb5, 0x93, 0xe2, 0x61, 0x46, 0x32, 0x5f, 0xe2, 0xa8, 0x3c, 0x97, 0x12, 0xc7, 0x2a, 0xcc, + 0xb2, 0xc8, 0x0f, 0xa9, 0x13, 0x4b, 0x6c, 0xac, 0x1a, 0x24, 0xf3, 0xa2, 0xb3, 0xad, 0x1c, 0x1f, + 0x07, 0x46, 0x90, 0x6d, 0x98, 0x8b, 0x27, 0x91, 0x7e, 0x41, 0xe3, 0xa2, 0x40, 0xba, 0xaa, 0x90, + 0xe6, 0xde, 0x2b, 0x90, 0xc1, 0xc2, 0x91, 0xe4, 0x1b, 0x30, 0x1d, 0x4f, 0xb3, 0x65, 0xfb, 0x01, + 0x35, 0xe6, 0x04, 0x94, 0x8e, 0x96, 0x77, 0xd2, 0x4c, 0xcc, 0xca, 0x92, 0xaf, 0x40, 0x39, 0xe8, + 0x58, 0x8c, 0xaa, 0x8a, 0x48, 0x9c, 0xf8, 0x96, 0xb7, 0x39, 0xf1, 0xc9, 0x51, 0xa3, 0xc6, 0xbf, + 0x99, 0x78, 0x40, 0x29, 0x48, 0x6e, 0x00, 0xec, 0xfa, 0x7d, 0xcf, 0xb1, 0xc2, 0xc3, 0x8d, 0x55, + 0x91, 0x06, 0xa5, 0x2e, 0x63, 0x9a, 0x9a, 0x83, 0x29, 0x29, 0xee, 0x6d, 0x7b, 0xd2, 0xef, 0xa8, + 0xc2, 0x86, 0xf6, 0xb6, 0xda, 0x1d, 0x29, 0x3e, 0x79, 0x1f, 0x6a, 0x2c, 0xb2, 0xc2, 0x88, 0x3a, + 0xcb, 0x91, 0xaa, 0x6e, 0xfc, 0xff, 0x54, 0x5c, 0xa8, 0xaf, 0x46, 0x93, 0x6f, 0xda, 0xa3, 0x91, + 0xc5, 0x23, 0xc5, 0x1d, 0xb7, 0x47, 0x93, 0x90, 0xa4, 0x15, 0x83, 0x60, 0x82, 0x47, 0x7e, 0x19, + 0x60, 0xcf, 0xf5, 0x5c, 0xd6, 0x11, 0xe8, 0xf5, 0xa7, 0x46, 0xd7, 0xef, 0xb9, 0xae, 0x51, 0x30, + 0x85, 0xc8, 0x13, 0xa6, 0xc0, 0x77, 0x36, 0xb6, 0x8d, 0x29, 0xf1, 0x96, 0x3a, 0x61, 0xda, 0xe6, + 0x44, 0x94, 0x3c, 0x72, 0x1d, 0xaa, 0x8e, 0x45, 0x7b, 0xbe, 0x47, 0x1d, 0x63, 0x3a, 0x29, 0x5a, + 0xac, 0x2a, 0x1a, 0x6a, 0x2e, 0xf9, 0x0e, 0x54, 0x5c, 0x11, 0x2f, 0x1a, 0xe7, 0xc5, 0x54, 0xbf, + 0x31, 0xdc, 0x89, 0x22, 0x20, 0x9a, 0xc0, 0xdd, 0x95, 0xfc, 0x1b, 0x15, 0x2c, 0xb1, 0x61, 0xd2, + 0xef, 0x47, 0x42, 0xc3, 0x8c, 0xd0, 0x30, 0x5c, 0x91, 0xe6, 0xbe, 0xc4, 0x90, 0x97, 0x63, 0xea, + 0x01, 0x63, 0x64, 0xfe, 0xbe, 0x76, 0xc7, 0xed, 0x3a, 0x21, 0xf5, 0x8c, 0x59, 0x91, 0x8f, 0x89, + 0xf7, 0x5d, 0x51, 0x34, 0xd4, 0x5c, 0xf2, 0x73, 0x30, 0xed, 0xf7, 0x23, 0x61, 0x37, 0xdc, 0xec, + 0x98, 0x71, 0x41, 0x88, 0x5f, 0xe0, 0x56, 0x7c, 0x3f, 0xcd, 0xc0, 0xac, 0x9c, 0x79, 0x1e, 0xa6, + 0xd2, 0x37, 0xca, 0xe6, 0x1f, 0x8c, 0x41, 0x3c, 0x8f, 0x9f, 0x84, 0x50, 0x9b, 0x98, 0x50, 0x09, + 0x29, 0xeb, 0x77, 0x23, 0xe5, 0xa9, 0xc5, 0xb7, 0x46, 0x41, 0x41, 0xc5, 0x31, 0x0f, 0x60, 0x9a, + 0xcf, 0xb6, 0xdb, 0xa5, 0xdd, 0x56, 0x44, 0x03, 0x46, 0xf6, 0xa0, 0xcc, 0xf8, 0x1f, 0x6a, 0x4d, + 0x86, 0xbb, 0xab, 0x8a, 0xfd, 0x14, 0x87, 0x4c, 0xec, 0x5d, 0x28, 0x40, 0x09, 0x6f, 0x7e, 0x6f, + 0x0c, 0x6a, 0x7a, 0x9d, 0x4e, 0x51, 0x5e, 0x7f, 0x05, 0x26, 0x1d, 0xba, 0x67, 0xf1, 0xb7, 0x51, + 0xd7, 0x47, 0xdc, 0xac, 0x56, 0x25, 0x09, 0x63, 0x1e, 0x69, 0xc4, 0x27, 0xa1, 0x7c, 0x65, 0x51, + 0xf2, 0x4a, 0x07, 0x9a, 0x64, 0x1f, 0x6a, 0xe2, 0x8f, 0xf5, 0xf8, 0xaa, 0x7b, 0xd8, 0xef, 0xfe, + 0x30, 0x46, 0x91, 0x85, 0x04, 0xfd, 0x88, 0x09, 0x7e, 0xee, 0x8a, 0xba, 0x7c, 0x9a, 0x2b, 0x6a, + 0x73, 0x1d, 0xb8, 0x63, 0xb8, 0xb5, 0x42, 0xde, 0x86, 0x2a, 0x53, 0xa6, 0xab, 0xd6, 0xe5, 0x4b, + 0x71, 0x0a, 0x1d, 0x9b, 0xf4, 0x93, 0xa3, 0xc6, 0xb4, 0x10, 0x8e, 0x09, 0xa8, 0x87, 0x98, 0x4b, + 0x50, 0x4f, 0x5d, 0xe9, 0xf1, 0x15, 0xe6, 0xf1, 0x4a, 0x7e, 0x85, 0x57, 0xad, 0xc8, 0x42, 0xc1, + 0x31, 0x9f, 0x8c, 0xc1, 0x2c, 0x52, 0xe6, 0xf7, 0x43, 0x9b, 0xa6, 0xcb, 0xba, 0x96, 0x9d, 0xba, + 0xe9, 0xd1, 0x21, 0xce, 0xb2, 0xa0, 0xa2, 0xe2, 0xf2, 0xe3, 0xa6, 0x47, 0xc3, 0xb6, 0xde, 0x6c, + 0xea, 0x23, 0xe9, 0xe3, 0x66, 0x33, 0xcd, 0xc4, 0xac, 0x2c, 0x79, 0x0d, 0xaa, 0x3d, 0xcb, 0x73, + 0xf7, 0x28, 0x8b, 0xf2, 0xf5, 0x96, 0x4d, 0x45, 0x47, 0x2d, 0x41, 0x6e, 0xc1, 0x05, 0x46, 0xa3, + 0xfb, 0x07, 0x1e, 0x0d, 0x91, 0xee, 0xd1, 0x50, 0x94, 0xe1, 0x27, 0x84, 0xcb, 0x7c, 0x41, 0x0d, + 0xbb, 0xd0, 0xca, 0x0b, 0xe0, 0xe0, 0x18, 0x71, 0x74, 0xf7, 0x6d, 0x9b, 0x32, 0xb6, 0xe2, 0x7b, + 0x8e, 0xab, 0xbb, 0x19, 0xd2, 0x47, 0x77, 0x8e, 0x8f, 0x03, 0x23, 0x38, 0xca, 0x9e, 0xe5, 0x76, + 0xfb, 0x21, 0x4d, 0x50, 0x2a, 0x59, 0x94, 0xf5, 0x1c, 0x1f, 0x07, 0x46, 0x98, 0xff, 0x54, 0x82, + 0x69, 0xa4, 0x51, 0x78, 0xa8, 0x17, 0xa5, 0x01, 0xe5, 0xae, 0xdb, 0x73, 0x65, 0xe9, 0xa8, 0x2c, + 0x2d, 0xf9, 0x1e, 0x27, 0xa0, 0xa4, 0x93, 0x55, 0xa8, 0x87, 0x7c, 0xc4, 0xb6, 0xdf, 0x75, 0xed, + 0x78, 0xc1, 0xcd, 0x38, 0x1a, 0xc3, 0x84, 0xf5, 0x24, 0xfb, 0x88, 0xe9, 0x61, 0xc4, 0x83, 0xc9, + 0x5d, 0x79, 0xaf, 0xa7, 0xae, 0xa1, 0x86, 0x73, 0xf6, 0xea, 0x6e, 0x50, 0xd4, 0x60, 0xe2, 0x8b, + 0xc2, 0x27, 0xc9, 0x9f, 0x18, 0x2b, 0x31, 0xbf, 0x5f, 0x02, 0x48, 0x1a, 0x0c, 0xc8, 0x3e, 0x54, + 0xd9, 0xcd, 0x66, 0xdf, 0xde, 0xd7, 0x35, 0xb2, 0x21, 0xaf, 0x52, 0x14, 0x48, 0x62, 0x39, 0x31, + 0x05, 0xb5, 0x82, 0x2f, 0xba, 0x7e, 0xfe, 0x8b, 0x71, 0xd0, 0xa3, 0xb8, 0x4d, 0x52, 0xcf, 0x09, + 0x7c, 0xd7, 0x8b, 0xf2, 0x97, 0x9c, 0x6b, 0x8a, 0x8e, 0x5a, 0x82, 0x6f, 0x93, 0x5d, 0xf9, 0x12, + 0x63, 0xd9, 0x6d, 0xa2, 0xe6, 0xa0, 0xb8, 0x5c, 0x2e, 0xa4, 0xed, 0xe4, 0x7e, 0x53, 0xcb, 0xa1, + 0xa0, 0xa2, 0xe2, 0xf2, 0xd3, 0x31, 0x2e, 0x12, 0x2b, 0xd3, 0x16, 0xa7, 0x63, 0x5c, 0x4f, 0x46, + 0xcd, 0x25, 0x1d, 0x98, 0xb1, 0x84, 0x45, 0x26, 0x85, 0xef, 0xa7, 0xaa, 0xe1, 0x27, 0x97, 0xdb, + 0x59, 0x14, 0xcc, 0xc3, 0x72, 0x4d, 0x2c, 0x19, 0xfe, 0xf4, 0xa5, 0x7c, 0xad, 0xa9, 0x95, 0x45, + 0xc1, 0x3c, 0x2c, 0x0f, 0x0c, 0x43, 0xbf, 0x4b, 0x97, 0x71, 0x4b, 0x05, 0xa0, 0x3a, 0x30, 0x44, + 0x49, 0xc6, 0x98, 0x6f, 0xfe, 0x4e, 0x09, 0xce, 0xb7, 0xec, 0xd0, 0x0d, 0x22, 0xed, 0xb2, 0xb6, + 0x44, 0x57, 0x42, 0x64, 0xf1, 0x90, 0x4d, 0xd9, 0xd4, 0x4b, 0x27, 0xd4, 0x10, 0xa5, 0x50, 0xa6, + 0x69, 0x41, 0x92, 0x30, 0x81, 0x10, 0x99, 0xbe, 0x70, 0x8a, 0xf9, 0x6f, 0xdb, 0x12, 0x54, 0x54, + 0x5c, 0xf3, 0x07, 0x25, 0xa8, 0xea, 0x1b, 0xbb, 0x97, 0xa1, 0x2c, 0x2e, 0x82, 0x94, 0xed, 0xe8, + 0x33, 0x70, 0x85, 0x13, 0x51, 0xf2, 0xb8, 0x90, 0x88, 0x42, 0x15, 0x70, 0xea, 0xa0, 0xb4, 0xc2, + 0x08, 0x25, 0x8f, 0x1b, 0x2d, 0xf5, 0x1c, 0x65, 0x2f, 0xda, 0x68, 0xd7, 0x3c, 0x07, 0x39, 0x5d, + 0x5c, 0x66, 0xfb, 0x61, 0xcf, 0x8a, 0xf2, 0x75, 0x88, 0x75, 0x41, 0x45, 0xc5, 0x35, 0xdf, 0x85, + 0x99, 0x56, 0x9f, 0x05, 0xd4, 0xd3, 0x69, 0xc7, 0xd3, 0xdd, 0xe3, 0x9b, 0xff, 0x51, 0x82, 0xfa, + 0xce, 0xce, 0x3d, 0xed, 0x9f, 0xee, 0xc3, 0x25, 0x46, 0x6d, 0xdf, 0x73, 0xd8, 0xf2, 0x5e, 0x44, + 0xc3, 0x15, 0xbf, 0x17, 0x74, 0x69, 0x44, 0x1d, 0xe5, 0xaf, 0x5e, 0x38, 0x3e, 0x6a, 0x5c, 0x6a, + 0x15, 0x09, 0x60, 0xf1, 0x38, 0xb2, 0x01, 0x17, 0xd3, 0x0c, 0xe5, 0x7a, 0x55, 0xd7, 0x80, 0xbc, + 0x9f, 0x19, 0x64, 0x63, 0xd1, 0x18, 0xb2, 0x0e, 0x24, 0x4d, 0x96, 0xf7, 0xfa, 0xaa, 0xed, 0xed, + 0xb2, 0xbc, 0xc1, 0xcb, 0x73, 0xb1, 0x60, 0x84, 0x39, 0x0d, 0xf5, 0x54, 0xc7, 0xa3, 0xf9, 0x9f, + 0x57, 0x40, 0xdf, 0xe5, 0xff, 0xb4, 0x23, 0x60, 0xa8, 0x74, 0xd9, 0xd6, 0xc9, 0x4b, 0x79, 0xf4, + 0xe4, 0x45, 0xdb, 0x7a, 0x2e, 0x81, 0x69, 0x27, 0x09, 0x4c, 0xe5, 0x0c, 0x12, 0x18, 0xed, 0x7d, + 0x06, 0x92, 0x98, 0xdf, 0x2d, 0xc1, 0x94, 0xe7, 0x3b, 0x34, 0xf6, 0x71, 0xc6, 0xa4, 0x08, 0x9a, + 0xef, 0x8f, 0xb4, 0x88, 0x8b, 0x5b, 0x29, 0x44, 0x59, 0x58, 0xd2, 0xd5, 0x8f, 0x34, 0x0b, 0x33, + 0xaa, 0xc9, 0x3a, 0x54, 0xad, 0x3d, 0x9e, 0x75, 0x46, 0x87, 0xaa, 0x29, 0xe1, 0x6a, 0x91, 0xd7, + 0x5b, 0x56, 0x32, 0xf2, 0x40, 0x89, 0x9f, 0x50, 0x8f, 0xe5, 0x27, 0x72, 0x4f, 0x15, 0xb7, 0x44, + 0x5a, 0x3e, 0xec, 0x89, 0x1c, 0x57, 0xc8, 0x52, 0xb1, 0x9c, 0xa2, 0xa0, 0x56, 0xc0, 0x53, 0x14, + 0x99, 0xd7, 0x8a, 0xa4, 0xbe, 0x2a, 0x53, 0x14, 0x99, 0xf3, 0xa2, 0xe2, 0x90, 0x76, 0x9c, 0x91, + 0xd4, 0xc5, 0xe2, 0x36, 0x87, 0xce, 0xd2, 0x74, 0x92, 0x53, 0x9c, 0x92, 0x90, 0x3b, 0xe9, 0x83, + 0x63, 0xea, 0x34, 0x07, 0xc7, 0xf4, 0x89, 0x87, 0x46, 0x1b, 0x2a, 0x4c, 0x1c, 0x4b, 0x22, 0x99, + 0xaf, 0xdf, 0x58, 0x19, 0x2e, 0xaa, 0xc9, 0x9c, 0x6c, 0x72, 0x75, 0x24, 0x0d, 0x15, 0x3c, 0xf1, + 0xa1, 0x1a, 0xaa, 0xa0, 0x5d, 0xd5, 0x03, 0x86, 0xbb, 0x8b, 0xc8, 0x47, 0xfe, 0xd2, 0x3e, 0x62, + 0x2a, 0x6a, 0x25, 0xe4, 0x7d, 0x18, 0x77, 0xac, 0xb6, 0xaa, 0x0c, 0x7c, 0x73, 0xe8, 0xf6, 0x8d, + 0x58, 0x8d, 0x68, 0x35, 0x5c, 0x5d, 0xbe, 0x85, 0x1c, 0x95, 0xec, 0xc3, 0x24, 0x93, 0xa7, 0x94, + 0x31, 0x3b, 0x42, 0x07, 0x5f, 0xee, 0xa4, 0x93, 0xb9, 0xa2, 0x22, 0x62, 0xac, 0x81, 0xac, 0xc1, + 0xe4, 0x63, 0xbf, 0xdb, 0xef, 0xa9, 0x92, 0x42, 0xfd, 0xc6, 0x7c, 0xd1, 0xd7, 0x7e, 0x28, 0x44, + 0x12, 0x27, 0x20, 0x9f, 0x19, 0xc6, 0x63, 0xc9, 0x6f, 0x94, 0xe0, 0x3c, 0xdf, 0x3a, 0xda, 0x0e, + 0x98, 0x41, 0x46, 0xb0, 0xd4, 0x07, 0x8c, 0x1f, 0x8a, 0xb1, 0x85, 0x5d, 0x56, 0x6a, 0xcf, 0x6f, + 0x64, 0x34, 0x60, 0x4e, 0x23, 0x09, 0xa0, 0xca, 0x5c, 0x87, 0xda, 0x56, 0xc8, 0x8c, 0x8b, 0x67, + 0xa6, 0x3d, 0x09, 0xa6, 0x15, 0x36, 0x6a, 0x2d, 0xe4, 0x37, 0x45, 0xd7, 0xa5, 0xea, 0x3b, 0x56, + 0xbd, 0xe0, 0x73, 0x67, 0xd9, 0x0b, 0x7e, 0x51, 0xb6, 0x5c, 0x66, 0x34, 0x60, 0x5e, 0x25, 0x0f, + 0x43, 0x78, 0x0a, 0xfa, 0x98, 0xae, 0x52, 0xcb, 0xe9, 0xba, 0x1e, 0x55, 0x47, 0xbb, 0x71, 0x49, + 0xdc, 0x16, 0x89, 0x30, 0x64, 0xb9, 0x48, 0x00, 0x8b, 0xc7, 0x91, 0x8f, 0x60, 0x3a, 0x4c, 0x27, + 0x62, 0xc6, 0xe5, 0x11, 0x5a, 0x15, 0x32, 0x29, 0x9d, 0x2c, 0x59, 0x65, 0x48, 0x98, 0xd5, 0x45, + 0xde, 0x80, 0x7a, 0xa0, 0x3c, 0x95, 0xcb, 0x7a, 0xc6, 0x15, 0xf1, 0x0e, 0xe2, 0x44, 0xdd, 0x4e, + 0xc8, 0x98, 0x96, 0x21, 0x0f, 0xa0, 0x1e, 0xf9, 0x5d, 0x1a, 0xaa, 0x6b, 0x15, 0x43, 0x7c, 0xfc, + 0x85, 0x22, 0x4b, 0xde, 0xd1, 0x62, 0x49, 0xd1, 0x3e, 0xa1, 0x31, 0x4c, 0xe3, 0xf0, 0x84, 0x9e, + 0xd9, 0x1d, 0xea, 0xf4, 0xbb, 0x34, 0x14, 0xd5, 0x8b, 0x17, 0xb2, 0x09, 0x7d, 0x2b, 0xcd, 0xc4, + 0xac, 0x2c, 0x4f, 0xd1, 0x83, 0xd0, 0xf5, 0x43, 0x37, 0x3a, 0x5c, 0xe9, 0x5a, 0x8c, 0x09, 0x80, + 0x79, 0x01, 0xa0, 0x53, 0xf4, 0xed, 0xbc, 0x00, 0x0e, 0x8e, 0xe1, 0x79, 0x50, 0x4c, 0x34, 0x5e, + 0x14, 0xe1, 0x9b, 0x70, 0x4b, 0xf1, 0x58, 0xd4, 0xdc, 0x13, 0x1a, 0xb7, 0xae, 0x0e, 0xd3, 0xb8, + 0x45, 0x1c, 0xb8, 0x6a, 0xf5, 0x23, 0xbf, 0xc7, 0x09, 0xd9, 0x21, 0x3b, 0xfe, 0x3e, 0xf5, 0x8c, + 0x6b, 0xe2, 0xac, 0xba, 0x76, 0x7c, 0xd4, 0xb8, 0xba, 0xfc, 0x39, 0x72, 0xf8, 0xb9, 0x28, 0xa4, + 0x07, 0x55, 0xaa, 0x9a, 0xcf, 0x8c, 0x2f, 0x8d, 0x70, 0x48, 0x64, 0x3b, 0xd8, 0xe4, 0x02, 0xc5, + 0x34, 0xd4, 0x2a, 0xc8, 0x0e, 0xd4, 0x3b, 0x3e, 0x8b, 0x96, 0xbb, 0xae, 0xc5, 0x28, 0x33, 0x5e, + 0x12, 0x76, 0x52, 0x78, 0xbe, 0xdd, 0x8e, 0xc5, 0x12, 0x33, 0xb9, 0x9d, 0x8c, 0xc4, 0x34, 0x0c, + 0xa1, 0x22, 0x29, 0xec, 0x8b, 0xaf, 0xe6, 0x7b, 0x11, 0xfd, 0x30, 0x32, 0x16, 0xc4, 0xbb, 0xbc, + 0x5a, 0x84, 0xbc, 0xed, 0x3b, 0xad, 0xac, 0xb4, 0xdc, 0xe5, 0x39, 0x22, 0xe6, 0x31, 0xc9, 0x9b, + 0x30, 0x15, 0xf8, 0x4e, 0x2b, 0xa0, 0xf6, 0xb6, 0x15, 0xd9, 0x1d, 0xa3, 0x91, 0xbd, 0x14, 0xda, + 0x4e, 0xf1, 0x30, 0x23, 0x39, 0xff, 0x2e, 0x5c, 0x18, 0x88, 0xa7, 0x9e, 0xea, 0x06, 0xed, 0x4f, + 0x79, 0xde, 0x93, 0x8a, 0x60, 0xcf, 0x3a, 0xee, 0xbf, 0x05, 0x17, 0xd4, 0x6f, 0xb9, 0xf8, 0x61, + 0xdb, 0xed, 0xeb, 0xee, 0xe7, 0x54, 0x39, 0x0b, 0xf3, 0x02, 0x38, 0x38, 0xc6, 0xfc, 0xb3, 0x12, + 0x4c, 0x67, 0xdc, 0xf7, 0x99, 0x67, 0xc2, 0xeb, 0x40, 0x7a, 0x6e, 0x18, 0xfa, 0xa1, 0x3c, 0x03, + 0x37, 0xb9, 0x2d, 0x33, 0xd5, 0x44, 0x2d, 0xd2, 0xaa, 0xcd, 0x01, 0x2e, 0x16, 0x8c, 0x30, 0xff, + 0xaa, 0x04, 0x49, 0xbd, 0x54, 0x77, 0x9c, 0x95, 0x4e, 0xec, 0x38, 0x7b, 0x0d, 0xaa, 0x8f, 0x98, + 0xef, 0x6d, 0x27, 0x7d, 0x69, 0x7a, 0x41, 0xef, 0xb4, 0xee, 0x6f, 0x09, 0x49, 0x2d, 0x21, 0xa4, + 0x3f, 0x58, 0x77, 0xbb, 0xd1, 0x60, 0xf7, 0xd6, 0x9d, 0x5f, 0x90, 0x74, 0xd4, 0x12, 0x64, 0x09, + 0x6a, 0xba, 0x44, 0xaf, 0x52, 0x68, 0xbd, 0x08, 0xba, 0x3e, 0x8d, 0x89, 0x8c, 0xf9, 0xc3, 0x31, + 0xa8, 0xc6, 0xf5, 0x6d, 0xf2, 0x2b, 0xa9, 0x60, 0x59, 0x2e, 0xf0, 0x57, 0x4e, 0x77, 0x71, 0x74, + 0x7f, 0xf7, 0x11, 0xb5, 0x23, 0x1e, 0x11, 0x27, 0x05, 0xe1, 0x84, 0x96, 0x8a, 0x90, 0x6d, 0x98, + 0x60, 0x01, 0xb5, 0x47, 0xfa, 0x5d, 0x9d, 0x2e, 0xc7, 0x07, 0xd4, 0x4e, 0x16, 0x98, 0x3f, 0xa1, + 0x00, 0x27, 0xfb, 0x50, 0x61, 0xe2, 0x82, 0x58, 0x25, 0x9e, 0x2b, 0x23, 0x56, 0xfd, 0x39, 0x54, + 0xba, 0x23, 0x82, 0x3f, 0xa3, 0x52, 0x61, 0x7e, 0x5a, 0x82, 0xa9, 0x58, 0xf4, 0x9e, 0xcb, 0x22, + 0xf2, 0xed, 0x81, 0x45, 0x5c, 0x3c, 0xdd, 0x22, 0xf2, 0xd1, 0x62, 0x09, 0xf5, 0x07, 0x8e, 0x29, + 0xa9, 0x05, 0xdc, 0x85, 0xb2, 0x2b, 0x3a, 0xc9, 0x47, 0xb9, 0x71, 0x89, 0xe7, 0x9b, 0x64, 0x0e, + 0xb2, 0x93, 0x5c, 0x42, 0x9b, 0x7f, 0x39, 0x97, 0xbc, 0x12, 0x5f, 0x56, 0xe2, 0x41, 0x2d, 0xde, + 0xe0, 0xf1, 0x4d, 0xca, 0xdb, 0x23, 0x25, 0x85, 0x89, 0x51, 0xc6, 0x14, 0x86, 0x89, 0x0a, 0x72, + 0x03, 0x80, 0x72, 0xcf, 0x26, 0xeb, 0x95, 0x63, 0xd9, 0x8b, 0x86, 0x35, 0xcd, 0xc1, 0x94, 0xd4, + 0xf3, 0x2f, 0x38, 0x14, 0x1f, 0xd1, 0x13, 0xcf, 0xe4, 0x88, 0xbe, 0x7a, 0xe6, 0x47, 0xf4, 0x4b, + 0xcf, 0xfe, 0x88, 0x4e, 0x25, 0x24, 0xe5, 0x11, 0x12, 0x92, 0x8f, 0x60, 0x4e, 0xfe, 0xb9, 0xd2, + 0xb5, 0xdc, 0x9e, 0xb6, 0x17, 0xd5, 0x3a, 0xf6, 0xe5, 0xc2, 0x83, 0x99, 0x86, 0xcc, 0x65, 0x11, + 0xf5, 0xa2, 0x87, 0xc9, 0xc8, 0xa4, 0xef, 0xe0, 0x61, 0x01, 0x1c, 0x16, 0x2a, 0xc9, 0x47, 0xb0, + 0x93, 0xa7, 0x88, 0x60, 0x7f, 0x50, 0x82, 0x4b, 0x56, 0xd1, 0x0f, 0xcc, 0x54, 0x1d, 0xe3, 0xce, + 0x48, 0xf9, 0x44, 0x06, 0x51, 0xe5, 0x03, 0x45, 0x2c, 0x2c, 0x9e, 0x03, 0x79, 0x25, 0x49, 0x49, + 0x6b, 0xc2, 0xa8, 0x8a, 0x93, 0xc9, 0xef, 0xe6, 0x4b, 0x41, 0x20, 0x56, 0xbb, 0x35, 0xb2, 0xc3, + 0x3e, 0x83, 0x72, 0x50, 0x7d, 0x84, 0x72, 0x50, 0x2e, 0xbd, 0x98, 0x3a, 0xa3, 0xf4, 0xc2, 0x83, + 0x59, 0xb7, 0x67, 0xb5, 0xe9, 0x76, 0xbf, 0xdb, 0x95, 0x55, 0x7f, 0x66, 0x4c, 0x0b, 0xec, 0xc2, + 0x7e, 0x5f, 0x9e, 0xee, 0x75, 0xe5, 0xf9, 0xa8, 0xef, 0xef, 0x92, 0xfb, 0xb5, 0x8d, 0x1c, 0x12, + 0x0e, 0x60, 0x73, 0xb3, 0xe4, 0x61, 0xeb, 0x16, 0x8d, 0xf8, 0x6a, 0x8b, 0x4a, 0x89, 0xfa, 0x21, + 0xed, 0xed, 0x84, 0x8c, 0x69, 0x19, 0x72, 0x17, 0x6a, 0x8e, 0xc7, 0xd4, 0xed, 0xda, 0x8c, 0xf0, + 0x52, 0xaf, 0x73, 0xdf, 0xb6, 0xba, 0xd5, 0xd2, 0xf7, 0x6a, 0x57, 0x07, 0xff, 0xa7, 0x80, 0x45, + 0xcd, 0xc7, 0x64, 0x3c, 0xd9, 0x14, 0x60, 0xaa, 0xf9, 0x5d, 0x96, 0x36, 0xae, 0x9d, 0x10, 0x21, + 0xaf, 0x6e, 0xc5, 0xbd, 0xfa, 0xd3, 0x4a, 0x9d, 0x6a, 0x69, 0x4f, 0x10, 0xc8, 0xab, 0x50, 0xf1, + 0xbd, 0xb5, 0x0f, 0xdd, 0xc8, 0xb8, 0x90, 0xad, 0xfa, 0xdf, 0x17, 0x54, 0x54, 0x5c, 0xf2, 0x00, + 0xae, 0x44, 0x51, 0x37, 0x53, 0xed, 0x56, 0x7d, 0x29, 0xa2, 0x49, 0xa9, 0xdc, 0x7c, 0xf1, 0xf8, + 0xa8, 0x71, 0x65, 0x67, 0xe7, 0x5e, 0x91, 0x08, 0x9e, 0x34, 0x56, 0x94, 0x8e, 0xa3, 0xae, 0xce, + 0x90, 0x17, 0x46, 0x29, 0x1d, 0x27, 0x57, 0x0a, 0xaa, 0x74, 0x9c, 0x10, 0x30, 0xad, 0xe5, 0xe4, + 0x4c, 0xff, 0xe2, 0x90, 0x99, 0x7e, 0x3a, 0xb9, 0x9c, 0xfb, 0xdc, 0xe4, 0x72, 0x20, 0x19, 0xbe, + 0xf4, 0x14, 0xc9, 0xf0, 0xfb, 0xa2, 0xfd, 0xe7, 0xd6, 0x8a, 0x2a, 0x24, 0xbc, 0x35, 0x5c, 0xfd, + 0x92, 0x23, 0xc8, 0x4b, 0x60, 0xf1, 0x27, 0x4a, 0x4c, 0xb2, 0x0d, 0x73, 0x81, 0xef, 0x0c, 0xe4, + 0xd2, 0xa2, 0x72, 0x90, 0x6a, 0x1c, 0xdb, 0x2e, 0x90, 0xc1, 0xc2, 0x91, 0xc2, 0x81, 0x27, 0x74, + 0xc3, 0x10, 0x0b, 0x23, 0x1d, 0x78, 0x42, 0xc6, 0xb4, 0x4c, 0x3e, 0xb5, 0x7c, 0xe1, 0x99, 0xa5, + 0x96, 0xf3, 0xcf, 0x21, 0xb5, 0x7c, 0xf1, 0xf9, 0xa5, 0x96, 0x9f, 0x55, 0xe1, 0x7c, 0x36, 0x68, + 0x4e, 0x3a, 0xef, 0x4a, 0xa7, 0xed, 0xbc, 0xcb, 0xb4, 0xc6, 0x8d, 0x3d, 0xd3, 0xd6, 0xb8, 0xf1, + 0x33, 0x6f, 0x8d, 0x4b, 0xb5, 0x00, 0x4e, 0x7c, 0x41, 0x0b, 0xe0, 0x32, 0xcc, 0xd8, 0x7e, 0x2f, + 0x10, 0x3f, 0xd1, 0x51, 0x8d, 0x60, 0xb2, 0x59, 0x43, 0xdf, 0x2b, 0xaf, 0x64, 0xd9, 0x98, 0x97, + 0x27, 0xbf, 0x0a, 0x65, 0x4f, 0x0c, 0xac, 0x8c, 0xd0, 0x7b, 0x9c, 0xfd, 0x60, 0xe2, 0x74, 0x56, + 0xed, 0xbf, 0x71, 0xad, 0xb6, 0x2c, 0x68, 0x4f, 0xe2, 0x3f, 0x50, 0x2a, 0xe5, 0x61, 0xce, 0x4c, + 0xb6, 0xf1, 0x93, 0x19, 0x35, 0x31, 0x91, 0x5f, 0x3c, 0x8b, 0x89, 0x64, 0xbb, 0x4c, 0xd5, 0x94, + 0x92, 0x3b, 0xf7, 0x2c, 0x17, 0xf3, 0x33, 0x21, 0x21, 0x5c, 0x0e, 0x8a, 0x82, 0x40, 0xa6, 0xee, + 0xb4, 0x3e, 0x2f, 0x14, 0x5d, 0x50, 0x5a, 0x2e, 0x17, 0x86, 0x91, 0x0c, 0x4f, 0x40, 0x4e, 0x37, + 0x1a, 0x56, 0x9f, 0x55, 0xa3, 0xe1, 0xfc, 0xa1, 0x6c, 0x80, 0x3e, 0xb1, 0x77, 0xfa, 0x41, 0xf6, + 0xf7, 0x0c, 0xef, 0x0e, 0xf9, 0x3f, 0xd7, 0xc4, 0x2d, 0xd6, 0xe9, 0xbe, 0xed, 0x5f, 0x2f, 0xc1, + 0x5c, 0xd1, 0x67, 0x29, 0x98, 0x45, 0x2b, 0x3b, 0x8b, 0xd1, 0x92, 0xc5, 0xb4, 0x8f, 0xf9, 0x97, + 0x72, 0x2a, 0x35, 0x8d, 0x68, 0xf0, 0xd3, 0x7b, 0xeb, 0xa1, 0xee, 0xad, 0x33, 0xbf, 0x49, 0x2f, + 0x3f, 0xc7, 0xdf, 0xa4, 0x57, 0x86, 0xf8, 0x4d, 0xfa, 0xe4, 0xf3, 0xfc, 0x4d, 0x7a, 0xf5, 0x94, + 0xbf, 0x49, 0xaf, 0x3d, 0xfb, 0xdf, 0xa4, 0x7f, 0x56, 0x82, 0xd9, 0x7c, 0x8b, 0xfc, 0x73, 0x28, + 0xd1, 0xed, 0x67, 0x4a, 0x74, 0x1b, 0x23, 0x39, 0x73, 0xdd, 0x96, 0x7f, 0x42, 0xa9, 0xce, 0xfc, + 0x71, 0x09, 0x06, 0x7e, 0x06, 0xf0, 0x1c, 0xaa, 0x68, 0x8f, 0xb2, 0x55, 0xb4, 0xb5, 0x33, 0x79, + 0xc9, 0x13, 0xaa, 0x69, 0xff, 0x55, 0xf0, 0x8a, 0xff, 0x2b, 0x55, 0xb5, 0x8c, 0x6b, 0x1b, 0x7b, + 0xf6, 0xae, 0xad, 0xb9, 0xf8, 0xc9, 0x67, 0x0b, 0xe7, 0x3e, 0xfd, 0x6c, 0xe1, 0xdc, 0x8f, 0x3e, + 0x5b, 0x38, 0xf7, 0xf1, 0xf1, 0x42, 0xe9, 0x93, 0xe3, 0x85, 0xd2, 0xa7, 0xc7, 0x0b, 0xa5, 0x1f, + 0x1d, 0x2f, 0x94, 0x7e, 0x7c, 0xbc, 0x50, 0xfa, 0xfd, 0x7f, 0x5c, 0x38, 0xf7, 0x4b, 0xd5, 0x18, + 0xf7, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0x11, 0x7e, 0xec, 0x1c, 0x52, 0x4f, 0x00, 0x00, } func (m *ArchiveStrategy) Marshal() (dAtA []byte, err error) { @@ -3710,6 +3745,44 @@ func (m *SuspendTemplate) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *TTLStrategy) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *TTLStrategy) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *TTLStrategy) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.SecondsAfterFailed != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.SecondsAfterFailed)) + i-- + dAtA[i] = 0x18 + } + if m.SecondsAfterSuccess != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.SecondsAfterSuccess)) + i-- + dAtA[i] = 0x10 + } + if m.SecondsAfterCompleted != nil { + i = encodeVarintGenerated(dAtA, i, uint64(*m.SecondsAfterCompleted)) + i-- + dAtA[i] = 0x8 + } + return len(dAtA) - i, nil +} + func (m *TarStrategy) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -4384,6 +4457,20 @@ func (m *WorkflowSpec) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.TTLStrategy != nil { + { + size, err := m.TTLStrategy.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenerated(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1 + i-- + dAtA[i] = 0xf2 + } if m.Executor != nil { { size, err := m.Executor.MarshalToSizedBuffer(dAtA[:i]) @@ -5820,6 +5907,24 @@ func (m *SuspendTemplate) Size() (n int) { return n } +func (m *TTLStrategy) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.SecondsAfterCompleted != nil { + n += 1 + sovGenerated(uint64(*m.SecondsAfterCompleted)) + } + if m.SecondsAfterSuccess != nil { + n += 1 + sovGenerated(uint64(*m.SecondsAfterSuccess)) + } + if m.SecondsAfterFailed != nil { + n += 1 + sovGenerated(uint64(*m.SecondsAfterFailed)) + } + return n +} + func (m *TarStrategy) Size() (n int) { if m == nil { return 0 @@ -6154,6 +6259,10 @@ func (m *WorkflowSpec) Size() (n int) { l = m.Executor.Size() n += 2 + l + sovGenerated(uint64(l)) } + if m.TTLStrategy != nil { + l = m.TTLStrategy.Size() + n += 2 + l + sovGenerated(uint64(l)) + } return n } @@ -6781,6 +6890,18 @@ func (this *SuspendTemplate) String() string { }, "") return s } +func (this *TTLStrategy) String() string { + if this == nil { + return "nil" + } + s := strings.Join([]string{`&TTLStrategy{`, + `SecondsAfterCompleted:` + valueToStringGenerated(this.SecondsAfterCompleted) + `,`, + `SecondsAfterSuccess:` + valueToStringGenerated(this.SecondsAfterSuccess) + `,`, + `SecondsAfterFailed:` + valueToStringGenerated(this.SecondsAfterFailed) + `,`, + `}`, + }, "") + return s +} func (this *TarStrategy) String() string { if this == nil { return "nil" @@ -7010,6 +7131,7 @@ func (this *WorkflowSpec) String() string { `PodSpecPatch:` + fmt.Sprintf("%v", this.PodSpecPatch) + `,`, `AutomountServiceAccountToken:` + valueToStringGenerated(this.AutomountServiceAccountToken) + `,`, `Executor:` + strings.Replace(this.Executor.String(), "ExecutorConfig", "ExecutorConfig", 1) + `,`, + `TTLStrategy:` + strings.Replace(this.TTLStrategy.String(), "TTLStrategy", "TTLStrategy", 1) + `,`, `}`, }, "") return s @@ -13671,6 +13793,119 @@ func (m *SuspendTemplate) Unmarshal(dAtA []byte) error { } return nil } +func (m *TTLStrategy) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: TTLStrategy: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: TTLStrategy: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterCompleted", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SecondsAfterCompleted = &v + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterSuccess", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SecondsAfterSuccess = &v + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field SecondsAfterFailed", wireType) + } + var v int32 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenerated + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int32(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.SecondsAfterFailed = &v + default: + iNdEx = preIndex + skippy, err := skipGenerated(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthGenerated + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func (m *TarStrategy) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 @@ -16624,6 +16859,42 @@ func (m *WorkflowSpec) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 30: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field TTLStrategy", 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 + } + if m.TTLStrategy == nil { + m.TTLStrategy = &TTLStrategy{} + } + if err := m.TTLStrategy.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipGenerated(dAtA[iNdEx:]) @@ -17909,6 +18180,7 @@ func (m *WorkflowTemplateSpec) Unmarshal(dAtA []byte) error { func skipGenerated(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 + depth := 0 for iNdEx < l { var wire uint64 for shift := uint(0); ; shift += 7 { @@ -17940,10 +18212,8 @@ func skipGenerated(dAtA []byte) (n int, err error) { break } } - return iNdEx, nil case 1: iNdEx += 8 - return iNdEx, nil case 2: var length int for shift := uint(0); ; shift += 7 { @@ -17964,55 +18234,30 @@ func skipGenerated(dAtA []byte) (n int, err error) { return 0, ErrInvalidLengthGenerated } iNdEx += length - if iNdEx < 0 { - return 0, ErrInvalidLengthGenerated - } - return iNdEx, nil case 3: - for { - var innerWire uint64 - var start int = iNdEx - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return 0, ErrIntOverflowGenerated - } - if iNdEx >= l { - return 0, io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - innerWire |= (uint64(b) & 0x7F) << shift - if b < 0x80 { - break - } - } - innerWireType := int(innerWire & 0x7) - if innerWireType == 4 { - break - } - next, err := skipGenerated(dAtA[start:]) - if err != nil { - return 0, err - } - iNdEx = start + next - if iNdEx < 0 { - return 0, ErrInvalidLengthGenerated - } - } - return iNdEx, nil + depth++ case 4: - return iNdEx, nil + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupGenerated + } + depth-- case 5: iNdEx += 4 - return iNdEx, nil default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } + if iNdEx < 0 { + return 0, ErrInvalidLengthGenerated + } + if depth == 0 { + return iNdEx, nil + } } - panic("unreachable") + return 0, io.ErrUnexpectedEOF } var ( - ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") + ErrInvalidLengthGenerated = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowGenerated = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupGenerated = fmt.Errorf("proto: unexpected end of group") ) diff --git a/pkg/apis/workflow/v1alpha1/generated.proto b/pkg/apis/workflow/v1alpha1/generated.proto index 5c96ef7bad4a..df4bbac6e69c 100644 --- a/pkg/apis/workflow/v1alpha1/generated.proto +++ b/pkg/apis/workflow/v1alpha1/generated.proto @@ -566,6 +566,15 @@ message SuspendTemplate { optional string duration = 1; } +// TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed +message TTLStrategy { + optional int32 secondsAfterCompleted = 1; + + optional int32 secondsAfterSuccess = 2; + + optional int32 secondsAfterFailed = 3; +} + // TarStrategy will tar and gzip the file or directory when saving message TarStrategy { } @@ -849,8 +858,16 @@ message WorkflowSpec { // deleted after ttlSecondsAfterFinished expires. If this field is unset, // ttlSecondsAfterFinished will not expire. If this field is set to zero, // ttlSecondsAfterFinished expires immediately after the Workflow finishes. + // DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead. optional int32 ttlSecondsAfterFinished = 18; + // TTLStrategy limits the lifetime of a Workflow that has finished execution depending on if it + // Succeeded or Failed. If this struct is set, once the Workflow finishes, it will be + // deleted after the time to live expires. If this field is unset, + // the controller config map will hold the default values + // Update + optional TTLStrategy ttlStrategy = 30; + // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to // terminate a Running workflow diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index ef0cd880f2dd..eae346c45d96 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -48,6 +48,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ScriptTemplate": schema_pkg_apis_workflow_v1alpha1_ScriptTemplate(ref), "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Sequence": schema_pkg_apis_workflow_v1alpha1_Sequence(ref), "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.SuspendTemplate": schema_pkg_apis_workflow_v1alpha1_SuspendTemplate(ref), + "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.TTLStrategy": schema_pkg_apis_workflow_v1alpha1_TTLStrategy(ref), "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.TarStrategy": schema_pkg_apis_workflow_v1alpha1_TarStrategy(ref), "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Template": schema_pkg_apis_workflow_v1alpha1_Template(ref), "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.TemplateRef": schema_pkg_apis_workflow_v1alpha1_TemplateRef(ref), @@ -1981,6 +1982,37 @@ func schema_pkg_apis_workflow_v1alpha1_SuspendTemplate(ref common.ReferenceCallb } } +func schema_pkg_apis_workflow_v1alpha1_TTLStrategy(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TTLStrategy is the strategy for the time to live depending on if the workflow succeded or failed", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "secondsAfterCompleted": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + "secondsAfterSuccess": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + "secondsAfterFailed": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_workflow_v1alpha1_TarStrategy(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -2913,11 +2945,17 @@ func schema_pkg_apis_workflow_v1alpha1_WorkflowSpec(ref common.ReferenceCallback }, "ttlSecondsAfterFinished": { SchemaProps: spec.SchemaProps{ - Description: "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes.", + Description: "TTLSecondsAfterFinished limits the lifetime of a Workflow that has finished execution (Succeeded, Failed, Error). If this field is set, once the Workflow finishes, it will be deleted after ttlSecondsAfterFinished expires. If this field is unset, ttlSecondsAfterFinished will not expire. If this field is set to zero, ttlSecondsAfterFinished expires immediately after the Workflow finishes. DEPRECATED: Use TTLStrategy.SecondsAfterCompleted instead.", Type: []string{"integer"}, Format: "int32", }, }, + "ttlStrategy": { + SchemaProps: spec.SchemaProps{ + Description: "TTLStrategy limits the lifetime of a Workflow that has finished execution depending on if it Succeeded or Failed. If this struct is set, once the Workflow finishes, it will be deleted after the time to live expires. If this field is unset, the controller config map will hold the default values Update", + Ref: ref("github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.TTLStrategy"), + }, + }, "activeDeadlineSeconds": { SchemaProps: spec.SchemaProps{ Description: "Optional duration in seconds relative to the workflow start time which the workflow is allowed to run before the controller terminates the workflow. A value of zero is used to terminate a Running workflow", @@ -2995,7 +3033,7 @@ func schema_pkg_apis_workflow_v1alpha1_WorkflowSpec(ref common.ReferenceCallback }, }, Dependencies: []string{ - "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Arguments", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ArtifactRepositoryRef", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ExecutorConfig", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.PodGC", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Template", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.HostAlias", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PersistentVolumeClaim", "k8s.io/api/core/v1.PodDNSConfig", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume"}, + "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Arguments", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ArtifactRepositoryRef", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.ExecutorConfig", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.PodGC", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.TTLStrategy", "github.com/argoproj/argo/pkg/apis/workflow/v1alpha1.Template", "k8s.io/api/core/v1.Affinity", "k8s.io/api/core/v1.HostAlias", "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PersistentVolumeClaim", "k8s.io/api/core/v1.PodDNSConfig", "k8s.io/api/core/v1.PodSecurityContext", "k8s.io/api/core/v1.Toleration", "k8s.io/api/core/v1.Volume"}, } } diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 4db23257c4cd..99b413d335c6 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -215,7 +215,7 @@ type WorkflowSpec struct { // deleted after the time to live expires. If this field is unset, // the controller config map will hold the default values // Update - TTLStrategy *TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,28,opt,name=ttlStrategy"` + TTLStrategy *TTLStrategy `json:"ttlStrategy,omitempty" protobuf:"bytes,30,opt,name=ttlStrategy"` // Optional duration in seconds relative to the workflow start time which the workflow is // allowed to run before the controller terminates the workflow. A value of zero is used to